Cypress CYWM6935 is a budget-limited ($9.75/ea. via
), FCC Type Certified, 2.7V to 3.6V, Industrial Temp, connect serial port at up to 2M, 2.4GHz RF module with range 50m outdoors LoS, 64kbps
Radio driver looks something like (origin is 8052)... ~1.5Kbytes of code space, ~70 bytes ram space:
Code: Select all#define SPI_WR 0x80
#define SPI_RD 0x00
#define SPI_INC 0x40
#define SPI_FRZ 0x00
// 0.65 is the implementation specific cal factor for DelayMicroSec();
#define SYNTH_SETTLE 200 * 0.65 // 200usec
#define PREAMBLE 32 * 0.65 // 32usec
#define RECEIVER_READY 35 * 0.65 // 35usec
#define CRYSTAL_STARTUP 2100 * 0.65 // 2100usec
#define RSSI_ADC_CONVERSION 50 * 0.65 // 50usec
#define tPD 10 * 0.65 // 10usec
#define tPWR_RST 1300 * 0.65 // 1300usec
#define tPDN_X13 2000 * 0.65 // 2000usec
#define tSPI_RDY 1 * 0.65 // 1usec
// RadioInit table
const BYTE code RadioInitTable[] =
{
0x20, 0x45, //REG_ANALOG_CTL
0x20, 0x44, //REG_ANALOG_CTL
0x2E, 0x80, //REG_PWR_CTL
0x26, 0xC0, //REG_VCO_CAL
0x33, 0x41, //REG_CLOCK_ENABLE
0x32, 0x41, //REG_CLOCK_MANUAL
0x24, 0x40, //REG_CRYSTAL_ADJ
0x06, 0x0B, //REG_SERDES_CTL
0x10, 0xFF, //REG_TX_VALID
0x04, 0x06, //REG_DATA_RATE - 64kbps, CODELEN=32, DATAMODE=DDR
0x19, 0x03, //REG_THRESHOLD_L - TH32=3
0x1A, 0x1D, //REG_THRESHOLD_H - TH32=3
0x11, 0xDC, //REG_PN_CODE, A overwrite default w/ PN Code Index 1 (64kbps table)
0x12, 0xC0, //REG_PN_CODE, A
0x13, 0x6B, //REG_PN_CODE, A
0x14, 0xB8, //REG_PN_CODE, A
0x15, 0x2B, //REG_PN_CODE, B
0x16, 0x09, //REG_PN_CODE, B
0x17, 0xBB, //REG_PN_CODE, B
0x18, 0xB2, //REG_PN_CODE, B
0x23, 0x05, //REG_PA - PA=5
0x21, 0x02 //REG_CHANNEL = 2402MHz
};
// RadioPnCode table
const BYTE code RadioPnCodeTable[] =
{
0x6A, 0xE7, 0x01, 0xEA, 0x03, 0xFD, 0x13, 0xD2, //PN Code 0
0xDC, 0xC0, 0x6B, 0xB8, 0x2B, 0x09, 0xBB, 0xB2, //PN Code 1
0xA3, 0x1E, 0xF2, 0xA4, 0x31, 0x32, 0x7A, 0xB3, //PN Code 2
0x44, 0x83, 0x3B, 0xDD, 0x14, 0xCF, 0x8E, 0xC9, //PN Code 3
0x35, 0x35, 0x4E, 0xC5, 0xF3, 0x52, 0x47, 0xB0, //PN Code 4
0x7C, 0x23, 0x8A, 0xCE, 0x45, 0x5C, 0x54, 0xD7, //PN Code 5
0x81, 0xAC, 0xFB, 0x83, 0x7A, 0x9A, 0x61, 0xAC, //PN Code 6
0x3C, 0x12, 0x5F, 0x9C, 0x39, 0x98, 0xF6, 0x8A //PN Code 7
};
BYTE radio_mid[] = {0,0,0,0};
// 16-bytes - data, data, data, data...
BYTE radio_txbuf[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
// 48-bytes - data, valid, rssi, data, valid, rssi...
BYTE radio_rxbuf[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
BYTE radio_rssi = 0;
BYTE radio_status[] = {0,0,0,0,0,0};
// 0 - REG_TX_INT_STAT
// 1 - SPARE
// 2 - REG_RX_INT_STAT
// 3 - REG_RX_DATA_A
// 4 - REG_RX_VALID_A
// 5 - REG_RSSI
// prototypes for radio snippets
void DelayMicroSec(WORD microsec);
void RadioReset(void);
void RadioInit(void);
void RadioSetPnCode(BYTE index);
void RadioGetMid(void);
BYTE RadioTransmit(BYTE len, BYTE *txbuf);
BYTE RadioReceive(BYTE *rxbuf);
void RadioSleep(void);
void RadioWake(void);
BYTE RadioGetRssi(void);
void DelayMicroSec(WORD microsec)
{
WORD i;
for(i=0;i<microsec;i++) {
// toggle SCK (w/o asserting nSS) to measure DelayMicroSec() w/scope
SCK_HI;
SCK_LO;
}
}
void RadioReset(void)
{
nRST_LO; nPD_LO; nSS_HI; SCK_LO;
DelayMicroSec(tPWR_RST); //1300usec min.
nPD_HI;
DelayMicroSec(tPDN_X13); //2000usec typ.
nRST_HI;
DelayMicroSec(tSPI_RDY); //1usec min.
nPD_HI;
DelayMicroSec(CRYSTAL_STARTUP); // ~Xmsec for crystal start to stable - idle
}
void RadioInit(void)
{
BYTE i;
for(i=0;i<sizeof(RadioInitTable);i+=2) {
SpiWrite(RadioInitTable[i],RadioInitTable[i+1]);
}
}
void RadioSetPnCode(BYTE index)
{
SpiFileWrite((SPI_INC | 0x11), 8, (&RadioPnCodeTable[0] + (8*index))); //REG_PN_CODE
}
void RadioGetMid(void)
{
SpiWrite((SPI_FRZ | 0x20), 0x64); //REG_ANALOG_CTL - enable reads from MID
SpiFileRead((SPI_INC | 0x3C), 4, &radio_mid[0]); //REG_MID - loaded into radio_mid[]
SpiWrite((SPI_FRZ | 0x20), 0x44); //REG_ANALOG_CTL - disable reads from MID
}
BYTE RadioTransmit(BYTE len, BYTE *txbuf)
{
BYTE i;
radio_status[0] = SpiRead((SPI_FRZ | 0x0E)); //REG_TX_INT_STAT - clear transmit status
SpiWrite((SPI_FRZ | 0x0D), 0x01); //REG_TX_INT_EN - enable empty flag on IRQ pin
SpiWrite((SPI_FRZ | 0x03), 0x50); //REG_CONTROL - enable tx
DelayMicroSec(SYNTH_SETTLE); // wait for synth to settle
DelayMicroSec(PREAMBLE); // delay in loading txbuf to send extra preamble symbol
for(i=0;i<len;i++) {
SpiWrite((SPI_FRZ | 0x0F), txbuf[i]); //REG_TX_DATA - send data
while(!IRQ); // wait 'til REG_TX_DATA empty
}
SpiWrite((SPI_FRZ | 0x0D), 0x02); //REG_TX_INT_EN - enable done flag on IRQ pin
while(!IRQ); // wait 'til REG_TX_DATA done
SpiWrite((SPI_FRZ | 0x03), 0x00); //REG_CONTROL - return to idle
radio_status[0] = SpiRead((SPI_FRZ | 0x0E)); //REG_TX_INT_STAT - clear transmit status
return(radio_status[0]);
}
BYTE RadioReceive(BYTE *rxbuf)
{
BYTE len;
BYTE i;
radio_status[2] = SpiRead((SPI_FRZ | 0x08)); //REG_RX_INT_STAT - clear receive status
SpiWrite((SPI_FRZ | 0x07), 0x03); //REG_RX_INT_EN - enable EOFA and FULLA flags on IRQ pin
SpiWrite((SPI_FRZ | 0x03), 0x90); //REG_CONTROL - enable rx
DelayMicroSec(SYNTH_SETTLE); // wait for synth to settle
DelayMicroSec(RECEIVER_READY); // wait for receiver afe ready
i = 0;
while(1)
{
while(!IRQ); // wait 'til either EOFA or FULLA receive flag fires
radio_status[2] = SpiRead((SPI_FRZ | 0x08)); //REG_RX_INT_STAT - check receive status
if(radio_status[2]&0x01)
{ //store REG_RX_DATA_A and REG_RX_VALID_A in user's rxbuf
SpiFileRead((SPI_INC | 0x09), 2, &rxbuf[i]);
if(rxbuf[i+1] > 3)
{
i += 2;
rxbuf[i] = SpiRead((SPI_FRZ | 0x22)); // store REG_RSSI in user's rxbuf
i++; // ~75usec of "idle" time between bytes when using 64kbps
}
}
if(radio_status[2]&0x02 && i) break;
}
SpiWrite((SPI_FRZ | 0x03), 0x00); //REG_CONTROL - return to idle
len = i;
return(len);
}
void RadioSleep(void)
{
SpiWrite((SPI_FRZ | 0x03), 0x00); //REG_CONTROL - force idle
nPD_LO; // force sleep
DelayMicroSec(tPD); //10usec
// typically takes ~50usec from the time nPD is asserted to low power mode
}
void RadioWake(void)
{
nPD_HI; // force idle
DelayMicroSec(CRYSTAL_STARTUP); // ~Xmsec for crystal start to stable - idle
}
BYTE RadioGetRssi(void)
{
SpiWrite((SPI_FRZ | 0x2F), 0x80); //REG_CARRIER_DETECT - force radio to manually acquire rssi reading
SpiWrite((SPI_FRZ | 0x03), 0x90); //REG_CONTROL - put radio in receive mode - triggers rssi adc
DelayMicroSec(SYNTH_SETTLE); // wait for synth to settle
DelayMicroSec(RECEIVER_READY); // wait for receiver ready
DelayMicroSec(RSSI_ADC_CONVERSION); // wait for 5-bit rssi adc to complete
radio_status[5] = SpiRead((SPI_FRZ | 0x22)); //REG_RSSI - flush stale rssi reading
DelayMicroSec(RSSI_ADC_CONVERSION); // wait for 5-bit rssi adc to complete
radio_status[5] = SpiRead((SPI_FRZ | 0x22)); //REG_RSSI - get rssi reading
SpiWrite((SPI_FRZ | 0x2F), 0x00); //REG_CARRIER_DETECT - manually clear CDET
SpiWrite((SPI_FRZ | 0x03), 0x00); //REG_CONTROL - put radio in idle mode
return(radio_status[5]);
}