SparkFun Forums 

Where electronics enthusiasts find answers.

All things pertaining to wireless and RF links
By bill951
#4121
John at J&S wrote:Has anyone played with the Cypress wireless part?
I have worked with both the Cypress wireless USB (which is not really
USB) and the nRF2401. In my opinion the nRF2401 is much easier to
use. There is much more to program with the Cypress and my luck
with range was not as good. Maximum data rate is not as good either.
With Cypress you have to do more in software. For example, the
nRF2401 will automatically error check using 8-bit or 16-bit CRC.
You have to do that in software with Cypress. I did not do a side
by side range comparison and it might not mean much anyway
unless you try different "gold" codes in the Cypress. I suspect
range is comparable at the same power level if everything is optimized.
The Cypress was just a lot more trouble to get going and the software
was much more involved. On top of the more complex programming
there were data sheet errors which made things worse. If you try
the Cypress, go with an evaluation kit so you have their reference
software to look at since it avoids some pitfalls due to data sheet
errors. I haven't looked lately to see if the data sheets are fixed.
Atmel is a second source for Cypress with their own part number
and their data sheets were correct.
By John at J&S
#4125
Bill: Thanks for the info.

The Cypress development kit is $750. I looked at the data sheet for the module, and it has ten I/O lines, and none of them says "Data In". Argh.

I want to capture about 500msec of data from a three axis accelerometer. I need to sample about once per msec., so 3 channels x 8 bits x 1000 samples is 24kbps, not counting overhead?

Range is just a few feet. I'm using a cable right now, but it's a little awkward.

Wow, I just checked the Nordic site, and they have a part with the radio and an MCU:
http://www.nvlsi.no/index.cfm?obj=produ ... lay&pro=79
By bill951
#4134
John at J&S wrote:
I want to capture about 500msec of data from a three axis accelerometer. I need to sample about once per msec., so 3 channels x 8 bits x 1000 samples is 24kbps, not counting overhead?

Wow, I just checked the Nordic site, and they have a part with the radio and an MCU:
http://www.nvlsi.no/index.cfm?obj=produ ... lay&pro=79
The only problem with the Nordic chip which has an 8051 MCU is that
you still need an external serial EEPROM to load the program into the
MCU so it takes two chips. I prefer to use the nRF2401 and my choice
of MCU which has on-board flash program memory. This is still a
two-chip solution and I use my favorite MCU.

I have used the nRF2401 to transmit accelerometer data through
G forces up to 2000G with no problems.
By John at J&S
#4136
Freescale (Motorola) has a small MC9S12C part. The 48 pin version is 7 mm square.

I don't know C. The only programming I've done is HC11 assembly, so it shouldn't be much trouble learning the HC12.
By John at J&S
#4158
Bill: Do you think I could get away with just a transmitter at the sensor end? Any reason for the sensor to hear from the base station?

Nordic took the 2401 transmitter section and made it the 2402. 16 pins, 4 x 4 mm. Symmetry has it for $2.60.
By bill951
#4191
John at J&S wrote:Bill: Do you think I could get away with just a transmitter at the sensor end? Any reason for the sensor to hear from the base station?

Nordic took the 2401 transmitter section and made it the 2402. 16 pins, 4 x 4 mm. Symmetry has it for $2.60.
That's really your call. I always use the transceiver just in case I
need communication the other way - for example to wake up
instrumentation from a lower-power sleep mode (CPU turns on the
receiver ever so often and looks for a packet to see if it needs
to wake up). You also might want to set some parameters like
sample rate remotely. Having said that, often I never use the
reverse direction and a transmitter would be fine.
By John at J&S
#4296
Did you make a software flow chart that I can use? Do C programmers even use flowcharts?

I would like to write my MCU code in assembler, since I don't know C.
By bill951
#4376
John at J&S wrote:Did you make a software flow chart that I can use? Do C programmers even use flowcharts?

I would like to write my MCU code in assembler, since I don't know C.
I used the flow charts in the nRF2401 data sheet for shockburst
transmission and reception. You also need to load configuration
data after power-up. Make sure you use at least 16-bit-long
addresses.
By -t
#36179
Cypress CYWM6935 is a budget-limited ($9.75/ea. via www.digikey.com), 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]);
}

Fixed bug in RadioGetRssi() - the final SpiWrite should be writing 0x00 to register 0x03, not 0x90.