Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
nRF2401A.cpp
- Committer:
- persoder
- Date:
- 2013-07-08
- Revision:
- 2:ee9416954280
- Parent:
- 1:d40d911b763a
File content as of revision 2:ee9416954280:
/** \file
* \brief
*
* \author Per Söderstam © 2011
*/
#include "nRF2401A.h"
const int Ts = 1; /**< Setup time from data to rising clock edge on write (accualy 500 ns). */
const int Th = 1; /**< Hold time from rising clock to data toggle/falling clock (accualy 500 ns). */
const int Tcs2data = 5; /**< Min delay from CS assert to data, in us. */
const int Tce2data = 5; /**< Min delay from CE assert to data, in us. */
const int Td = 1; /**< Minimum delay between edges (actually 50 ns). */
const int Tpd2cfgm = 3; /**< Minimum delay from power up of tranciever to configuration. */
const int Tsby2txSB = 195; /**< Minimum delay from tx initation to air, in us. */
const int Thmin = 5; /**< */
const int Tclk2data = 1; /**< */
nRF2401A::nRF2401A(PinName ce,
PinName cs,
PinName dr1,
PinName clk1,
PinName data)
: _ce(DigitalOut(ce)),
_cs(DigitalOut(cs)),
_dr1(DigitalIn(dr1)),
_clk1(DigitalOut(clk1)),
_data(DigitalInOut(data)),
_state(nRF2401A::UNDEF),
_rx_handler((nRF2401A_rx_handler_t) 0),
_rx_handler_arg((void *) 0),
_dr1_isr(InterruptIn(dr1)) {
// init member variables
_data.output();
// setup...
_ctrl_packet = (uint8_t *) &_ctrl_packet_buf;
_dr1_isr.rise(this, &nRF2401A::dataReadyHandler);
// ...tranciever in standby...
_ce = 0;
_cs = 0;
// ...and clear receive buffer
for (int i = 0; i < 16; i++)
_data_buf[i] = 0x0;
// ...set imutable control fields...
_ctrl_packet_buf.enable_dual_channel_mode = 0x0; // single channel receive
_ctrl_packet_buf.communication_mode = 0x1; // ShockBurst mode
_ctrl_packet_buf.xo_frequency = 0x3; // 16 MHz crystal
_ctrl_packet_buf.rf_power = 0x3; // 0 dBm (1 mW) output power
// ...start in RX mode
_ctrl_packet_buf.txr_switch = nRF2401A::RX_MODE;
// assure minimum wake up time while assuming tranciever powers up with uP
wait_ms(Tpd2cfgm);
return;
}
void nRF2401A::printControlPacket(Serial& port)
{
for(int i = 0; i < sizeof(_ctrl_packet_buf); i++)
port.printf("%02x ", _ctrl_packet[i]);
port.printf("\n\r");
return;
}
void nRF2401A::printDataPacket(Serial& port)
{
for(int i = 0; i < sizeof(_data_buf); i++)
port.printf("%02x ", _data_buf[i]);
port.printf("\r");
return;
}
nRF2401A& nRF2401A::attachRXHandler(nRF2401A_rx_handler_t handler, void *arg) {
_rx_handler = handler;
_rx_handler_arg = arg;
return *this;
}
nRF2401A& nRF2401A::sendMsg(nRF2401A::address_t addr, uint8_t addr_len, uint8_t *msg_buf, uint8_t msg_len) {
// point to start of address byte in address
uint8_t *aligned_addr = &addr[sizeof(address_t) - (addr_len / 8)];
// wait for tx completion
int Toa = (_ctrl_packet_buf.rf_data_rate == nRF2401A::BIT_RATE_1MBITS ? 1 : 4) * (addr_len + msg_len + 1 + 16);
switch (_state) {
case nRF2401A::RX:
// switch to transmit
_ce = 0;
_cs = 0;
wait_us(Td);
// assert CS/CE and wait Tcs2data
_ce = 0;
_cs = 1;
wait_us(Tcs2data);
// push out the bits
_data = nRF2401A::TX_MODE;
wait_us(Ts);
_clk1 = 1;
wait_us(Th);
_clk1 = 0;
// wait Td
wait_us(Td);
// deassert CS/CE and done...
_cs = 0;
_ce = 0;
// zero control and data lines
_clk1 = 0;
_data = 0;
// wait Td
wait_us(Td);
// assert CE and wait Tcs2data
_ce = 1;
wait_us(Tce2data);
// push out the address bits
for (int i = 0; i < addr_len; i++) {
_data = ((0x80 >> (i % 8)) & aligned_addr[i / 8]) ? 0x1 : 0x0;
wait_us(Ts);
_clk1 = 1;
wait_us(Th);
_clk1 = 0;
}
// push out the message bits
for (int i = 0; i < msg_len; i++) {
_data = ((0x80 >> (i % 8)) & msg_buf[i / 8]) ? 0x1 : 0x0;
wait_us(Ts);
_clk1 = 1;
wait_us(Th);
_clk1 = 0;
}
// reset data
_data = 0;
// deassert CE will initiate transmission
_ce = 0;
wait_us(Tsby2txSB + Toa);
// switch back to receive
wait_us(Td);
// assert CS/CE and wait Tcs2data
_cs = 1;
wait_us(Tcs2data);
// push out the bits
_data = nRF2401A::RX_MODE;
wait_us(Ts);
_clk1 = 1;
wait_us(Th);
_clk1 = 0;
// wait Td
wait_us(Td);
_data = 0;
// deassert CS/CE and done...
_cs = 0;
// wait Td to avoid simultaineous control high
wait_us(Td);
_ce = 1;
// done
break;
case nRF2401A::STANDBY:
case nRF2401A::TX:
case nRF2401A::UNDEF:
default:
// can only send in RX mode
break;
}
return *this;
}
void nRF2401A::pushCtrl(uint8_t *buf, uint8_t n_bits, bool is_ctrl) {
DigitalOut &ctrl_pin = is_ctrl ? _cs : _ce;
// set data to output
_data.output();
// zero control and data lines
_cs = 0;
_ce = 0;
_clk1 = 0;
_data = 0;
// wait Td
wait_us(Td);
// assert CS/CE and wait Tcs2data
ctrl_pin = 1;
wait_us(Tcs2data);
// push out the bits
for (int i = 0; i < n_bits; i++) {
_data = ((0x80 >> (i % 8)) & buf[i / 8]) ? 0x1 : 0x0;
wait_us(Ts);
_clk1 = 1;
wait_us(Th);
_clk1 = 0;
}
_data = 0;
// wait Td
wait_us(Td);
// deassert CS/CE and done...
ctrl_pin = 0;
return;
}
int nRF2401A::pull(uint8_t *buf) {
int n = 0;
// read from data pin
_data.input();
// init signals, go to standby
_ce = 1;
_cs = 0;
_clk1 = 0;
// ensure time from DR
wait_us(Td);
while (_dr1 == 1) {
_clk1 = 1;
wait_us(Thmin);
if(_data.read())
buf[n / 8] |= (0x80 >> (n % 8));
else
buf[n / 8] &= ~(0x80 >> (n % 8));
n++;
_clk1 = 0;
wait_us(Thmin);
}
// return to active
_ce = 1;
// reset data pin direction
_data.output();
return n;
}
void nRF2401A::activate(bool active) {
switch (_state) {
case nRF2401A::RX:
if (!active) {
_state = nRF2401A::STANDBY;
_ce = 0;
_cs = 0;
}
break;
case nRF2401A::STANDBY:
if (active) {
_state = nRF2401A::RX;
_ce = 1;
_cs = 0;
}
break;
case nRF2401A::TX:
case nRF2401A::UNDEF:
default:
break;
}
return;
}
void nRF2401A::dataReadyHandler(void) {
switch (_state) {
case nRF2401A::RX:
pull(_data_buf);
if (_rx_handler != (nRF2401A_rx_handler_t) 0)
_rx_handler(_rx_handler_arg);
break;
default:
// todo: error msg
break;
}
return;
}
nRF2401A& nRF2401A::flushControlPacket() {
switch (_state) {
case nRF2401A::UNDEF:
case nRF2401A::RX:
pushCtrl(_ctrl_packet, 15 << 3 );
_state = nRF2401A::RX;
_ce = 1;
_cs = 0;
break;
case nRF2401A::STANDBY:
pushCtrl(_ctrl_packet, 15 << 3 );
_state = nRF2401A::STANDBY;
_ce = 0;
_cs = 0;
break;
case nRF2401A::TX:
default:
_ce = 0;
_cs = 0;
}
return *this;
}