2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
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; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 #include <ao_cc1120.h>
22 #include <ao_packet.h>
24 #define AO_RADIO_MAX_RECV sizeof(struct ao_packet)
25 #define AO_RADIO_MAX_SEND sizeof(struct ao_packet)
27 static uint8_t ao_radio_mutex;
29 static uint8_t ao_radio_wake; /* radio ready. Also used as sleep address */
30 static uint8_t ao_radio_abort; /* radio operation should abort */
31 static uint8_t ao_radio_mcu_wake; /* MARC status change */
32 static uint8_t ao_radio_marc_status; /* Last read MARC status value */
33 static uint8_t ao_radio_tx_finished; /* MARC status indicates TX finished */
35 int8_t ao_radio_rssi; /* Last received RSSI value */
37 #define CC1120_DEBUG AO_FEC_DEBUG
38 #define CC1120_TRACE 0
40 extern const uint32_t ao_radio_cal;
44 #define ao_radio_try_select(task_id) ao_spi_try_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz, task_id)
45 #define ao_radio_select() ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz)
46 #define ao_radio_deselect() ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
47 #define ao_radio_spi_send_sync(d,l) ao_spi_send_sync((d), (l), AO_CC1120_SPI_BUS)
48 #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
49 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
50 #define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
51 #define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
54 ao_radio_reg_read(uint16_t addr)
60 printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
62 if (CC1120_IS_EXTENDED(addr)) {
63 data[0] = ((1 << CC1120_READ) |
69 data[0] = ((1 << CC1120_READ) |
75 ao_radio_spi_send(data, d);
76 ao_radio_spi_recv(data, 1);
79 printf (" %02x\n", data[0]);
85 ao_radio_reg_write(uint16_t addr, uint8_t value)
91 printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
93 if (CC1120_IS_EXTENDED(addr)) {
94 data[0] = ((0 << CC1120_READ) |
100 data[0] = ((0 << CC1120_READ) |
101 (0 << CC1120_BURST) |
107 ao_radio_spi_send(data, d+1);
112 _ao_radio_burst_read_start (uint16_t addr)
117 if (CC1120_IS_EXTENDED(addr)) {
118 data[0] = ((1 << CC1120_READ) |
119 (1 << CC1120_BURST) |
124 data[0] = ((1 << CC1120_READ) |
125 (1 << CC1120_BURST) |
130 ao_radio_spi_send_sync(data, d);
134 ao_radio_burst_read_stop (void)
141 ao_radio_strobe(uint8_t addr)
146 printf("\t\tao_radio_strobe (%02x): ", addr); flush();
149 ao_radio_duplex(&addr, &in, 1);
152 printf("%02x\n", in); flush();
159 ao_radio_fifo_read(uint8_t *data, uint8_t len)
161 uint8_t addr = ((1 << CC1120_READ) |
162 (1 << CC1120_BURST) |
167 ao_radio_duplex(&addr, &status, 1);
168 ao_radio_spi_recv(data, len);
175 ao_radio_fifo_write_start(void)
177 uint8_t addr = ((0 << CC1120_READ) |
178 (1 << CC1120_BURST) |
183 ao_radio_duplex(&addr, &status, 1);
187 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
193 ao_radio_fifo_write(uint8_t *data, uint8_t len)
195 uint8_t status = ao_radio_fifo_write_start();
196 ao_radio_spi_send(data, len);
197 return ao_radio_fifo_write_stop(status);
201 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
203 uint8_t status = ao_radio_fifo_write_start();
204 ao_radio_spi_send_fixed(data, len);
205 return ao_radio_fifo_write_stop(status);
209 ao_radio_tx_fifo_space(void)
211 return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
216 ao_radio_status(void)
218 return ao_radio_strobe (CC1120_SNOP);
223 ao_radio_recv_abort(void)
226 ao_wakeup(&ao_radio_wake);
229 #define ao_radio_rdf_value 0x55
232 ao_radio_get_marc_status(void)
234 return ao_radio_reg_read(CC1120_MARC_STATUS1);
238 ao_radio_mcu_wakeup_isr(void)
240 ao_radio_mcu_wake = 1;
241 ao_wakeup(&ao_radio_wake);
246 ao_radio_check_marc_status(void)
248 ao_radio_mcu_wake = 0;
249 ao_radio_marc_status = ao_radio_get_marc_status();
251 /* Anyt other than 'tx/rx finished' means an error occurred */
252 if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED))
254 if (ao_radio_marc_status & (CC1120_MARC_STATUS1_TX_FINISHED))
255 ao_radio_tx_finished = 1;
261 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
263 ao_wakeup(&ao_radio_wake);
267 ao_radio_start_tx(void)
269 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
270 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
271 ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
272 ao_radio_tx_finished = 0;
273 ao_radio_strobe(CC1120_STX);
280 uint8_t state = (ao_radio_strobe(CC1120_SIDLE) >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK;
281 if (state == CC1120_STATUS_STATE_IDLE)
283 if (state == CC1120_STATUS_STATE_TX_FIFO_ERROR)
284 ao_radio_strobe(CC1120_SFTX);
285 if (state == CC1120_STATUS_STATE_RX_FIFO_ERROR)
286 ao_radio_strobe(CC1120_SFRX);
288 /* Flush any pending TX bytes */
289 ao_radio_strobe(CC1120_SFTX);
295 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
297 * Deviation for 38400 baud should be 20.5kHz:
299 * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
301 * Deviation for 9600 baud should be 5.125kHz:
303 * 32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 3) = 5127Hz
305 * Deviation for 2400 baud should be 1.28125kHz, but cc1111 and
306 * cc115l can't do that, so we'll use 1.5kHz instead:
308 * 32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 1) = 1499Hz
311 #define PACKET_DEV_M_384 80
312 #define PACKET_DEV_E_384 5
314 #define PACKET_DEV_M_96 80
315 #define PACKET_DEV_E_96 3
317 #define PACKET_DEV_M_24 137
318 #define PACKET_DEV_E_24 1
321 * For our packet data
323 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
324 * Rdata = -------------------------------------- * fosc
327 * Given the bit period of the baseband, T, the bandwidth of the
328 * baseband signal is B = 1/(2T). The overall bandwidth of the
329 * modulated signal is then Channel bandwidth = 2Δf + 2B.
331 * 38400 -- 2 * 20500 + 38400 = 79.4 kHz
332 * 9600 -- 2 * 5.125 + 9600 = 19.9 kHz
333 * 2400 -- 2 * 1.5 + 2400 = 5.4 khz
335 * Symbol rate 38400 Baud:
337 * DATARATE_M = 239914
339 * CHANBW = 79.4 (round to 100)
341 * Symbol rate 9600 Baud:
343 * DATARATE_M = 239914
345 * CHANBW = 19.9 (round to 20)
347 * Symbol rate 2400 Baud:
349 * DATARATE_M = 239914
351 * CHANBW = 5.0 (round to 8.0)
354 #define PACKET_DRATE_M 239914
356 #define PACKET_DRATE_E_384 9
359 #define PACKET_CHAN_BW_384 ((0 << CC1120_CHAN_BW_CHFILT_BYPASS) | \
360 (CC1120_CHAN_BW_ADC_CIC_DECFACT_20 << CC1120_CHAN_BW_ADC_CIC_DECFACT) | \
361 (2 << CC1120_CHAN_BW_BB_CIC_DECFACT))
363 #define PACKET_DRATE_E_96 7
365 #define PACKET_CHAN_BW_96 ((0 << CC1120_CHAN_BW_CHFILT_BYPASS) | \
366 (CC1120_CHAN_BW_ADC_CIC_DECFACT_20 << CC1120_CHAN_BW_ADC_CIC_DECFACT) | \
367 (10 << CC1120_CHAN_BW_BB_CIC_DECFACT))
369 #define PACKET_DRATE_E_24 5
371 #define PACKET_CHAN_BW_24 ((0 << CC1120_CHAN_BW_CHFILT_BYPASS) | \
372 (CC1120_CHAN_BW_ADC_CIC_DECFACT_20 << CC1120_CHAN_BW_ADC_CIC_DECFACT) | \
373 (25 << CC1120_CHAN_BW_BB_CIC_DECFACT))
375 static const uint16_t packet_setup[] = {
376 CC1120_DRATE1, ((PACKET_DRATE_M >> 8) & 0xff),
377 CC1120_DRATE0, ((PACKET_DRATE_M >> 0) & 0xff),
378 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
379 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
380 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
381 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
382 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
383 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
384 CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
385 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
386 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
387 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
388 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
389 CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
390 (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
391 AO_CC1120_MARC_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
394 static const uint16_t packet_setup_384[] = {
395 CC1120_DEVIATION_M, PACKET_DEV_M_384,
396 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
397 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
398 (PACKET_DEV_E_384 << CC1120_MODCFG_DEV_E_DEV_E)),
399 CC1120_DRATE2, ((PACKET_DRATE_E_384 << CC1120_DRATE2_DATARATE_E) |
400 (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
401 CC1120_CHAN_BW, PACKET_CHAN_BW_384,
402 CC1120_PA_CFG0, 0x7b,
405 static const uint16_t packet_setup_96[] = {
406 CC1120_DEVIATION_M, PACKET_DEV_M_96,
407 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
408 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
409 (PACKET_DEV_E_96 << CC1120_MODCFG_DEV_E_DEV_E)),
410 CC1120_DRATE2, ((PACKET_DRATE_E_96 << CC1120_DRATE2_DATARATE_E) |
411 (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
412 CC1120_CHAN_BW, PACKET_CHAN_BW_96,
413 CC1120_PA_CFG0, 0x7d,
416 static const uint16_t packet_setup_24[] = {
417 CC1120_DEVIATION_M, PACKET_DEV_M_24,
418 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
419 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
420 (PACKET_DEV_E_24 << CC1120_MODCFG_DEV_E_DEV_E)),
421 CC1120_DRATE2, ((PACKET_DRATE_E_24 << CC1120_DRATE2_DATARATE_E) |
422 (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
423 CC1120_CHAN_BW, PACKET_CHAN_BW_24,
424 CC1120_PA_CFG0, 0x7e,
427 static const uint16_t packet_tx_setup[] = {
428 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
429 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
430 AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
433 static const uint16_t packet_rx_setup[] = {
434 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
435 (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
436 AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
440 * RDF deviation is 5kHz
442 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
444 * 32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
449 #define RDF_PACKET_LEN 50
452 * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
454 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
455 * Rdata = -------------------------------------- * fosc
461 * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
463 #define RDF_DRATE_E 5
464 #define RDF_DRATE_M 25166
465 #define RDF_PACKET_LEN 50
467 static const uint16_t rdf_setup[] = {
468 CC1120_DEVIATION_M, RDF_DEV_M,
469 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
470 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
471 (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
472 CC1120_DRATE2, ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
473 (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
474 CC1120_DRATE1, ((RDF_DRATE_M >> 8) & 0xff),
475 CC1120_DRATE0, ((RDF_DRATE_M >> 0) & 0xff),
476 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
477 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
478 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
479 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
480 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
481 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
482 CC1120_PKT_CFG0, ((0 << CC1120_PKT_CFG0_RESERVED7) |
483 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
484 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
485 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
486 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
487 CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
488 (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
489 CC1120_PA_CFG0, 0x7e,
493 * APRS deviation is 3kHz
495 * fdev = fosc >> 24 * (256 + dev_m) << dev_e
497 * 32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 2) = 2998Hz
501 #define APRS_DEV_M 137
504 * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
506 * (2**20 + DATARATE_M) * 2 ** DATARATE_E
507 * Rdata = -------------------------------------- * fosc
510 * DATARATE_M = 239914
513 * Rdata = 9599.998593330383301
516 #define APRS_DRATE_E 7
517 #define APRS_DRATE_M 239914
519 static const uint16_t aprs_setup[] = {
520 CC1120_DEVIATION_M, APRS_DEV_M,
521 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
522 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
523 (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
524 CC1120_DRATE2, ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
525 (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
526 CC1120_DRATE1, ((APRS_DRATE_M >> 8) & 0xff),
527 CC1120_DRATE0, ((APRS_DRATE_M >> 0) & 0xff),
528 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
529 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
530 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
531 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
532 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
533 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
534 CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
535 (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
536 CC1120_PA_CFG0, 0x7d,
540 * For Test mode, we want an unmodulated carrier. To do that, we
541 * set the deviation to zero and enable a preamble so that the radio
542 * turns on before we send any data
545 static const uint16_t test_setup[] = {
546 CC1120_DEVIATION_M, 0,
547 CC1120_MODCFG_DEV_E, ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
548 (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
549 (0 << CC1120_MODCFG_DEV_E_DEV_E)),
550 CC1120_DRATE2, ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
551 (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
552 CC1120_DRATE1, ((APRS_DRATE_M >> 8) & 0xff),
553 CC1120_DRATE0, ((APRS_DRATE_M >> 0) & 0xff),
554 CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
555 (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
556 CC1120_PKT_CFG1, ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
557 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
558 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
559 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
560 CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
561 (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
564 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) | \
565 (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
566 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | \
567 (0 << CC1120_PKT_CFG0_UART_MODE_EN) | \
568 (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
570 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) | \
571 (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
572 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) | \
573 (0 << CC1120_PKT_CFG0_UART_MODE_EN) | \
574 (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
576 static uint16_t ao_radio_mode;
578 #define AO_RADIO_MODE_BITS_PACKET 1
579 #define AO_RADIO_MODE_BITS_PACKET_TX 2
580 #define AO_RADIO_MODE_BITS_TX_BUF 4
581 #define AO_RADIO_MODE_BITS_TX_FINISH 8
582 #define AO_RADIO_MODE_BITS_PACKET_RX 16
583 #define AO_RADIO_MODE_BITS_RDF 32
584 #define AO_RADIO_MODE_BITS_APRS 64
585 #define AO_RADIO_MODE_BITS_TEST 128
586 #define AO_RADIO_MODE_BITS_INFINITE 256
587 #define AO_RADIO_MODE_BITS_FIXED 512
589 #define AO_RADIO_MODE_NONE 0
590 #define AO_RADIO_MODE_PACKET_TX_BUF (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
591 #define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
592 #define AO_RADIO_MODE_PACKET_RX (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
593 #define AO_RADIO_MODE_RDF (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
594 #define AO_RADIO_MODE_APRS_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
595 #define AO_RADIO_MODE_APRS_LAST_BUF (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
596 #define AO_RADIO_MODE_APRS_FINISH (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
597 #define AO_RADIO_MODE_TEST (AO_RADIO_MODE_BITS_TEST | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
600 _ao_radio_set_regs(const uint16_t *regs, int nreg)
604 for (i = 0; i < nreg; i++) {
605 ao_radio_reg_write(regs[0], regs[1]);
610 #define ao_radio_set_regs(setup) _ao_radio_set_regs(setup, (sizeof (setup) / sizeof(setup[0])) >> 1)
613 ao_radio_set_mode(uint16_t new_mode)
617 if (new_mode == ao_radio_mode)
620 changes = new_mode & (~ao_radio_mode);
622 if (changes & AO_RADIO_MODE_BITS_PACKET) {
623 ao_radio_set_regs(packet_setup);
625 switch (ao_config.radio_rate) {
627 case AO_RADIO_RATE_38400:
628 ao_radio_set_regs(packet_setup_384);
630 case AO_RADIO_RATE_9600:
631 ao_radio_set_regs(packet_setup_96);
633 case AO_RADIO_RATE_2400:
634 ao_radio_set_regs(packet_setup_24);
639 if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
640 ao_radio_set_regs(packet_tx_setup);
642 if (changes & AO_RADIO_MODE_BITS_TX_BUF)
643 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
645 if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
646 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
648 if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
649 ao_radio_set_regs(packet_rx_setup);
651 if (changes & AO_RADIO_MODE_BITS_RDF)
652 ao_radio_set_regs(rdf_setup);
654 if (changes & AO_RADIO_MODE_BITS_APRS)
655 ao_radio_set_regs(aprs_setup);
657 if (changes & AO_RADIO_MODE_BITS_TEST)
658 ao_radio_set_regs(test_setup);
660 if (changes & AO_RADIO_MODE_BITS_INFINITE)
661 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
663 if (changes & AO_RADIO_MODE_BITS_FIXED)
664 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
666 ao_radio_mode = new_mode;
669 static const uint16_t radio_setup[] = {
670 #include "ao_cc1120_CC1120.h"
673 static uint8_t ao_radio_configured = 0;
678 ao_radio_strobe(CC1120_SRES);
680 ao_radio_set_regs(radio_setup);
686 ao_radio_configured = 1;
690 ao_radio_set_len(uint8_t len)
692 static uint8_t last_len;
694 if (len != last_len) {
695 ao_radio_reg_write(CC1120_PKT_LEN, len);
701 ao_radio_get(uint8_t len)
703 static uint32_t last_radio_setting;
704 static uint8_t last_radio_rate;
706 ao_mutex_get(&ao_radio_mutex);
708 if (!ao_radio_configured)
710 if (ao_config.radio_setting != last_radio_setting) {
711 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
712 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
713 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
714 last_radio_setting = ao_config.radio_setting;
716 if (ao_config.radio_rate != last_radio_rate) {
717 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET;
718 last_radio_rate = ao_config.radio_rate;
720 ao_radio_set_len(len);
723 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
726 ao_rdf_start(uint8_t len)
731 ao_radio_set_mode(AO_RADIO_MODE_RDF);
741 ao_arch_block_interrupts();
742 while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
743 ao_sleep(&ao_radio_wake);
744 ao_arch_release_interrupts();
745 if (ao_radio_mcu_wake)
746 ao_radio_check_marc_status();
755 ao_rdf_start(AO_RADIO_RDF_LEN);
757 ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
763 ao_radio_continuity(uint8_t c)
768 ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
770 status = ao_radio_fifo_write_start();
771 for (i = 0; i < 3; i++) {
772 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
774 ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
776 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
778 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
779 status = ao_radio_fifo_write_stop(status);
785 ao_radio_rdf_abort(void)
788 ao_wakeup(&ao_radio_wake);
792 ao_radio_test_cmd(void)
795 static uint8_t radio_on;
797 if (ao_cmd_lex_c != '\n') {
799 mode = (uint8_t) ao_cmd_lex_u32;
802 if ((mode & 2) && !radio_on) {
804 ao_monitor_disable();
807 ao_packet_slave_stop();
810 ao_radio_set_mode(AO_RADIO_MODE_TEST);
811 ao_radio_strobe(CC1120_STX);
814 for (t = 0; t < 10; t++) {
815 printf ("status: %02x\n", ao_radio_status());
816 ao_delay(AO_MS_TO_TICKS(100));
823 printf ("Hit a character to stop..."); flush();
827 if ((mode & 1) && radio_on) {
838 ao_radio_wait_isr(uint16_t timeout)
840 ao_arch_block_interrupts();
841 while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
842 if (ao_sleep_for(&ao_radio_wake, timeout))
844 ao_arch_release_interrupts();
845 if (ao_radio_mcu_wake)
846 ao_radio_check_marc_status();
850 ao_radio_wait_tx(uint8_t wait_fifo)
852 uint8_t fifo_space = 0;
855 ao_radio_wait_isr(0);
858 fifo_space = ao_radio_tx_fifo_space();
859 } while (!fifo_space && !ao_radio_abort);
863 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
866 ao_radio_send(const void *d, uint8_t size)
868 uint8_t *e = tx_data;
874 encode_len = ao_fec_encode(d, size, tx_data);
876 ao_radio_get(encode_len);
880 /* Flush any pending TX bytes */
881 ao_radio_strobe(CC1120_SFTX);
884 fifo_space = CC1120_FIFO_SIZE;
886 this_len = encode_len;
889 if (this_len > fifo_space) {
890 this_len = fifo_space;
891 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
893 ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
896 ao_radio_fifo_write(e, this_len);
898 encode_len -= this_len;
904 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
907 fifo_space = ao_radio_wait_tx(encode_len != 0);
908 if (ao_radio_abort) {
913 while (started && !ao_radio_abort && !ao_radio_tx_finished)
914 ao_radio_wait_isr(0);
918 #define AO_RADIO_LOTS 64
921 ao_radio_send_aprs(ao_radio_fill_func fill)
923 uint8_t buf[AO_RADIO_LOTS], *b;
931 fifo_space = CC1120_FIFO_SIZE;
933 cnt = (*fill)(buf, sizeof(buf));
940 /* At the last buffer, set the total length */
942 ao_radio_set_len(total & 0xff);
946 uint8_t this_len = cnt;
948 /* Wait for some space in the fifo */
949 while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
951 ao_radio_wait_isr(0);
955 if (this_len > fifo_space)
956 this_len = fifo_space;
962 ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
964 ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
966 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
968 ao_radio_fifo_write(b, this_len);
975 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
977 if (ao_radio_abort) {
981 /* Wait for the transmitter to go idle */
983 ao_radio_wait_isr(0);
988 static uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
989 static uint16_t rx_data_count;
990 static uint16_t rx_data_consumed;
991 static uint16_t rx_data_cur;
992 static uint8_t rx_ignore;
993 static uint8_t rx_waiting;
994 static uint8_t rx_starting;
995 static uint8_t rx_task_id;
996 static uint32_t rx_fast_start;
997 static uint32_t rx_slow_start;
998 static uint32_t rx_missed;
1001 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
1003 uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
1005 #include <ao_profile.h>
1009 ao_radio_rx_isr(void)
1014 if (ao_radio_try_select(rx_task_id)) {
1017 _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
1030 ao_wakeup(&ao_radio_wake);
1032 d = AO_CC1120_SPI.dr;
1033 AO_CC1120_SPI.dr = 0;
1034 if (rx_ignore == 0) {
1035 if (rx_data_cur < rx_data_count)
1036 rx_data[rx_data_cur++] = d;
1037 if (rx_data_cur >= rx_data_count) {
1038 ao_spi_clr_cs(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN));
1039 ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
1041 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
1043 if (!rx_packet_tick)
1044 rx_packet_tick = ao_profile_tick();
1045 if (rx_data_cur < rx_data_count)
1049 ao_wakeup(&ao_radio_wake);
1057 ao_radio_rx_wait(void)
1059 ao_arch_block_interrupts();
1061 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
1065 if (ao_sleep_for(&ao_radio_wake, AO_MS_TO_TICKS(100)))
1069 ao_arch_release_interrupts();
1070 if (ao_radio_abort || ao_radio_mcu_wake)
1072 rx_data_consumed += AO_FEC_DECODE_BLOCK;
1074 return rx_data_cur - rx_data_consumed;
1076 return AO_FEC_DECODE_BLOCK;
1080 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
1083 uint8_t radio_rssi = 0;
1087 size -= 2; /* status bytes */
1088 if (size > AO_RADIO_MAX_RECV) {
1089 ao_delay(AO_SEC_TO_TICKS(1));
1093 rx_start_tick = ao_profile_tick();
1096 len = size + 2; /* CRC bytes */
1097 len += 1 + ~(len & 1); /* 1 or two pad bytes */
1098 len *= 2; /* 1/2 rate convolution */
1099 rx_data_count = len * 8; /* bytes to bits */
1101 rx_data_consumed = 0;
1104 /* Must be set before changing the frequency; any abort
1105 * after the frequency is set needs to terminate the read
1106 * so that the registers can be reprogrammed
1113 ao_radio_mcu_wake = 0;
1115 ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
1117 /* configure interrupt pin */
1118 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
1119 ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1120 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
1123 rx_task_id = ao_cur_task->task_id;
1125 ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
1126 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
1128 ao_radio_strobe(CC1120_SRX);
1130 ao_arch_block_interrupts();
1131 while (rx_starting && !ao_radio_abort) {
1132 if (ao_sleep_for(&ao_radio_wake, timeout))
1135 uint8_t rx_task_id_save = rx_task_id;
1138 ao_arch_release_interrupts();
1140 if (ao_radio_abort) {
1141 if (rx_task_id_save == 0)
1142 ao_radio_burst_read_stop();
1147 if (rx_task_id_save) {
1150 _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
1152 uint8_t ignore = AO_CC1120_SPI.dr;
1154 AO_CC1120_SPI.dr = 0;
1159 ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
1161 ao_radio_burst_read_stop();
1163 if (ao_radio_mcu_wake)
1164 ao_radio_check_marc_status();
1169 /* Convert from 'real' rssi to cc1111-style values */
1171 rssi0 = ao_radio_reg_read(CC1120_RSSI0);
1173 int8_t rssi = ao_radio_reg_read(CC1120_RSSI1);
1174 ao_radio_rssi = rssi;
1176 /* Bound it to the representable range */
1179 radio_rssi = AO_RADIO_FROM_RSSI (rssi);
1186 /* Store the received RSSI value; the crc-OK byte is already done */
1188 ((uint8_t *) d)[size] = radio_rssi;
1191 rx_last_done_tick = rx_done_tick;
1192 rx_done_tick = ao_profile_tick();
1194 ao_rx_start_tick = rx_start_tick;
1195 ao_rx_packet_tick = rx_packet_tick;
1196 ao_rx_done_tick = rx_done_tick;
1197 ao_rx_last_done_tick = rx_last_done_tick;
1205 static char *cc1120_state_name[] = {
1206 [CC1120_STATUS_STATE_IDLE] = "IDLE",
1207 [CC1120_STATUS_STATE_RX] = "RX",
1208 [CC1120_STATUS_STATE_TX] = "TX",
1209 [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
1210 [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
1211 [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
1212 [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
1213 [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
1216 struct ao_cc1120_reg {
1221 static const struct ao_cc1120_reg ao_cc1120_reg[] = {
1222 { .addr = CC1120_IOCFG3, .name = "IOCFG3" },
1223 { .addr = CC1120_IOCFG2, .name = "IOCFG2" },
1224 { .addr = CC1120_IOCFG1, .name = "IOCFG1" },
1225 { .addr = CC1120_IOCFG0, .name = "IOCFG0" },
1226 { .addr = CC1120_SYNC3, .name = "SYNC3" },
1227 { .addr = CC1120_SYNC2, .name = "SYNC2" },
1228 { .addr = CC1120_SYNC1, .name = "SYNC1" },
1229 { .addr = CC1120_SYNC0, .name = "SYNC0" },
1230 { .addr = CC1120_SYNC_CFG1, .name = "SYNC_CFG1" },
1231 { .addr = CC1120_SYNC_CFG0, .name = "SYNC_CFG0" },
1232 { .addr = CC1120_DEVIATION_M, .name = "DEVIATION_M" },
1233 { .addr = CC1120_MODCFG_DEV_E, .name = "MODCFG_DEV_E" },
1234 { .addr = CC1120_DCFILT_CFG, .name = "DCFILT_CFG" },
1235 { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
1236 { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
1237 { .addr = CC1120_FREQ_IF_CFG, .name = "FREQ_IF_CFG" },
1238 { .addr = CC1120_IQIC, .name = "IQIC" },
1239 { .addr = CC1120_CHAN_BW, .name = "CHAN_BW" },
1240 { .addr = CC1120_MDMCFG1, .name = "MDMCFG1" },
1241 { .addr = CC1120_MDMCFG0, .name = "MDMCFG0" },
1242 { .addr = CC1120_DRATE2, .name = "DRATE2" },
1243 { .addr = CC1120_DRATE1, .name = "DRATE1" },
1244 { .addr = CC1120_DRATE0, .name = "DRATE0" },
1245 { .addr = CC1120_AGC_REF, .name = "AGC_REF" },
1246 { .addr = CC1120_AGC_CS_THR, .name = "AGC_CS_THR" },
1247 { .addr = CC1120_AGC_GAIN_ADJUST, .name = "AGC_GAIN_ADJUST" },
1248 { .addr = CC1120_AGC_CFG3, .name = "AGC_CFG3" },
1249 { .addr = CC1120_AGC_CFG2, .name = "AGC_CFG2" },
1250 { .addr = CC1120_AGC_CFG1, .name = "AGC_CFG1" },
1251 { .addr = CC1120_AGC_CFG0, .name = "AGC_CFG0" },
1252 { .addr = CC1120_FIFO_CFG, .name = "FIFO_CFG" },
1253 { .addr = CC1120_DEV_ADDR, .name = "DEV_ADDR" },
1254 { .addr = CC1120_SETTLING_CFG, .name = "SETTLING_CFG" },
1255 { .addr = CC1120_FS_CFG, .name = "FS_CFG" },
1256 { .addr = CC1120_WOR_CFG1, .name = "WOR_CFG1" },
1257 { .addr = CC1120_WOR_CFG0, .name = "WOR_CFG0" },
1258 { .addr = CC1120_WOR_EVENT0_MSB, .name = "WOR_EVENT0_MSB" },
1259 { .addr = CC1120_WOR_EVENT0_LSB, .name = "WOR_EVENT0_LSB" },
1260 { .addr = CC1120_PKT_CFG2, .name = "PKT_CFG2" },
1261 { .addr = CC1120_PKT_CFG1, .name = "PKT_CFG1" },
1262 { .addr = CC1120_PKT_CFG0, .name = "PKT_CFG0" },
1263 { .addr = CC1120_RFEND_CFG1, .name = "RFEND_CFG1" },
1264 { .addr = CC1120_RFEND_CFG0, .name = "RFEND_CFG0" },
1265 { .addr = CC1120_PA_CFG2, .name = "PA_CFG2" },
1266 { .addr = CC1120_PA_CFG1, .name = "PA_CFG1" },
1267 { .addr = CC1120_PA_CFG0, .name = "PA_CFG0" },
1268 { .addr = CC1120_PKT_LEN, .name = "PKT_LEN" },
1269 { .addr = CC1120_IF_MIX_CFG, .name = "IF_MIX_CFG" },
1270 { .addr = CC1120_FREQOFF_CFG, .name = "FREQOFF_CFG" },
1271 { .addr = CC1120_TOC_CFG, .name = "TOC_CFG" },
1272 { .addr = CC1120_MARC_SPARE, .name = "MARC_SPARE" },
1273 { .addr = CC1120_ECG_CFG, .name = "ECG_CFG" },
1274 { .addr = CC1120_SOFT_TX_DATA_CFG, .name = "SOFT_TX_DATA_CFG" },
1275 { .addr = CC1120_EXT_CTRL, .name = "EXT_CTRL" },
1276 { .addr = CC1120_RCCAL_FINE, .name = "RCCAL_FINE" },
1277 { .addr = CC1120_RCCAL_COARSE, .name = "RCCAL_COARSE" },
1278 { .addr = CC1120_RCCAL_OFFSET, .name = "RCCAL_OFFSET" },
1279 { .addr = CC1120_FREQOFF1, .name = "FREQOFF1" },
1280 { .addr = CC1120_FREQOFF0, .name = "FREQOFF0" },
1281 { .addr = CC1120_FREQ2, .name = "FREQ2" },
1282 { .addr = CC1120_FREQ1, .name = "FREQ1" },
1283 { .addr = CC1120_FREQ0, .name = "FREQ0" },
1284 { .addr = CC1120_IF_ADC2, .name = "IF_ADC2" },
1285 { .addr = CC1120_IF_ADC1, .name = "IF_ADC1" },
1286 { .addr = CC1120_IF_ADC0, .name = "IF_ADC0" },
1287 { .addr = CC1120_FS_DIG1, .name = "FS_DIG1" },
1288 { .addr = CC1120_FS_DIG0, .name = "FS_DIG0" },
1289 { .addr = CC1120_FS_CAL3, .name = "FS_CAL3" },
1290 { .addr = CC1120_FS_CAL2, .name = "FS_CAL2" },
1291 { .addr = CC1120_FS_CAL1, .name = "FS_CAL1" },
1292 { .addr = CC1120_FS_CAL0, .name = "FS_CAL0" },
1293 { .addr = CC1120_FS_CHP, .name = "FS_CHP" },
1294 { .addr = CC1120_FS_DIVTWO, .name = "FS_DIVTWO" },
1295 { .addr = CC1120_FS_DSM1, .name = "FS_DSM1" },
1296 { .addr = CC1120_FS_DSM0, .name = "FS_DSM0" },
1297 { .addr = CC1120_FS_DVC1, .name = "FS_DVC1" },
1298 { .addr = CC1120_FS_DVC0, .name = "FS_DVC0" },
1299 { .addr = CC1120_FS_LBI, .name = "FS_LBI" },
1300 { .addr = CC1120_FS_PFD, .name = "FS_PFD" },
1301 { .addr = CC1120_FS_PRE, .name = "FS_PRE" },
1302 { .addr = CC1120_FS_REG_DIV_CML, .name = "FS_REG_DIV_CML" },
1303 { .addr = CC1120_FS_SPARE, .name = "FS_SPARE" },
1304 { .addr = CC1120_FS_VCO4, .name = "FS_VCO4" },
1305 { .addr = CC1120_FS_VCO3, .name = "FS_VCO3" },
1306 { .addr = CC1120_FS_VCO2, .name = "FS_VCO2" },
1307 { .addr = CC1120_FS_VCO1, .name = "FS_VCO1" },
1308 { .addr = CC1120_FS_VCO0, .name = "FS_VCO0" },
1309 { .addr = CC1120_GBIAS6, .name = "GBIAS6" },
1310 { .addr = CC1120_GBIAS5, .name = "GBIAS5" },
1311 { .addr = CC1120_GBIAS4, .name = "GBIAS4" },
1312 { .addr = CC1120_GBIAS3, .name = "GBIAS3" },
1313 { .addr = CC1120_GBIAS2, .name = "GBIAS2" },
1314 { .addr = CC1120_GBIAS1, .name = "GBIAS1" },
1315 { .addr = CC1120_GBIAS0, .name = "GBIAS0" },
1316 { .addr = CC1120_IFAMP, .name = "IFAMP" },
1317 { .addr = CC1120_LNA, .name = "LNA" },
1318 { .addr = CC1120_RXMIX, .name = "RXMIX" },
1319 { .addr = CC1120_XOSC5, .name = "XOSC5" },
1320 { .addr = CC1120_XOSC4, .name = "XOSC4" },
1321 { .addr = CC1120_XOSC3, .name = "XOSC3" },
1322 { .addr = CC1120_XOSC2, .name = "XOSC2" },
1323 { .addr = CC1120_XOSC1, .name = "XOSC1" },
1324 { .addr = CC1120_XOSC0, .name = "XOSC0" },
1325 { .addr = CC1120_ANALOG_SPARE, .name = "ANALOG_SPARE" },
1326 { .addr = CC1120_PA_CFG3, .name = "PA_CFG3" },
1327 { .addr = CC1120_WOR_TIME1, .name = "WOR_TIME1" },
1328 { .addr = CC1120_WOR_TIME0, .name = "WOR_TIME0" },
1329 { .addr = CC1120_WOR_CAPTURE1, .name = "WOR_CAPTURE1" },
1330 { .addr = CC1120_WOR_CAPTURE0, .name = "WOR_CAPTURE0" },
1331 { .addr = CC1120_BIST, .name = "BIST" },
1332 { .addr = CC1120_DCFILTOFFSET_I1, .name = "DCFILTOFFSET_I1" },
1333 { .addr = CC1120_DCFILTOFFSET_I0, .name = "DCFILTOFFSET_I0" },
1334 { .addr = CC1120_DCFILTOFFSET_Q1, .name = "DCFILTOFFSET_Q1" },
1335 { .addr = CC1120_DCFILTOFFSET_Q0, .name = "DCFILTOFFSET_Q0" },
1336 { .addr = CC1120_IQIE_I1, .name = "IQIE_I1" },
1337 { .addr = CC1120_IQIE_I0, .name = "IQIE_I0" },
1338 { .addr = CC1120_IQIE_Q1, .name = "IQIE_Q1" },
1339 { .addr = CC1120_IQIE_Q0, .name = "IQIE_Q0" },
1340 { .addr = CC1120_RSSI1, .name = "RSSI1" },
1341 { .addr = CC1120_RSSI0, .name = "RSSI0" },
1342 { .addr = CC1120_MARCSTATE, .name = "MARCSTATE" },
1343 { .addr = CC1120_LQI_VAL, .name = "LQI_VAL" },
1344 { .addr = CC1120_PQT_SYNC_ERR, .name = "PQT_SYNC_ERR" },
1345 { .addr = CC1120_DEM_STATUS, .name = "DEM_STATUS" },
1346 { .addr = CC1120_FREQOFF_EST1, .name = "FREQOFF_EST1" },
1347 { .addr = CC1120_FREQOFF_EST0, .name = "FREQOFF_EST0" },
1348 { .addr = CC1120_AGC_GAIN3, .name = "AGC_GAIN3" },
1349 { .addr = CC1120_AGC_GAIN2, .name = "AGC_GAIN2" },
1350 { .addr = CC1120_AGC_GAIN1, .name = "AGC_GAIN1" },
1351 { .addr = CC1120_AGC_GAIN0, .name = "AGC_GAIN0" },
1352 { .addr = CC1120_SOFT_RX_DATA_OUT, .name = "SOFT_RX_DATA_OUT" },
1353 { .addr = CC1120_SOFT_TX_DATA_IN, .name = "SOFT_TX_DATA_IN" },
1354 { .addr = CC1120_ASK_SOFT_RX_DATA, .name = "ASK_SOFT_RX_DATA" },
1355 { .addr = CC1120_RNDGEN, .name = "RNDGEN" },
1356 { .addr = CC1120_MAGN2, .name = "MAGN2" },
1357 { .addr = CC1120_MAGN1, .name = "MAGN1" },
1358 { .addr = CC1120_MAGN0, .name = "MAGN0" },
1359 { .addr = CC1120_ANG1, .name = "ANG1" },
1360 { .addr = CC1120_ANG0, .name = "ANG0" },
1361 { .addr = CC1120_CHFILT_I2, .name = "CHFILT_I2" },
1362 { .addr = CC1120_CHFILT_I1, .name = "CHFILT_I1" },
1363 { .addr = CC1120_CHFILT_I0, .name = "CHFILT_I0" },
1364 { .addr = CC1120_CHFILT_Q2, .name = "CHFILT_Q2" },
1365 { .addr = CC1120_CHFILT_Q1, .name = "CHFILT_Q1" },
1366 { .addr = CC1120_CHFILT_Q0, .name = "CHFILT_Q0" },
1367 { .addr = CC1120_GPIO_STATUS, .name = "GPIO_STATUS" },
1368 { .addr = CC1120_FSCAL_CTRL, .name = "FSCAL_CTRL" },
1369 { .addr = CC1120_PHASE_ADJUST, .name = "PHASE_ADJUST" },
1370 { .addr = CC1120_PARTNUMBER, .name = "PARTNUMBER" },
1371 { .addr = CC1120_PARTVERSION, .name = "PARTVERSION" },
1372 { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1373 { .addr = CC1120_RX_STATUS, .name = "RX_STATUS" },
1374 { .addr = CC1120_TX_STATUS, .name = "TX_STATUS" },
1375 { .addr = CC1120_MARC_STATUS1, .name = "MARC_STATUS1" },
1376 { .addr = CC1120_MARC_STATUS0, .name = "MARC_STATUS0" },
1377 { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1378 { .addr = CC1120_FSRF_TEST, .name = "FSRF_TEST" },
1379 { .addr = CC1120_PRE_TEST, .name = "PRE_TEST" },
1380 { .addr = CC1120_PRE_OVR, .name = "PRE_OVR" },
1381 { .addr = CC1120_ADC_TEST, .name = "ADC_TEST" },
1382 { .addr = CC1120_DVC_TEST, .name = "DVC_TEST" },
1383 { .addr = CC1120_ATEST, .name = "ATEST" },
1384 { .addr = CC1120_ATEST_LVDS, .name = "ATEST_LVDS" },
1385 { .addr = CC1120_ATEST_MODE, .name = "ATEST_MODE" },
1386 { .addr = CC1120_XOSC_TEST1, .name = "XOSC_TEST1" },
1387 { .addr = CC1120_XOSC_TEST0, .name = "XOSC_TEST0" },
1388 { .addr = CC1120_RXFIRST, .name = "RXFIRST" },
1389 { .addr = CC1120_TXFIRST, .name = "TXFIRST" },
1390 { .addr = CC1120_RXLAST, .name = "RXLAST" },
1391 { .addr = CC1120_TXLAST, .name = "TXLAST" },
1392 { .addr = CC1120_NUM_TXBYTES, .name = "NUM_TXBYTES" },
1393 { .addr = CC1120_NUM_RXBYTES, .name = "NUM_RXBYTES" },
1394 { .addr = CC1120_FIFO_NUM_TXBYTES, .name = "FIFO_NUM_TXBYTES" },
1395 { .addr = CC1120_FIFO_NUM_RXBYTES, .name = "FIFO_NUM_RXBYTES" },
1398 #define AO_NUM_CC1120_REG (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1400 static void ao_radio_show(void) {
1401 uint8_t status = ao_radio_status();
1405 status = ao_radio_status();
1406 printf ("Status: %02x\n", status);
1407 printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1408 printf ("STATE: %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1409 printf ("MARC: %02x\n", ao_radio_get_marc_status());
1411 for (i = 0; i < AO_NUM_CC1120_REG; i++)
1412 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1414 printf("RX fast start: %u\n", rx_fast_start);
1415 printf("RX slow start: %u\n", rx_slow_start);
1416 printf("RX missed: %u\n", rx_missed);
1420 static void ao_radio_beep(void) {
1424 static void ao_radio_packet(void) {
1425 static const uint8_t packet[] = {
1427 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1428 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1429 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1430 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1436 ao_radio_send(packet, sizeof (packet));
1440 ao_radio_test_recv(void)
1445 if (ao_radio_recv(bytes, 34, 0)) {
1446 if (bytes[33] & 0x80)
1450 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1451 for (b = 0; b < 32; b++)
1452 printf (" %02x", bytes[b]);
1458 #include <ao_aprs.h>
1463 ao_packet_slave_stop();
1469 static const struct ao_cmds ao_radio_cmds[] = {
1470 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
1473 { ao_radio_aprs, "G\0Send APRS packet" },
1475 { ao_radio_show, "R\0Show CC1120 status" },
1476 { ao_radio_beep, "b\0Emit an RDF beacon" },
1477 { ao_radio_packet, "p\0Send a test packet" },
1478 { ao_radio_test_recv, "q\0Recv a test packet" },
1486 ao_radio_configured = 0;
1487 ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1490 AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1491 for (i = 0; i < 10000; i++) {
1492 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1495 AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1497 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1500 /* Enable the EXTI interrupt for the appropriate pin */
1501 ao_enable_port(AO_CC1120_INT_PORT);
1502 ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1503 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1506 /* Enable the hacked up GPIO3 pin */
1507 ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1508 ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1509 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1510 ao_radio_mcu_wakeup_isr);
1512 ao_cmd_register(&ao_radio_cmds[0]);