www.pudn.com > CC2420_TRX.rar > hal.h
/*******************************************************************************************************
* *
* ********** *
* ************ *
* *** *** *
* *** +++ *** *
* *** + + *** *
* *** + CHIPCON HARDWARE ABSTRACTION LIBRARY FOR THE CC2420 *
* *** + + *** Library header file *
* *** +++ *** *
* *** *** *
* ************ *
* ********** *
* *
*******************************************************************************************************
* The Chipcon Hardware Abstraction Library is a collection of functions, macros and constants, which *
* can be used to ease access to the hardware on the CC2420 and the target microcontroller. *
* *
* All HAL library macros and constants are defined here. *
*******************************************************************************************************
* Compiler: AVR-GCC *
* Target platform: CC2420DB, CC2420 + any ATMEGA MCU *
*******************************************************************************************************
* Revision history: *
* $Log: hal.h,v $
* Revision 1.8 2004/03/30 14:59:03 mbr
* Release for web
*
*
*
*******************************************************************************************************/
#ifndef HAL_H
#define HAL_H
/*******************************************************************************************************
*******************************************************************************************************
************************** AVR<->CC2420 SPI INTERFACE **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// Initialization
// Initialize mcu
#define Mcu_INIT() \
do { \
DISABLE_GLOBAL_INT(); \
XDIV = 0x00; \
XMCRA = 0x00; \
XMCRB = 0x00; \
MCUCR = 0x80; \
ENABLE_GLOBAL_INT(); \
} while (0)
// Enables SPI, selects "master", clock rate FCK / 2, and SPI mode 0
#define SPI_INIT() \
do { \
DISABLE_GLOBAL_INT(); \
SPCR = BM(SPE) | BM(MSTR); \
SPSR = BM(SPI2X); \
ENABLE_GLOBAL_INT(); \
} while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// FAST SPI: Low level functions
// x = value (BYTE or WORD)
// p = pointer to the byte array to operate on
// c = the byte count
//
// SPI_ENABLE() and SPI_DISABLE() are located in the devboard header file (CS_N uses GPIO)
#define FASTSPI_WAIT() \
do { \
while (!(SPSR & BM(SPIF))); \
} while (0)
#define FASTSPI_TX(x) \
do { \
SPDR = x; \
FASTSPI_WAIT(); \
} while (0)
#define FASTSPI_RX(x) \
do { \
SPDR = 0; \
FASTSPI_WAIT(); \
x = SPDR; \
} while (0)
#define FASTSPI_RX_GARBAGE() \
do { \
SPDR = 0; \
FASTSPI_WAIT(); \
} while (0)
#define FASTSPI_TX_WORD_LE(x) \
do { \
FASTSPI_TX(x); \
FASTSPI_TX((x) >> 8); \
} while (0)
#define FASTSPI_TX_WORD(x) \
do { \
FASTSPI_TX(((WORD)(x)) >> 8); \
FASTSPI_TX((BYTE)(x)); \
} while (0)
#define FASTSPI_TX_MANY(p,c) \
do { \
for (UINT8 spiCnt = 0; spiCnt < (c); spiCnt++) { \
FASTSPI_TX(((BYTE*)(p))[spiCnt]); \
} \
} while (0)
#define FASTSPI_RX_WORD_LE(x) \
do { \
SPDR = 0; \
FASTSPI_WAIT(); \
x = SPDR; \
SPDR = 0; \
FASTSPI_WAIT(); \
x |= SPDR << 8; \
} while (0)
#define FASTSPI_RX_WORD(x) \
do { \
SPDR = 0; \
FASTSPI_WAIT(); \
x = SPDR << 8; \
SPDR = 0; \
FASTSPI_WAIT(); \
x |= SPDR; \
} while (0)
#define FASTSPI_RX_MANY(p,c) \
do { \
for (UINT8 spiCnt = 0; spiCnt < (c); spiCnt++) { \
FASTSPI_RX((p)[spiCnt]); \
} \
} while (0)
// Register address:
#define FASTSPI_TX_ADDR(a) \
do { \
SPDR = a; \
FASTSPI_WAIT(); \
} while (0)
// Register address:
#define FASTSPI_RX_ADDR(a) \
do { \
SPDR = (a) | 0x40; \
FASTSPI_WAIT(); \
} while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// FAST SPI: Register access
// s = command strobe
// a = register address
// v = register value
#define FASTSPI_STROBE(s) \
do { \
SPI_ENABLE(); \
FASTSPI_TX_ADDR(s); \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_SETREG(a,v) \
do { \
SPI_ENABLE(); \
FASTSPI_TX_ADDR(a); \
FASTSPI_TX((BYTE) ((v) >> 8)); \
FASTSPI_TX((BYTE) (v)); \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_GETREG(a,v) \
do { \
SPI_ENABLE(); \
SPDR = (a) | 0x40; \
FASTSPI_WAIT(); \
FASTSPI_RX_WORD(v); \
SPI_DISABLE(); \
} while (0)
// Updates the SPI status byte
#define FASTSPI_UPD_STATUS(s) \
do { \
SPI_ENABLE(); \
FASTSPI_TX_ADDR(CC2420_SNOP); \
s = SPDR; \
SPI_DISABLE(); \
} while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// FAST SPI: FIFO access
// p = pointer to the byte array to be read/written
// c = the number of bytes to read/write
// b = single data byte
#define FASTSPI_WRITE_FIFO(p,c) \
do { \
SPI_ENABLE(); \
FASTSPI_TX_ADDR(CC2420_TXFIFO); \
for (UINT8 spiCnt = 0; spiCnt < (c); spiCnt++) { \
FASTSPI_TX(((BYTE*)(p))[spiCnt]); \
} \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_READ_FIFO(p,c) \
do { \
SPI_ENABLE(); \
SPDR = (CC2420_RXFIFO) | 0x40; \
FASTSPI_WAIT(); \
for (UINT8 spiCnt = 0; spiCnt < (c); spiCnt++) { \
while (!FIFO_IS_1); \
FASTSPI_RX(((BYTE*)(p))[spiCnt]); \
} \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_READ_FIFO_BYTE(b) \
do { \
SPI_ENABLE(); \
FASTSPI_RX_ADDR(CC2420_RXFIFO); \
FASTSPI_RX(b); \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_READ_FIFO_NO_WAIT(p,c) \
do { \
SPI_ENABLE(); \
SPDR = (CC2420_RXFIFO) | 0x40; \
FASTSPI_WAIT(); \
for (UINT8 spiCnt = 0; spiCnt < (c); spiCnt++) { \
FASTSPI_RX(((BYTE*)(p))[spiCnt]); \
} \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_READ_FIFO_GARBAGE(c) \
do { \
SPI_ENABLE(); \
FASTSPI_RX_ADDR(CC2420_RXFIFO); \
for (UINT8 spiCnt = 0; ((spiCnt < (c)) && (FIFO_IS_1)); spiCnt++) { \
FASTSPI_RX_GARBAGE(); \
} \
SPI_DISABLE(); \
} while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// FAST SPI: CC2420 RAM access (big or little-endian order)
// p = pointer to the variable to be written
// a = the CC2420 RAM address
// c = the number of bytes to write
// n = counter variable which is used in for/while loops (UINT8)
//
// Example of usage:
// UINT8 n;
// UINT16 shortAddress = 0xBEEF;
// FASTSPI_WRITE_RAM_LE(&shortAddress, CC2420RAM_SHORTADDR, 2);
#define FASTSPI_WRITE_RAM_LE(p,a,c,n) \
do { \
SPI_ENABLE(); \
FASTSPI_TX(0x80 | (a & 0x7F)); \
FASTSPI_TX((a >> 1) & 0xC0); \
for (n = 0; n < (c); n++) { \
FASTSPI_TX(((BYTE*)(p))[n]); \
} \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_READ_RAM_LE(p,a,c,n) \
do { \
SPI_ENABLE(); \
FASTSPI_TX(0x80 | (a & 0x7F)); \
FASTSPI_TX(((a >> 1) & 0xC0) | 0x20); \
for (n = 0; n < (c); n++) { \
FASTSPI_RX(((BYTE*)(p))[n]); \
} \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_WRITE_RAM(p,a,c,n) \
do { \
SPI_ENABLE(); \
FASTSPI_TX(0x80 | (a & 0x7F)); \
FASTSPI_TX((a >> 1) & 0xC0); \
n = c; \
do { \
FASTSPI_TX(((BYTE*)(p))[--n]); \
} while (n); \
SPI_DISABLE(); \
} while (0)
#define FASTSPI_READ_RAM(p,a,c,n) \
do { \
SPI_ENABLE(); \
FASTSPI_TX(0x80 | (a & 0x7F)); \
FASTSPI_TX(((a >> 1) & 0xC0) | 0x20); \
n = c; \
do { \
FASTSPI_RX(((BYTE*)(p))[--n]); \
} while (n); \
SPI_DISABLE(); \
} while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// Other useful SPI macros
#define FASTSPI_RESET_CC2420() \
do { \
FASTSPI_SETREG(CC2420_MAIN, 0x0000); \
FASTSPI_SETREG(CC2420_MAIN, 0xF800); \
} while (0)
//-------------------------------------------------------------------------------------------------------
/*******************************************************************************************************
*******************************************************************************************************
************************** INTERRUPTS **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// General
#define ENABLE_GLOBAL_INT() do { asm ("sei\n\t" ::); } while (0)
#define DISABLE_GLOBAL_INT() do { asm ("cli\n\t" ::); } while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// UART1 interrupts
#define ENABLE_UART1_INT() do { UCSR1B |= (BM(UDRIE1) | BM(RXCIE1)); } while (0)
#define DISABLE_UART1_INT() do { UCSR1B &= ~(BM(UDRIE1) | BM(RXCIE1)); } while (0)
#define ENABLE_UART1_TX_INT() do { UCSR1B |= BM(UDRIE1); } while (0)
#define DISABLE_UART1_TX_INT() do { UCSR1B &= ~BM(UDRIE1); } while (0)
#define CLEAR_UART1_TX_INT() do { UCSR1A &= ~BM(UDRE1); } while (0)
#define SET_UART1_TX_INT() do { UCSR1A |= BM(UDRE1); } while (0)
#define ENABLE_UART1_RX_INT() do { UCSR1B |= BM(RXCIE1); } while (0)
#define DISABLE_UART1_RX_INT() do { UCSR1B &= ~BM(RXCIE1); } while (0)
#define CLEAR_UART1_RX_INT() do { UCSR1A &= ~BM(RXC1); } while (0)
//-------------------------------------------------------------------------------------------------------
/*******************************************************************************************************
*******************************************************************************************************
************************** ADC **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// ADC initialization
#define ADC_INIT() \
do { \
ADCSRA = BM(ADPS0) | BM(ADPS1) | BM(ADFR); \
ADMUX = BM(REFS0); \
} while (0)
// Selects which ADC channel to use. The channels (0-3) are defined in the development board definition
// files, e.g. hal_cc2420db.h, as ADC_INPUT_...
#define ADC_SET_CHANNEL(channel) do { ADMUX = (ADMUX & ~0x1F) | (channel); } while (0)
// Enables/disables the ADC
#define ADC_ENABLE() do { ADCSRA |= BM(ADEN); } while (0)
#define ADC_DISABLE() do { ADCSRA &= ~BM(ADEN); } while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// ADC sampling
// Macro for taking a single sample in single-conversion mode (not required in continuous mode)
#define ADC_SAMPLE_SINGLE() \
do { \
ADCSRA |= BM(ADSC); \
while (!(ADCSRA & 0x10)); \
} while(0)
// Macros for obtaining the latest sample value
#define ADC_GET_SAMPLE_10(x) \
do { \
x = ADCL; \
x |= ADCH << 8; \
} while (0)
#define ADC_GET_SAMPLE_8(x) \
do { \
x = ((UINT8) ADCL) >> 2; \
x |= ((INT8) ADCH) << 6; \
} while (0)
//-------------------------------------------------------------------------------------------------------
/*******************************************************************************************************
*******************************************************************************************************
************************** Timer / Pulse Width Modulator **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// Pulse width modulator (PWM) using timer 0 (8 bits)
//
// Example of usage:
// // Initialize
// PWM_INIT(TIMER_CLK_DIV1);
//
// // Increase level gradually (over approx 2.5 seconds)
// for (UINT8 n; n < 255; n++) {
// PWM0_SET_DUTY_CYCLE(n);
// halWait(10000);
// }
// Initialization
#define PWM0_INIT(period) \
do { \
OCR0 = 0; \
TCCR0 = BM(WGM01)|BM(WGM00) | BM(COM01) | BM(COM00); \
PWM0_SET_PERIOD(period); \
} while(0)
// Sets the PWM period
#define PWM0_SET_PERIOD(period) do { TCCR0 = ((TCCR0 & ~0x07) | (period)); } while (0)
// Period definitions for use with the PWM0_INIT and PWM0_SET_PERIOD macros
#define TIMER_CLK_STOP 0x00 /* Stop mode (the timer is not counting) */
#define TIMER_CLK_DIV1 0x01 /* Total period = Clock freq / 256 */
#define TIMER_CLK_DIV8 0x02 /* Total period = Clock freq / (256 * 8) */
#define TIMER_CLK_DIV32 0x03 /* Total period = Clock freq / (256 * 64) */
#define TIMER_CLK_DIV64 0x04 /* Total period = Clock freq / (256 * 256) */
#define TIMER_CLK_DIV128 0x05 /* Total period = Clock freq / (256 * 1024) */
#define TIMER_CLK_DIV256 0x06 /* Total period = Clock freq / (256 * 1024) */
#define TIMER_CLK_DIV1024 0x07 /* Total period = Clock freq / (256 * 1024) */
//#define TIMER_CLK_T_FALL 0x06 /* External Clock on T(x) pin (falling edge) */
//#define TIMER_CLK_T_RISE 0x07 /* External Clock on T(x) pin (rising edge) */
// Sets the PWM duty cycle
#define PWM0_SET_DUTY_CYCLE(dutyCycle) do { OCR0 = (dutyCycle); } while (0)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// Timer/Counter0 interrupts
// Compare match interrupt
#define ENABLE_T0_COMPARE_INT() do { TIMSK |= BM(OCIE0); } while (0)
#define DISABLE_T0_COMPARE_INT() do { TIMSK &= ~BM(OCIE0); } while (0)
#define CLEAR_T0_COMPARE_INT() do { TIFR &= ~BM(TOV0); } while (0)
// Overflow interrupt
#define ENABLE_T0_OVERFLOW_INT() do { TIMSK |= BM(TOIE1); } while (0)
#define DISABLE_T0_OVERFLOW_INT() do { TIMSK &= ~BM(TOIE1); } while (0)
#define CLEAR_T0_OVERFLOW_INT() do { TIFR &= ~BM(OCF0)); } while (0)
//-------------------------------------------------------------------------------------------------------
/*******************************************************************************************************
*******************************************************************************************************
************************** SERIAL PORT (UART1) **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// INIT_UART1(baudRate,options)
//
// DESCRIPTION:
// A macro which does all the initialization necessary to communicate on UART 1. The UART is
// configured according to options (defined below). Note that this macro does not call
// ENABLE_UART1().
//
// ARGUMENTS:
// baudRate
// One of the UART_BAUDRATE_... constants defined below
// options
// One or more of the UART_OPT constants defined below. The value 0 gives one stop bit, no
// parity and 5 bits per char.
//-------------------------------------------------------------------------------------------------------
#define INIT_UART1(baudRate,options) \
do { \
UBRR1H = (baudRate) >> 8; \
UBRR1L = (baudRate); \
UCSR1C = (BYTE) options; \
if (options > 0xFF) { \
UCSR1B |= 0x04; \
} else { \
UCSR1B &= ~0x04; \
} \
UCSR1A |= BM(U2X1); \
} while (0)
// Baud rate codes for use with the INIT_UART1 macro
#define UART_BAUDRATE_2K4 416
#define UART_BAUDRATE_4K8 207
#define UART_BAUDRATE_9K6 103
#define UART_BAUDRATE_14K4 68
#define UART_BAUDRATE_19K2 51
#define UART_BAUDRATE_28K8 34
#define UART_BAUDRATE_38K4 25
#define UART_BAUDRATE_57K6 16
#define UART_BAUDRATE_76K8 12
#define UART_BAUDRATE_115K2 8
#define UART_BAUDRATE_230K4 3
#define UART_BAUDRATE_250K 3
#define UART_BAUDRATE_500K 1
#define UART_BAUDRATE_1M 0
// Options for use with the INIT_UART1 macro
#define UART_OPT_ONE_STOP_BIT 0
#define UART_OPT_TWO_STOP_BITS 0x08
#define UART_OPT_NO_PARITY 0
#define UART_OPT_EVEN_PARITY 0x20
#define UART_OPT_ODD_PARITY 0x30
#define UART_OPT_5_BITS_PER_CHAR 0
#define UART_OPT_6_BITS_PER_CHAR 0x02
#define UART_OPT_7_BITS_PER_CHAR 0x04
#define UART_OPT_8_BITS_PER_CHAR 0x06
#define UART_OPT_9_BITS_PER_CHAR 0x0406
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// Enable/disable macros
// Enable/disable UART1
#define ENABLE_UART1() (UCSR1B |= (BM(RXEN1) | BM(TXEN1)))
#define DISABLE_UART1() (UCSR1B &= ~(BM(RXEN1) | BM(TXEN1)))
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// Macros which are helful when transmitting and receiving data over the serial interface.
//
// Example of usage:
// UART1_SEND(pData[0]);
// for (i = 1; i < len; i++) {
// UART1_WAIT_AND_SEND(pData[i]);
// }
#define UART1_WAIT() do { while (!(UCSR1A & BM(UDRE1))); CLEAR_UART1_TX_INT(); } while (0)
#define UART1_SEND(x) do { UDR1 = (x); } while (0)
#define UART1_WAIT_AND_SEND(x) do { UART1_WAIT(); UART1_SEND(x); } while (0)
#define UART1_RECEIVE(x) do { (x) = UDR1; } while (0)
#define UART1_WAIT_AND_RECEIVE(x) do { UDR = 0; UART1_WAIT(); UART1_RX(x); } while (0)
//-------------------------------------------------------------------------------------------------------
/*******************************************************************************************************
*******************************************************************************************************
************************** Timter / Counter 0 **************************
*******************************************************************************************************
*******************************************************************************************************/
#define TIMER0_OFF 0
#define TIMER0_PRESCALE_1 1
#define TIMER0_PRESCALE_8 2
#define TIMER0_PRESCALE_32 3
#define TIMER0_PRESCALE_64 4
#define TIMER0_PRESCALE_128 5
#define TIMER0_PRESCALE_256 6
#define TIMER0_PRESCALE_1024 7
#define TIMER0_WGM_0 0x00
#define TIMER0_WGM_1 0x40
#define TIMER0_WGM_2 0x08
#define TIMER0_WGM_3 0x48
#define TIMER0_COM_0 0x00
#define TIMER0_COM_1 0x08
#define TIMER0_COM_2 0x10
#define TIMER0_COM_3 0x18
#define TIMER0_COM_4 0x20
#define TIMER0_COM_5 0x28
#define TIMER0_COM_6 0x30
#define TIMER0_COM_7 0x38
#define TIMER0_SET_CONTROL(x) do {TCCR0 = (x); } while (0)
#define TIMER0_SET_VALUE(x) do {TCNT0 = (x); } while (0)
#define TIMER0_READ_VALUE(x) do {(x) = TCNT0; } while (0)
#define TIMER0_SET_COMPARE_VALUE(x) do {OCR0 = (x); } while (0)
#define TIMER0_READ_COMPARE_VALUE(x) do {(x) = OCR0; } while (0)
/*******************************************************************************************************
*******************************************************************************************************
************************** USEFUL STUFF **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// Useful stuff
#define NOP() asm volatile ("nop\n\t" ::)
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// void halWait(UINT16 timeout)
//
// DESCRIPTION:
// Runs an idle loop for [timeout] microseconds.
//
// ARGUMENTS:
// UINT16 timeout
// The timeout in microseconds
//-------------------------------------------------------------------------------------------------------
void halWait(UINT16 timeout);
/*******************************************************************************************************
*******************************************************************************************************
************************** SIMPLE CC2420 FUNCTIONS **************************
*******************************************************************************************************
*******************************************************************************************************/
//-------------------------------------------------------------------------------------------------------
// Example of usage: Starts RX on channel 14 after reset
// FASTSPI_RESET_CC2420();
// FASTSPI_STROBE(CC2420_SXOSCON);
// halRfSetChannel(14);
// ... other registers can for instance be initialized here ...
// halRfWaitForCrystalOscillator();
// ... RAM access can be done here, since the crystal oscillator must be on and stable ...
// FASTSPI_STROBE(CC2420_SRXON);
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// void rfWaitForCrystalOscillator(void)
//
// DESCRIPTION:
// Waits for the crystal oscillator to become stable. The flag is polled via the SPI status byte.
//
// Note that this function will lock up if the SXOSCON command strobe has not been given before the
// function call. Also note that global interrupts will always be enabled when this function
// returns.
//-------------------------------------------------------------------------------------------------------
void halRfWaitForCrystalOscillator(void);
//-------------------------------------------------------------------------------------------------------
// void halRfSetChannel(UINT8 Channel)
//
// DESCRIPTION:
// Programs CC2420 for a given IEEE 802.15.4 channel.
// Note that SRXON, STXON or STXONCCA must be run for the new channel selection to take full effect.
//
// PARAMETERS:
// UINT8 channel
// The channel number (11-26)
//-------------------------------------------------------------------------------------------------------
void halRfSetChannel(UINT8 channel);
#endif