/* wireless.c ================================================================================================
*
* This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTYT; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Author(s): Ole Saether
*
* NOTES:
*
* A frame is the time between each transmission of a packet.
* A frame is divided into NSLOTS time-slots. The duration of a time-slot is 1/fs, where fs is the ADC
* sampling frequency.
*
* The NOSYNC variable is used by the slave to keep track of how many frames have gone since it received a
* valid packet. It is incremented once each frame in the TIMER2 irq handler and cleared each time a packet is
* received. If the variable reaches the constant NSYNC (see below) the slave enters continuous receive mode.
*
* The pin P0.2 is used to select slave (P0.2 = 1) or master (P0.2 = 0).
*
* $Date: 8.10.03 12:02 $
* $Revision: 1 $
*
*=============================================================================================================
*/
#include <Nordic\reg24e1.h>
#define ADDR_INDEX 8 // Index to address bytes in RFConfig.buf
#define ADDR_COUNT 4 // Number of address bytes
#define FSZ 32 // Buffer size
#define FMASK FSZ-1
struct RFConfig
{
unsigned char n;
unsigned char buf[15];
};
typedef struct RFConfig RFConfig;
#define NSLOTS 24 // Number of samples in one packet
#define NSYNC 10 // #frames wo/packets before the slave enters receive mode
#define RXSLOT 14 // Wait from slot 14 to..
#define WTSLOT 21 // ..slot 21 for reception of a packet
#define SYNCSLOT 20 // When the slave receives a valid packet set the slot counter to this number
volatile unsigned char idata RxBuf[FSZ];
volatile unsigned char idata TxBuf[FSZ];
volatile unsigned char TxWrp, TxRdp, TxNum;
volatile unsigned char RxWrp, RxRdp, RxNum;
volatile unsigned char rec, slotn, nosync, slave, prevsample;
const RFConfig RxTxConf =
{
15,
0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xaa, 0xbb, 0x12, 0x34, 0x83, 0x6f, 0x04
};
void InitBuffers(void)
{
RxWrp = RxRdp = RxRdp = RxNum = 0;
TxWrp = TxRdp = TxRdp = TxNum = 0;
}
void Delay100us(volatile unsigned char n)
{
unsigned char i;
while(n--)
for(i=0;i<35;i++)
;
}
unsigned char SpiReadWrite(unsigned char b)
{
EXIF &= ~0x20; // Clear SPI interrupt
SPI_DATA = b; // Move byte to send to SPI data register
while((EXIF & 0x20) == 0x00) // Wait until SPI hs finished transmitting
;
return SPI_DATA;
}
void Init(void)
{
unsigned char i;
P0_DIR = 0x04; // P0.2 is input, the rest output
P0 = 0x02; // P0.1 = 1 for the master/slave selection
slotn = nosync = 0;
InitBuffers();
if ((P0 & 0x04) == 0x04)
slave = 1;
else
slave = 0;
// TIMER2:
TR2 = 0; // Stop timer2 if running
CKCON |= 0x20; // T2M=1 (/4 timer clock)
RCAP2L = 0x0C; // 8KHz tick...
RCAP2H = 0xFE; // ... = 65536-16e6/(4*8e3) = FE0Ch
TF2 = 0; // Clear any pending timer2 interrupts
TR2 = 1; // Start timer2
ET2 = 1; // Enable timer2 interrupts
// PWM:
P0_ALT = 0x80; // Enable PWM output (P0.7)
PWMCON = 0xC0; // Enable 8 bit PWM, pre=min
PWMDUTY = 0xFF;
// ADC:
ADCSTATIC &= 0x1C; // DIFFM=0, SLEEP=0, CLK8=0
ADCSTATIC |= 0x03; // 12 bit
ADCCON = 0x32; // Channel 2, NPD=1, ADCRUN=0, EXTREF=1
// RADIO:
PWR_UP = 1;
Delay100us(30); // Wait > 3ms
// SPI:
SPICLK = 0x00; // Max SPICLK (=CLK/8)
SPI_CTRL = 0x02; // Connect SPI to RADIO CH1
// RADIO:
CE = 0;
CS = 1; // RF SPI CS = 1
Delay100us(0);
for(i=0;i<RxTxConf.n;i++)
{
SpiReadWrite(RxTxConf.buf[i]);
}
CS = 0;
EA = 1; // Enable global interrupts
}
void TxPacket(void)
{
unsigned char i, rp;
CE = 1;
Delay100us(0);
// All packets start with the address:
for (i=0;i<ADDR_COUNT;i++)
{
SpiReadWrite(RxTxConf.buf[ADDR_INDEX+i]);
}
/*
* Read the packet from the transmit buffer and write it to the radio with inline
* SPI commands (for increased speed) and update the buffer write pointer and
* number of bytes in buffer:
*/
rp = TxRdp;
for (i=0;i<NSLOTS;i++)
{
EXIF &= ~0x20; // Clear SPI interrupt
SPI_DATA = TxBuf[rp]; // Move byte to send to SPI data register
rp++;
rp &= FMASK;
ET2 = 0;
TxNum--;
ET2 = 1;
while((EXIF & 0x20) == 0x00) // Wait until SPI hs finished transmitting
;
}
CE = 0;
TxRdp = rp;
}
void RxPacket(void)
{
unsigned char wp;
if(slave)
{
/*
* Tell the interrupt routine that we have received
* a packet and it's time to sync to the master:
*/
ET2 = 0;
rec = 1;
nosync = 0;
ET2 = 1;
}
/*
* Read the received packet from the radio with inline SPI commands (for increased speed)
* and put it in the receive buffer and advance the buffer write pointer, and number of
* bytes in the buffer:
*/
while(DR1)
{
EXIF &= ~0x20; // Clear SPI interrupt
SPI_DATA = 0; // Write dummy byte to SPI data register
wp = RxWrp;
RxWrp++;
RxWrp &= FMASK;
while((EXIF & 0x20) == 0x00) // Wait until SPI hs finished receiving
;
RxBuf[wp] = SPI_DATA;
ET2 = 0;
RxNum++;
ET2 = 1;
}
}
void Timer2ISR (void) interrupt 5 using 1
{
unsigned char adc;
TF2 = 0; // Clear timer2 interrupt
adc = ADCDATAH; // Read ADC and...
ADCCON &= ~0x80; // ...start new...
ADCCON |= 0x80; // ...conversion
if(RxNum > 0)
{
/*
* If there are any samples in receive buffer, write next
* sample to the PWM and advance the buffer read pointer.
*/
PWMDUTY = RxBuf[RxRdp];
RxRdp++;
RxRdp &= FMASK;
RxNum--;
}
TxBuf[TxWrp] = adc; // Write ADC sample to the transmit buffer and..
TxWrp++; // ..advance buffer..
TxWrp &= FMASK; // ..write pointer
TxNum++;
if(rec != 0) // Valid packet received by slave?
{
rec = 0; // Yes, preset time...
slotn = SYNCSLOT; // ...slot counter (sync to master)
} else
{
slotn++; // Increment time slot counter
if(slotn == NSLOTS) // If at beginning of frame....
{
slotn = 0; // ... reset