From 638640113e870565762cf07a937d51072662d976 Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Thu, 15 Mar 2007 21:26:00 +0000 Subject: [PATCH] A very simple CC2420 driver that can only send and receive raw packets. No extra CC2420 functionality is enabled or used. --- core/dev/simple-cc2420.c | 449 +++++++++++++++++++++++++++++++++++++++ core/dev/simple-cc2420.h | 64 ++++++ 2 files changed, 513 insertions(+) create mode 100644 core/dev/simple-cc2420.c create mode 100644 core/dev/simple-cc2420.h diff --git a/core/dev/simple-cc2420.c b/core/dev/simple-cc2420.c new file mode 100644 index 000000000..cc00014f3 --- /dev/null +++ b/core/dev/simple-cc2420.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2007, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: simple-cc2420.c,v 1.1 2007/03/15 21:26:00 adamdunkels Exp $ + */ +/* + * This code is almost device independent and should be easy to port. + */ + +#include +#include + +#include "contiki.h" + +#if defined(__AVR__) +#include +#elif defined(__MSP430__) +#include +#endif + +#include "dev/leds.h" + +#include "dev/spi.h" +#include "dev/simple-cc2420.h" +#include "dev/cc2420_const.h" + +#define FOOTER1_CRC_OK 0x80 +#define FOOTER1_CORRELATION 0x7f + +#if 0 +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do {} while (0) +#endif +/*---------------------------------------------------------------------------*/ +PROCESS(simple_cc2420_process, "CC2420 driver"); +/*---------------------------------------------------------------------------*/ + +static void (* receiver_callback)(void); + +signed char simple_cc2420_last_rssi; +u8_t simple_cc2420_last_correlation; + +static u8_t receive_on; +/* Radio stuff in network byte order. */ +static u16_t pan_id; +/*---------------------------------------------------------------------------*/ +static unsigned +getreg(enum cc2420_register regname) +{ + unsigned reg; + int s = splhigh(); + FASTSPI_GETREG(regname, reg); + splx(s); + return reg; +} +/*---------------------------------------------------------------------------*/ +static void +setreg(enum cc2420_register regname, unsigned value) +{ + int s = splhigh(); + FASTSPI_SETREG(regname, value); + splx(s); +} +/*---------------------------------------------------------------------------*/ +static void +strobe(enum cc2420_register regname) +{ + int s = splhigh(); + FASTSPI_STROBE(regname); + splx(s); +} +/*---------------------------------------------------------------------------*/ +static unsigned +status(void) +{ + u8_t status; + int s = splhigh(); + FASTSPI_UPD_STATUS(status); + splx(s); + return status; +} +/*---------------------------------------------------------------------------*/ +#define AUTOACK (1 << 4) +#define ADR_DECODE (1 << 11) +#define RXFIFO_PROTECTION (1 << 9) +#define CORR_THR(n) (((n) & 0x1f) << 6) +#define FIFOP_THR(n) ((n) & 0x7f) +#define RXBPF_LOCUR (1 << 13); +/*---------------------------------------------------------------------------*/ +void +simple_cc2420_set_receiver(void (* recv)(void)) +{ + receiver_callback = recv; +} +/*---------------------------------------------------------------------------*/ +void +simple_cc2420_init(void) +{ + u16_t reg; + { + int s = splhigh(); + __cc2420_arch_init(); /* Initalize ports and SPI. */ + DISABLE_FIFOP_INT(); + FIFOP_INT_INIT(); + splx(s); + } + + /* Turn on voltage regulator and reset. */ + SET_VREG_ACTIVE(); + //clock_delay(250); OK + SET_RESET_ACTIVE(); + clock_delay(127); + SET_RESET_INACTIVE(); + //clock_delay(125); OK + + + /* Turn on the crystal oscillator. */ + strobe(CC2420_SXOSCON); + + /* Turn off automatic packet acknowledgment. */ + reg = getreg(CC2420_MDMCTRL0); + reg &= ~AUTOACK; + setreg(CC2420_MDMCTRL0, reg); + + /* Turn off address decoding. */ + reg = getreg(CC2420_MDMCTRL0); + reg &= ~ADR_DECODE; + setreg(CC2420_MDMCTRL0, reg); + + /* Change default values as recomended in the data sheet, */ + /* correlation threshold = 20, RX bandpass filter = 1.3uA. */ + setreg(CC2420_MDMCTRL1, CORR_THR(20)); + reg = getreg(CC2420_RXCTRL1); + reg |= RXBPF_LOCUR; + setreg(CC2420_RXCTRL1, reg); + + /* Set the FIFOP threshold to maximum. */ + setreg(CC2420_IOCFG0, FIFOP_THR(127)); + + /* Turn off "Security enable" (page 32). */ + reg = getreg(CC2420_SECCTRL0); + reg &= ~RXFIFO_PROTECTION; + setreg(CC2420_SECCTRL0, reg); + + simple_cc2420_set_chan_pan_addr(11, 0xffff, 0x0000, NULL); + + process_start(&simple_cc2420_process, NULL); +} +/*---------------------------------------------------------------------------*/ +int +simple_cc2420_send(const u8_t *payload, u8_t payload_len) +{ + u8_t spiStatusByte; + int s, i; + + /* struct hdr_802_15::len shall *not* be counted, thus the -1. + * 2 == sizeof(footer). + */ + /* if(((hdr_len - 1) + payload_len + 2) > MAX_PACKET_LEN) { + return -1; + }*/ + + /* This code uses the CC2420 CCA (Clear Channel Assessment) to + * implement Carrier Sense Multiple Access with Collision Avoidance + * (CSMA-CA) and requires the receiver to be enabled and ready. + */ + if(!receive_on) { + return -2; + } + + /* Wait for previous transmission to finish and RSSI. */ + do { + spiStatusByte = status(); + if(!(spiStatusByte & BV(CC2420_RSSI_VALID))) { /* RSSI needed by CCA */ + continue; + } + } while(spiStatusByte & BV(CC2420_TX_ACTIVE)); + +#if 0 + hdr->dst_pan = pan_id; /* Not at fixed position! xxx/bg */ + last_correspondent = hdr->dst; /* Not dst either. */ + last_used_seq++; + hdr->seq = last_used_seq; + cc2420_ack_received = 0; +#endif + + /* Write packet to TX FIFO, appending FCS if AUTOCRC is enabled. */ + strobe(CC2420_SFLUSHTX); /* Cancel send that never started. */ + s = splhigh(); + /* FASTSPI_WRITE_FIFO(hdr, hdr_len);*/ + FASTSPI_WRITE_FIFO(&payload_len, 1); + FASTSPI_WRITE_FIFO(payload, payload_len); + splx(s); + PRINTF("simple_cc2420_send: wrote %d bytes\n", payload_len); + + /* if(hdr->dst == 0xffff) { + int i; + for(i = 1; i < 3; i++) { + if(do_send() >= 0) { + return 0; + } + clock_delay(i*256); + } + }*/ + + if(FIFOP_IS_1 && !FIFO_IS_1) { + /* RXFIFO overflow, send on retransmit. */ + PRINTF("rxfifo overflow!\n"); + return -4; + } + + /* The TX FIFO can only hold one packet! Make sure to not overrun + * FIFO by waiting for transmission to start here and synchronizing + * with the CC2420_TX_ACTIVE check in cc2420_send. + * + * Note that we may have to wait up to 320 us (20 symbols) before + * transmission starts. + */ +#ifdef TMOTE_SKY +#define LOOP_20_SYMBOLS 100 /* 326us (msp430 @ 2.4576MHz) */ +#elif __AVR__ +#define LOOP_20_SYMBOLS 500 /* XXX */ +#endif + strobe(CC2420_STXONCCA); + for(i = LOOP_20_SYMBOLS; i > 0; i--) { + if(SFD_IS_1) { + PRINTF("simple_cc2420: do_send() transmission has started\n"); + return 0; /* Transmission has started. */ + } + } + + PRINTF("simple_cc2420: do_send() transmission never started\n"); + return -3; /* Transmission never started! */ +} +/*---------------------------------------------------------------------------*/ +void +simple_cc2420_off(void) +{ + u8_t spiStatusByte; + + if (receive_on == 0) + return; + receive_on = 0; + /* Wait for transmission to end before turning radio off. */ + do { + spiStatusByte = status(); + } while(spiStatusByte & BV(CC2420_TX_ACTIVE)); + + strobe(CC2420_SRFOFF); + DISABLE_FIFOP_INT(); +} +/*---------------------------------------------------------------------------*/ +void +simple_cc2420_on(void) +{ + if(receive_on) { + return; + } + receive_on = 1; + + strobe(CC2420_SRXON); + strobe(CC2420_SFLUSHRX); + ENABLE_FIFOP_INT(); +} +/*---------------------------------------------------------------------------*/ +void +simple_cc2420_set_chan_pan_addr(unsigned channel, /* 11 - 26 */ + unsigned pan, + unsigned addr, + const u8_t *ieee_addr) +{ + /* + * Subtract the base channel (11), multiply by 5, which is the + * channel spacing. 357 is 2405-2048 and 0x4000 is LOCK_THR = 1. + */ + u8_t spiStatusByte; + u16_t f = channel; + int s; + + f = 5*(f - 11) + 357 + 0x4000; + /* + * Writing RAM requires crystal oscillator to be stable. + */ + do { + spiStatusByte = status(); + } while(!(spiStatusByte & (BV(CC2420_XOSC16M_STABLE)))); + + pan_id = pan; + setreg(CC2420_FSCTRL, f); + s = splhigh(); + FASTSPI_WRITE_RAM_LE(&pan, CC2420RAM_PANID, 2, f); + FASTSPI_WRITE_RAM_LE(&addr, CC2420RAM_SHORTADDR, 2, f); + if(ieee_addr != NULL) { + FASTSPI_WRITE_RAM_LE(ieee_addr, CC2420RAM_IEEEADDR, 8, f); + } + splx(s); +} +/*---------------------------------------------------------------------------*/ +static volatile u8_t rx_fifo_remaining_bytes; + +/* + * Interrupt either leaves frame intact in FIFO or reads *only* the + * MAC header and sets rx_fifo_remaining_bytes. + * + * In order to quickly empty the FIFO ack processing is done at + * interrupt priority rather than poll priority. + */ +int +__cc2420_intr(void) +{ + u8_t length; + /* const u8_t *const ack_footer = (u8_t *)&h.dst_pan;*/ + + leds_toggle(LEDS_YELLOW); + CLEAR_FIFOP_INT(); + + if(spi_busy || rx_fifo_remaining_bytes > 0) { + /* SPI bus hardware is currently used elsewhere (UART0 or I2C bus) + * or we already have a packet in the works and will have to defer + * interrupt processing of this packet in a fake interrupt. + */ + process_poll(&simple_cc2420_process); + return 1; + } + + FASTSPI_READ_FIFO_BYTE(length); + if(length > SIMPLE_CC2420_MAX_PACKET_LEN) { + /* Oops, we must be out of sync. */ + FASTSPI_STROBE(CC2420_SFLUSHRX); + FASTSPI_STROBE(CC2420_SFLUSHRX); + leds_toggle(LEDS_RED); + return 0; + } + + + /* The payload and footer is now left in the RX FIFO and will be + * picked up asynchronously at poll priority in the cc2420_process + * below. + */ + rx_fifo_remaining_bytes = length; + process_poll(&simple_cc2420_process); + leds_toggle(LEDS_GREEN); + return 1; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(simple_cc2420_process, ev, data) +{ + PROCESS_BEGIN(); + + while(1) { + PROCESS_YIELD(); + + if(receiver_callback != NULL) { + receiver_callback(); + } else { + PRINTF("simple_cc2420_process dropping %d bytes\n", + rx_fifo_remaining_bytes); + if(rx_fifo_remaining_bytes > 0) { + int s; + s = splhigh(); + FASTSPI_READ_FIFO_GARBAGE(rx_fifo_remaining_bytes); + rx_fifo_remaining_bytes = 0; /* RX FIFO emptied! */ + splx(s); + } + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +int +simple_cc2420_read(u8_t *buf, u8_t bufsize) +{ + u8_t footer[2]; + int len; + int s; + + len = rx_fifo_remaining_bytes; + + if(len > 0) { + /* Read payload and two bytes of footer */ + if(len > bufsize) { + PRINTF("simple_cc2420_poll too big len=%d\n", len); + s = splhigh(); + FASTSPI_READ_FIFO_GARBAGE(len); + rx_fifo_remaining_bytes = 0; /* RX FIFO emptied! */ + splx(s); + len = 0; + } else { + s = splhigh(); + FASTSPI_READ_FIFO_NO_WAIT(buf, len - 2); + FASTSPI_READ_FIFO_NO_WAIT(footer, 2); + rx_fifo_remaining_bytes = 0; /* RX FIFO emptied! */ + splx(s); + if(footer[1] & FOOTER1_CRC_OK) { + simple_cc2420_last_rssi = footer[0]; + simple_cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; + /* if((h.fc0 & FC0_TYPE_MASK) == FC0_TYPE_DATA) { + uip_len = len - 2; + }*/ + } + } + } + + /* Clean up in case of FIFO overflow! This happens for every full + * length frame and is signaled by FIFOP = 1 and FIFO = 0. + */ + if(FIFOP_IS_1 && !FIFO_IS_1) { + strobe(CC2420_SFLUSHRX); + strobe(CC2420_SFLUSHRX); + } + + if(FIFOP_IS_1) { + s = splhigh(); + __cc2420_intr(); /* Fake interrupt! */ + splx(s); + } + + return len; +} +/*---------------------------------------------------------------------------*/ diff --git a/core/dev/simple-cc2420.h b/core/dev/simple-cc2420.h new file mode 100644 index 000000000..cc82605e8 --- /dev/null +++ b/core/dev/simple-cc2420.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2007, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: simple-cc2420.h,v 1.1 2007/03/15 21:26:00 adamdunkels Exp $ + */ + +/** + * \file + * A brief description of what this file is. + * \author + * Adam Dunkels + */ + +#ifndef __SIMPLE_CC2420_H__ +#define __SIMPLE_CC2420_H__ + +#include "contiki.h" + +#define SIMPLE_CC2420_MAX_PACKET_LEN 127 + +void simple_cc2420_init(void); + +void simple_cc2420_on(void); +void simple_cc2420_off(void); + +int simple_cc2420_read(u8_t *buf, u8_t bufsize); + +int simple_cc2420_send(const u8_t *data, u8_t len); + +void simple_cc2420_set_receiver(void (* recv)(void)); + +void simple_cc2420_set_chan_pan_addr(unsigned channel, /* 11 - 26 */ + unsigned pan, + unsigned addr, + const u8_t *ieee_addr); + +#endif /* __SIMPLE_CC2420_H__ */