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@2:ee9416954280, 2013-07-08 (annotated)
- Committer:
- persoder
- Date:
- Mon Jul 08 21:09:26 2013 +0000
- Revision:
- 2:ee9416954280
- Parent:
- 1:d40d911b763a
Time for address bits added.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| persoder | 1:d40d911b763a | 1 | /** \file |
| persoder | 1:d40d911b763a | 2 | * \brief |
| persoder | 1:d40d911b763a | 3 | * |
| persoder | 1:d40d911b763a | 4 | * \author Per Söderstam © 2011 |
| persoder | 1:d40d911b763a | 5 | */ |
| persoder | 1:d40d911b763a | 6 | |
| persoder | 1:d40d911b763a | 7 | #include "nRF2401A.h" |
| persoder | 1:d40d911b763a | 8 | |
| persoder | 1:d40d911b763a | 9 | const int Ts = 1; /**< Setup time from data to rising clock edge on write (accualy 500 ns). */ |
| persoder | 1:d40d911b763a | 10 | const int Th = 1; /**< Hold time from rising clock to data toggle/falling clock (accualy 500 ns). */ |
| persoder | 1:d40d911b763a | 11 | const int Tcs2data = 5; /**< Min delay from CS assert to data, in us. */ |
| persoder | 1:d40d911b763a | 12 | const int Tce2data = 5; /**< Min delay from CE assert to data, in us. */ |
| persoder | 1:d40d911b763a | 13 | const int Td = 1; /**< Minimum delay between edges (actually 50 ns). */ |
| persoder | 1:d40d911b763a | 14 | const int Tpd2cfgm = 3; /**< Minimum delay from power up of tranciever to configuration. */ |
| persoder | 1:d40d911b763a | 15 | const int Tsby2txSB = 195; /**< Minimum delay from tx initation to air, in us. */ |
| persoder | 1:d40d911b763a | 16 | const int Thmin = 5; /**< */ |
| persoder | 1:d40d911b763a | 17 | const int Tclk2data = 1; /**< */ |
| persoder | 1:d40d911b763a | 18 | |
| persoder | 1:d40d911b763a | 19 | nRF2401A::nRF2401A(PinName ce, |
| persoder | 1:d40d911b763a | 20 | PinName cs, |
| persoder | 1:d40d911b763a | 21 | PinName dr1, |
| persoder | 1:d40d911b763a | 22 | PinName clk1, |
| persoder | 1:d40d911b763a | 23 | PinName data) |
| persoder | 1:d40d911b763a | 24 | : _ce(DigitalOut(ce)), |
| persoder | 1:d40d911b763a | 25 | _cs(DigitalOut(cs)), |
| persoder | 1:d40d911b763a | 26 | _dr1(DigitalIn(dr1)), |
| persoder | 1:d40d911b763a | 27 | _clk1(DigitalOut(clk1)), |
| persoder | 1:d40d911b763a | 28 | _data(DigitalInOut(data)), |
| persoder | 1:d40d911b763a | 29 | _state(nRF2401A::UNDEF), |
| persoder | 1:d40d911b763a | 30 | _rx_handler((nRF2401A_rx_handler_t) 0), |
| persoder | 1:d40d911b763a | 31 | _rx_handler_arg((void *) 0), |
| persoder | 1:d40d911b763a | 32 | _dr1_isr(InterruptIn(dr1)) { |
| persoder | 1:d40d911b763a | 33 | |
| persoder | 1:d40d911b763a | 34 | // init member variables |
| persoder | 1:d40d911b763a | 35 | _data.output(); |
| persoder | 1:d40d911b763a | 36 | // setup... |
| persoder | 1:d40d911b763a | 37 | _ctrl_packet = (uint8_t *) &_ctrl_packet_buf; |
| persoder | 1:d40d911b763a | 38 | _dr1_isr.rise(this, &nRF2401A::dataReadyHandler); |
| persoder | 1:d40d911b763a | 39 | // ...tranciever in standby... |
| persoder | 1:d40d911b763a | 40 | _ce = 0; |
| persoder | 1:d40d911b763a | 41 | _cs = 0; |
| persoder | 1:d40d911b763a | 42 | // ...and clear receive buffer |
| persoder | 1:d40d911b763a | 43 | for (int i = 0; i < 16; i++) |
| persoder | 1:d40d911b763a | 44 | _data_buf[i] = 0x0; |
| persoder | 1:d40d911b763a | 45 | // ...set imutable control fields... |
| persoder | 1:d40d911b763a | 46 | _ctrl_packet_buf.enable_dual_channel_mode = 0x0; // single channel receive |
| persoder | 1:d40d911b763a | 47 | _ctrl_packet_buf.communication_mode = 0x1; // ShockBurst mode |
| persoder | 1:d40d911b763a | 48 | _ctrl_packet_buf.xo_frequency = 0x3; // 16 MHz crystal |
| persoder | 1:d40d911b763a | 49 | _ctrl_packet_buf.rf_power = 0x3; // 0 dBm (1 mW) output power |
| persoder | 1:d40d911b763a | 50 | // ...start in RX mode |
| persoder | 1:d40d911b763a | 51 | _ctrl_packet_buf.txr_switch = nRF2401A::RX_MODE; |
| persoder | 1:d40d911b763a | 52 | // assure minimum wake up time while assuming tranciever powers up with uP |
| persoder | 1:d40d911b763a | 53 | wait_ms(Tpd2cfgm); |
| persoder | 1:d40d911b763a | 54 | |
| persoder | 1:d40d911b763a | 55 | return; |
| persoder | 1:d40d911b763a | 56 | } |
| persoder | 1:d40d911b763a | 57 | |
| persoder | 1:d40d911b763a | 58 | void nRF2401A::printControlPacket(Serial& port) |
| persoder | 1:d40d911b763a | 59 | { |
| persoder | 1:d40d911b763a | 60 | for(int i = 0; i < sizeof(_ctrl_packet_buf); i++) |
| persoder | 1:d40d911b763a | 61 | port.printf("%02x ", _ctrl_packet[i]); |
| persoder | 1:d40d911b763a | 62 | port.printf("\n\r"); |
| persoder | 1:d40d911b763a | 63 | return; |
| persoder | 1:d40d911b763a | 64 | } |
| persoder | 1:d40d911b763a | 65 | |
| persoder | 1:d40d911b763a | 66 | void nRF2401A::printDataPacket(Serial& port) |
| persoder | 1:d40d911b763a | 67 | { |
| persoder | 1:d40d911b763a | 68 | for(int i = 0; i < sizeof(_data_buf); i++) |
| persoder | 1:d40d911b763a | 69 | port.printf("%02x ", _data_buf[i]); |
| persoder | 1:d40d911b763a | 70 | port.printf("\r"); |
| persoder | 1:d40d911b763a | 71 | return; |
| persoder | 1:d40d911b763a | 72 | } |
| persoder | 1:d40d911b763a | 73 | |
| persoder | 1:d40d911b763a | 74 | nRF2401A& nRF2401A::attachRXHandler(nRF2401A_rx_handler_t handler, void *arg) { |
| persoder | 1:d40d911b763a | 75 | |
| persoder | 1:d40d911b763a | 76 | _rx_handler = handler; |
| persoder | 1:d40d911b763a | 77 | _rx_handler_arg = arg; |
| persoder | 1:d40d911b763a | 78 | |
| persoder | 1:d40d911b763a | 79 | return *this; |
| persoder | 1:d40d911b763a | 80 | } |
| persoder | 1:d40d911b763a | 81 | |
| persoder | 1:d40d911b763a | 82 | nRF2401A& nRF2401A::sendMsg(nRF2401A::address_t addr, uint8_t addr_len, uint8_t *msg_buf, uint8_t msg_len) { |
| persoder | 1:d40d911b763a | 83 | |
| persoder | 1:d40d911b763a | 84 | // point to start of address byte in address |
| persoder | 1:d40d911b763a | 85 | uint8_t *aligned_addr = &addr[sizeof(address_t) - (addr_len / 8)]; |
| persoder | 1:d40d911b763a | 86 | // wait for tx completion |
| persoder | 1:d40d911b763a | 87 | int Toa = (_ctrl_packet_buf.rf_data_rate == nRF2401A::BIT_RATE_1MBITS ? 1 : 4) * (addr_len + msg_len + 1 + 16); |
| persoder | 1:d40d911b763a | 88 | |
| persoder | 1:d40d911b763a | 89 | switch (_state) { |
| persoder | 1:d40d911b763a | 90 | case nRF2401A::RX: |
| persoder | 1:d40d911b763a | 91 | // switch to transmit |
| persoder | 1:d40d911b763a | 92 | _ce = 0; |
| persoder | 1:d40d911b763a | 93 | _cs = 0; |
| persoder | 1:d40d911b763a | 94 | wait_us(Td); |
| persoder | 1:d40d911b763a | 95 | // assert CS/CE and wait Tcs2data |
| persoder | 1:d40d911b763a | 96 | _ce = 0; |
| persoder | 1:d40d911b763a | 97 | _cs = 1; |
| persoder | 1:d40d911b763a | 98 | wait_us(Tcs2data); |
| persoder | 1:d40d911b763a | 99 | // push out the bits |
| persoder | 1:d40d911b763a | 100 | _data = nRF2401A::TX_MODE; |
| persoder | 1:d40d911b763a | 101 | wait_us(Ts); |
| persoder | 1:d40d911b763a | 102 | _clk1 = 1; |
| persoder | 1:d40d911b763a | 103 | wait_us(Th); |
| persoder | 1:d40d911b763a | 104 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 105 | // wait Td |
| persoder | 1:d40d911b763a | 106 | wait_us(Td); |
| persoder | 1:d40d911b763a | 107 | // deassert CS/CE and done... |
| persoder | 1:d40d911b763a | 108 | _cs = 0; |
| persoder | 1:d40d911b763a | 109 | _ce = 0; |
| persoder | 1:d40d911b763a | 110 | |
| persoder | 1:d40d911b763a | 111 | // zero control and data lines |
| persoder | 1:d40d911b763a | 112 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 113 | _data = 0; |
| persoder | 1:d40d911b763a | 114 | // wait Td |
| persoder | 1:d40d911b763a | 115 | wait_us(Td); |
| persoder | 1:d40d911b763a | 116 | // assert CE and wait Tcs2data |
| persoder | 1:d40d911b763a | 117 | _ce = 1; |
| persoder | 1:d40d911b763a | 118 | wait_us(Tce2data); |
| persoder | 1:d40d911b763a | 119 | // push out the address bits |
| persoder | 1:d40d911b763a | 120 | for (int i = 0; i < addr_len; i++) { |
| persoder | 1:d40d911b763a | 121 | _data = ((0x80 >> (i % 8)) & aligned_addr[i / 8]) ? 0x1 : 0x0; |
| persoder | 1:d40d911b763a | 122 | wait_us(Ts); |
| persoder | 1:d40d911b763a | 123 | _clk1 = 1; |
| persoder | 1:d40d911b763a | 124 | wait_us(Th); |
| persoder | 1:d40d911b763a | 125 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 126 | } |
| persoder | 1:d40d911b763a | 127 | // push out the message bits |
| persoder | 1:d40d911b763a | 128 | for (int i = 0; i < msg_len; i++) { |
| persoder | 1:d40d911b763a | 129 | _data = ((0x80 >> (i % 8)) & msg_buf[i / 8]) ? 0x1 : 0x0; |
| persoder | 1:d40d911b763a | 130 | wait_us(Ts); |
| persoder | 1:d40d911b763a | 131 | _clk1 = 1; |
| persoder | 1:d40d911b763a | 132 | wait_us(Th); |
| persoder | 1:d40d911b763a | 133 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 134 | } |
| persoder | 1:d40d911b763a | 135 | // reset data |
| persoder | 1:d40d911b763a | 136 | _data = 0; |
| persoder | 1:d40d911b763a | 137 | // deassert CE will initiate transmission |
| persoder | 1:d40d911b763a | 138 | _ce = 0; |
| persoder | 1:d40d911b763a | 139 | wait_us(Tsby2txSB + Toa); |
| persoder | 1:d40d911b763a | 140 | |
| persoder | 1:d40d911b763a | 141 | // switch back to receive |
| persoder | 1:d40d911b763a | 142 | wait_us(Td); |
| persoder | 1:d40d911b763a | 143 | // assert CS/CE and wait Tcs2data |
| persoder | 1:d40d911b763a | 144 | _cs = 1; |
| persoder | 1:d40d911b763a | 145 | wait_us(Tcs2data); |
| persoder | 1:d40d911b763a | 146 | // push out the bits |
| persoder | 1:d40d911b763a | 147 | _data = nRF2401A::RX_MODE; |
| persoder | 1:d40d911b763a | 148 | wait_us(Ts); |
| persoder | 1:d40d911b763a | 149 | _clk1 = 1; |
| persoder | 1:d40d911b763a | 150 | wait_us(Th); |
| persoder | 1:d40d911b763a | 151 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 152 | // wait Td |
| persoder | 1:d40d911b763a | 153 | wait_us(Td); |
| persoder | 1:d40d911b763a | 154 | _data = 0; |
| persoder | 1:d40d911b763a | 155 | // deassert CS/CE and done... |
| persoder | 1:d40d911b763a | 156 | _cs = 0; |
| persoder | 1:d40d911b763a | 157 | // wait Td to avoid simultaineous control high |
| persoder | 1:d40d911b763a | 158 | wait_us(Td); |
| persoder | 1:d40d911b763a | 159 | _ce = 1; |
| persoder | 1:d40d911b763a | 160 | // done |
| persoder | 1:d40d911b763a | 161 | break; |
| persoder | 1:d40d911b763a | 162 | case nRF2401A::STANDBY: |
| persoder | 1:d40d911b763a | 163 | case nRF2401A::TX: |
| persoder | 1:d40d911b763a | 164 | case nRF2401A::UNDEF: |
| persoder | 1:d40d911b763a | 165 | default: |
| persoder | 1:d40d911b763a | 166 | // can only send in RX mode |
| persoder | 1:d40d911b763a | 167 | break; |
| persoder | 1:d40d911b763a | 168 | } |
| persoder | 1:d40d911b763a | 169 | |
| persoder | 1:d40d911b763a | 170 | return *this; |
| persoder | 1:d40d911b763a | 171 | } |
| persoder | 1:d40d911b763a | 172 | |
| persoder | 1:d40d911b763a | 173 | void nRF2401A::pushCtrl(uint8_t *buf, uint8_t n_bits, bool is_ctrl) { |
| persoder | 1:d40d911b763a | 174 | |
| persoder | 1:d40d911b763a | 175 | DigitalOut &ctrl_pin = is_ctrl ? _cs : _ce; |
| persoder | 1:d40d911b763a | 176 | |
| persoder | 1:d40d911b763a | 177 | // set data to output |
| persoder | 1:d40d911b763a | 178 | _data.output(); |
| persoder | 1:d40d911b763a | 179 | // zero control and data lines |
| persoder | 1:d40d911b763a | 180 | _cs = 0; |
| persoder | 1:d40d911b763a | 181 | _ce = 0; |
| persoder | 1:d40d911b763a | 182 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 183 | _data = 0; |
| persoder | 1:d40d911b763a | 184 | // wait Td |
| persoder | 1:d40d911b763a | 185 | wait_us(Td); |
| persoder | 1:d40d911b763a | 186 | // assert CS/CE and wait Tcs2data |
| persoder | 1:d40d911b763a | 187 | ctrl_pin = 1; |
| persoder | 1:d40d911b763a | 188 | wait_us(Tcs2data); |
| persoder | 1:d40d911b763a | 189 | // push out the bits |
| persoder | 1:d40d911b763a | 190 | for (int i = 0; i < n_bits; i++) { |
| persoder | 1:d40d911b763a | 191 | _data = ((0x80 >> (i % 8)) & buf[i / 8]) ? 0x1 : 0x0; |
| persoder | 1:d40d911b763a | 192 | wait_us(Ts); |
| persoder | 1:d40d911b763a | 193 | _clk1 = 1; |
| persoder | 1:d40d911b763a | 194 | wait_us(Th); |
| persoder | 1:d40d911b763a | 195 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 196 | } |
| persoder | 1:d40d911b763a | 197 | _data = 0; |
| persoder | 1:d40d911b763a | 198 | // wait Td |
| persoder | 1:d40d911b763a | 199 | wait_us(Td); |
| persoder | 1:d40d911b763a | 200 | // deassert CS/CE and done... |
| persoder | 1:d40d911b763a | 201 | ctrl_pin = 0; |
| persoder | 1:d40d911b763a | 202 | |
| persoder | 1:d40d911b763a | 203 | return; |
| persoder | 1:d40d911b763a | 204 | } |
| persoder | 1:d40d911b763a | 205 | |
| persoder | 1:d40d911b763a | 206 | int nRF2401A::pull(uint8_t *buf) { |
| persoder | 1:d40d911b763a | 207 | int n = 0; |
| persoder | 1:d40d911b763a | 208 | |
| persoder | 1:d40d911b763a | 209 | // read from data pin |
| persoder | 1:d40d911b763a | 210 | _data.input(); |
| persoder | 1:d40d911b763a | 211 | // init signals, go to standby |
| persoder | 1:d40d911b763a | 212 | _ce = 1; |
| persoder | 1:d40d911b763a | 213 | _cs = 0; |
| persoder | 1:d40d911b763a | 214 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 215 | // ensure time from DR |
| persoder | 1:d40d911b763a | 216 | wait_us(Td); |
| persoder | 1:d40d911b763a | 217 | |
| persoder | 1:d40d911b763a | 218 | while (_dr1 == 1) { |
| persoder | 1:d40d911b763a | 219 | _clk1 = 1; |
| persoder | 1:d40d911b763a | 220 | wait_us(Thmin); |
| persoder | 1:d40d911b763a | 221 | if(_data.read()) |
| persoder | 1:d40d911b763a | 222 | buf[n / 8] |= (0x80 >> (n % 8)); |
| persoder | 1:d40d911b763a | 223 | else |
| persoder | 1:d40d911b763a | 224 | buf[n / 8] &= ~(0x80 >> (n % 8)); |
| persoder | 1:d40d911b763a | 225 | n++; |
| persoder | 1:d40d911b763a | 226 | _clk1 = 0; |
| persoder | 1:d40d911b763a | 227 | wait_us(Thmin); |
| persoder | 1:d40d911b763a | 228 | } |
| persoder | 1:d40d911b763a | 229 | // return to active |
| persoder | 1:d40d911b763a | 230 | _ce = 1; |
| persoder | 1:d40d911b763a | 231 | // reset data pin direction |
| persoder | 1:d40d911b763a | 232 | _data.output(); |
| persoder | 1:d40d911b763a | 233 | |
| persoder | 1:d40d911b763a | 234 | return n; |
| persoder | 1:d40d911b763a | 235 | } |
| persoder | 1:d40d911b763a | 236 | |
| persoder | 1:d40d911b763a | 237 | void nRF2401A::activate(bool active) { |
| persoder | 1:d40d911b763a | 238 | switch (_state) { |
| persoder | 1:d40d911b763a | 239 | case nRF2401A::RX: |
| persoder | 1:d40d911b763a | 240 | if (!active) { |
| persoder | 1:d40d911b763a | 241 | _state = nRF2401A::STANDBY; |
| persoder | 1:d40d911b763a | 242 | _ce = 0; |
| persoder | 1:d40d911b763a | 243 | _cs = 0; |
| persoder | 1:d40d911b763a | 244 | } |
| persoder | 1:d40d911b763a | 245 | break; |
| persoder | 1:d40d911b763a | 246 | case nRF2401A::STANDBY: |
| persoder | 1:d40d911b763a | 247 | if (active) { |
| persoder | 1:d40d911b763a | 248 | _state = nRF2401A::RX; |
| persoder | 1:d40d911b763a | 249 | _ce = 1; |
| persoder | 1:d40d911b763a | 250 | _cs = 0; |
| persoder | 1:d40d911b763a | 251 | } |
| persoder | 1:d40d911b763a | 252 | break; |
| persoder | 1:d40d911b763a | 253 | case nRF2401A::TX: |
| persoder | 1:d40d911b763a | 254 | case nRF2401A::UNDEF: |
| persoder | 1:d40d911b763a | 255 | default: |
| persoder | 1:d40d911b763a | 256 | break; |
| persoder | 1:d40d911b763a | 257 | } |
| persoder | 1:d40d911b763a | 258 | |
| persoder | 1:d40d911b763a | 259 | return; |
| persoder | 1:d40d911b763a | 260 | } |
| persoder | 1:d40d911b763a | 261 | |
| persoder | 1:d40d911b763a | 262 | void nRF2401A::dataReadyHandler(void) { |
| persoder | 1:d40d911b763a | 263 | switch (_state) { |
| persoder | 1:d40d911b763a | 264 | case nRF2401A::RX: |
| persoder | 1:d40d911b763a | 265 | pull(_data_buf); |
| persoder | 1:d40d911b763a | 266 | if (_rx_handler != (nRF2401A_rx_handler_t) 0) |
| persoder | 1:d40d911b763a | 267 | _rx_handler(_rx_handler_arg); |
| persoder | 1:d40d911b763a | 268 | break; |
| persoder | 1:d40d911b763a | 269 | default: |
| persoder | 1:d40d911b763a | 270 | // todo: error msg |
| persoder | 1:d40d911b763a | 271 | break; |
| persoder | 1:d40d911b763a | 272 | } |
| persoder | 1:d40d911b763a | 273 | return; |
| persoder | 1:d40d911b763a | 274 | } |
| persoder | 1:d40d911b763a | 275 | |
| persoder | 1:d40d911b763a | 276 | nRF2401A& nRF2401A::flushControlPacket() { |
| persoder | 1:d40d911b763a | 277 | switch (_state) { |
| persoder | 1:d40d911b763a | 278 | case nRF2401A::UNDEF: |
| persoder | 1:d40d911b763a | 279 | case nRF2401A::RX: |
| persoder | 1:d40d911b763a | 280 | pushCtrl(_ctrl_packet, 15 << 3 ); |
| persoder | 1:d40d911b763a | 281 | _state = nRF2401A::RX; |
| persoder | 1:d40d911b763a | 282 | _ce = 1; |
| persoder | 1:d40d911b763a | 283 | _cs = 0; |
| persoder | 1:d40d911b763a | 284 | break; |
| persoder | 1:d40d911b763a | 285 | case nRF2401A::STANDBY: |
| persoder | 1:d40d911b763a | 286 | pushCtrl(_ctrl_packet, 15 << 3 ); |
| persoder | 1:d40d911b763a | 287 | _state = nRF2401A::STANDBY; |
| persoder | 1:d40d911b763a | 288 | _ce = 0; |
| persoder | 1:d40d911b763a | 289 | _cs = 0; |
| persoder | 1:d40d911b763a | 290 | break; |
| persoder | 1:d40d911b763a | 291 | case nRF2401A::TX: |
| persoder | 1:d40d911b763a | 292 | default: |
| persoder | 1:d40d911b763a | 293 | _ce = 0; |
| persoder | 1:d40d911b763a | 294 | _cs = 0; |
| persoder | 1:d40d911b763a | 295 | } |
| persoder | 1:d40d911b763a | 296 | |
| persoder | 1:d40d911b763a | 297 | return *this; |
| persoder | 1:d40d911b763a | 298 | } |