-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnrf24l01.c
671 lines (601 loc) · 24 KB
/
nrf24l01.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
#include "project-defs.h"
/*global variables related to this file*/
volatile bool dataReady = 0;
static GpioConfig CSN_pin = GPIO_PIN_CONFIG(NRF24_CSN_PORT, NRF24_CSN_PIN, GPIO_BIDIRECTIONAL_MODE);
static GpioConfig CE_pin = GPIO_PIN_CONFIG(NRF24_CE_PORT, NRF24_CE_PIN, GPIO_BIDIRECTIONAL_MODE);
static uint8_t str_to_send[STATIC_PAYLOAD_WIDTH_DEFAULT]; // the array that will be padded if need be to be sent
static uint8_t SPI_command; /*1 byte spi command*/
static uint8_t register_current_value; /*in order to change some bits of internal registers or to check their content*/
static uint8_t register_new_value; /*used to write new value to nrf24l01+ registers*/
static uint8_t write_pointer; /*used as an input for read and write functions (as a pointer)*/
static uint8_t current_address_width; /*current address width for receiver pipe addresses (up to 6 pipes), from 3 to 5 bytes*/
static uint8_t reset_flag = 0; /*reset flag lets the software know if the nrf24l01+ has ever been reset or not*/
static uint8_t current_mode = DEVICE_NOT_INITIALIZED; /*current mode of operation: DEVICE_NOT_INITIALIZED, PRX, PTX, STANDBYI, STANDBYII, POWER_DOWN*/
static uint8_t current_payload_width; /*payload width could be from 1 to 32 bytes, in either dynamic or static forms*/
static uint8_t current_acknowledgement_state = NO_ACK_MODE;
static uint8_t dynamic_payload = DISABLE;
/*2 dimensional array of pipe addresses (5 byte address width) by default. you can change addresses using a new array later.
Pipe 1 address could be anything. pipe 3 to 6 addresses share the first 4 bytes with pipe 2 and only differ in byte 5*/
uint8_t datapipe_address[MAXIMUM_NUMBER_OF_DATAPIPES][ADDRESS_WIDTH_DEFAULT] = {
{0xE1, 0xF0, 0xF0, 0xF0, 0xF0},
{0xD2, 0xF0, 0xF0, 0xF0, 0xF0},
{0xF0, 0xF0, 0xF0, 0xF0, 0xF0},
{0xF0, 0xF0, 0xF0, 0xF0, 0xF0},
{0xF0, 0xF0, 0xF0, 0xF0, 0xF0},
{0xF0, 0xF0, 0xF0, 0xF0, 0xF0}
};
/*delay in miliseconds*/
void delay_function(uint32_t duration_ms)
{
delay1ms(duration_ms);
}
/*contains all SPI configuations, such as pins and control registers*/
/*SPI control: master, interrupts disabled, clock polarity low when idle, clock phase falling edge, clock up tp 1 MHz*/
void SPI_Initializer(void) {
spiConfigure(
SPI_MSB_FIRST,
SPI_MODE0,
spiSelectSpeed(SPI_SPEED),
SPI_PIN_CONFIG,
GPIO_BIDIRECTIONAL_MODE
);
}
/*contains all CSN and CE pins gpio configurations, including setting them as gpio outputs and turning SPI off and CE '1'*/
void pinout_Initializer(void)
{
gpioConfigure(&CSN_pin);
gpioConfigure(&CE_pin);
gpioWrite(&CSN_pin, SPI_OFF);
gpioWrite(&CE_pin, CE_OFF);
}
/*CSN pin manipulation to high or low (SPI on or off)*/
void nrf24_SPI(uint8_t input)
{
gpioWrite(&CSN_pin, input);
}
/*1 byte SPI shift register send and receive routine*/
uint8_t SPI_send_command(uint8_t command) {
spiSend(&command, 1, &dataReady);
// readyFlag is cleared when calling send and is set after all buffer bits are sent, in this case the after the 1 bit is sent and the new byte is written to SPI_command
while(!dataReady);
return command;
}
/*CE pin maniplation to high or low*/
void nrf24_CE(uint8_t input)
{
gpioWrite(&CE_pin, input);
}
void nrf24_print_internal_register_values(void) {
uint8_t pipe_address[ADDRESS_WIDTH_DEFAULT];
for (int i=0; i<24; i++) {
if (i == 0x0a || i == 0x0b || i == 0x10) {
nrf24_read(i, pipe_address, current_address_width, CLOSE);
printf("\rRegister 0x%02x: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", i, \
pipe_address[0], \
pipe_address[1], \
pipe_address[2], \
pipe_address[3], \
pipe_address[4] \
);
} else {
nrf24_read(i, ®ister_current_value, 1, CLOSE);
printf("\rRegister 0x%02x: %d\n", i, register_current_value);
}
delay1ms(20);
}
nrf24_read(0X1C, ®ister_current_value, 1, CLOSE);
printf("\rRegister 0x1C: %d\n", register_current_value);
delay1ms(20);
nrf24_read(0X1D, ®ister_current_value, 1, CLOSE);
printf("\rRegister 0x1D: %d\n", register_current_value);
delay1ms(20);
printf("\n\n");
}
/*function to enable or disable dynamic acknowledge. if enabled, you can disable acknowledge
on a specific payload with W_TX_PAYLOAD_NOACK or enable acknowledge using W_TX_PAYLOAD commands.
if disabled, you cannot disable acknowledging a payload. manipulates EN_DYN_ACK inside FEATURE*/
void nrf24_dynamic_ack(uint8_t state)
{
if (state == ENABLE)
{
nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE);
register_new_value = register_current_value | (1 << EN_DYN_ACK);
nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE);
}
else
{
nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE);
register_new_value = register_current_value & (~(1 << EN_DYN_ACK));
nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE);
}
}
NRF24_SEND_STRING_STATUS nrf24_send_string(uint8_t* string) {
/* do { */
/* //TODO: for some reason if i don't reset the nrf every single time */
/* // the sending will miss many characters */
/* nrf24_device(TRANSMITTER, RESET); */
/* while(nrf24_transmit(string, 1, ACK_MODE) == TRANSMIT_FAIL) { printf("nrf24 failed to send!\n"); } */
/* nrf24_CE(1); */
/* while(nrf24_transmit_status() == TRANSMIT_IN_PROGRESS); */
/* nrf24_CE(0); */
/* } while (*++string != '\0'); */
/* nrf24_device(RECEIVER, RESET); */
// adjusting string to be payload_width size
uint8_t str_size = strlen(string);
if( str_size > current_payload_width) {
return SENT_FAILED_WRONG_STRING_SIZE;
}
strcpy(str_to_send, string);
for(int8_t i = (current_payload_width-str_size); i<0 ; i--) {
str_to_send[str_size+i] = 0x00;
}
// entering transmitter mode
nrf24_device(TRANSMITTER, RESET);
// loading the transmit FIFO of the nrf24
while(nrf24_transmit(str_to_send, current_payload_width, ACK_MODE) == TRANSMIT_FAIL) {
printf("nrf24 failed to send!\n");
return SENT_FAILED_TRANSMIT_FUNC_ERROR;
}
// Chip enabling, and waiting until TRANSMIT_DONE
nrf24_CE(1);
while(nrf24_transmit_status() == TRANSMIT_IN_PROGRESS);
nrf24_CE(0);
// Go back to listening :D
nrf24_device(RECEIVER, RESET);
// Transmit was successful ;D
return SENT_SUCCESS;
}
/*function for PTX device to transmit 1 to 32 bytes of data, used for both dynamic payload length
and static payload length methods. acknowledgemet state could be NO_ACK_MODE or ACK_MODE*/
uint8_t nrf24_transmit(uint8_t *payload, uint8_t payload_width, uint8_t acknowledgement_state)
{
nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*in order to check TX_FIFO status*/
if ((!(register_current_value & (1 << TX_FULL))) && (current_mode == PTX))
{
current_acknowledgement_state = acknowledgement_state; /*setting the acknowledgement state to either NO_ACK or ACK, based on input*/
if (dynamic_payload == ENABLE)
payload_width = current_payload_width;
nrf24_send_payload(payload, payload_width); /*the actual function to send data*/
return (TRANSMIT_BEGIN); /*TX FIFO is not full and nrf24l01+ mode is standby ii or ptx*/
}
else
{
return (TRANSMIT_FAIL); /*TX FIFO full or wrong mode*/
}
}
/*used by nrf24_transmit function to send the actual data*/
void nrf24_send_payload(uint8_t *payload, uint8_t payload_width)
{
nrf24_SPI(SPI_ON);
if (current_acknowledgement_state == NO_ACK_MODE)
SPI_command = W_TX_PAYLOAD_NOACK;
else
SPI_command = W_TX_PAYLOAD;
SPI_send_command(SPI_command);
for (; payload_width; payload_width--)
{
SPI_command = *payload;
SPI_send_command(SPI_command);
payload++;
}
nrf24_SPI(SPI_OFF);
}
/*reports back transmit status: TRANSMIT_DONE, TRANSMIT_FAILED (in case of reaching maximum number of retransmits in auto acknowledgement mode)
and TRANSMIT_IN_PROGRESS, if neither flags are set. automatically resets the '1' flags.*/
uint8_t nrf24_transmit_status()
{
nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*status register is read to check TX_DS flag*/
if (register_current_value & (1 << TX_DS)) /*if the TX_DS == 1, */
{
nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the TX_DS flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/
return TRANSMIT_DONE;
}
else if (register_current_value & (1 << MAX_RT))
{
nrf24_write(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*reseting the MAX_RT flag. as mentioned by datasheet, writing '1' to a flag resets that flag*/
return TRANSMIT_FAILED;
}
else
return TRANSMIT_IN_PROGRESS;
}
/*the receive function output is used as a polling method to check the received data inside RX FIFOs.
If there is any data available, it will be loaded inside payload array*/
uint8_t nrf24_receive(uint8_t *payload, uint8_t payload_width)
{
if (current_mode == PRX)
{
nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE);
if (register_current_value & (1 << RX_DR)) /*if received data is ready inside RX FIFO*/
{
if(dynamic_payload == DISABLE) /*if dynamic payload width is disabled, use the static payload width and ignore the input*/
payload_width = current_payload_width;
nrf24_SPI(SPI_ON); /*sending the read payload command to nrf24l01+*/
SPI_command = R_RX_PAYLOAD;
SPI_send_command(SPI_command);
for (; payload_width; payload_width--)
{
SPI_command = NOP_CMD;
*payload = SPI_send_command(SPI_command);
payload++;
}
nrf24_SPI(SPI_OFF);
nrf24_read(FIFO_STATUS_ADDRESS, ®ister_current_value, 1, CLOSE); /*in order to check the RX_EMPTY flag*/
if(register_current_value & (1 << RX_EMPTY)) /*if the RX FIFO is empty, reset the RX_DR flag inside STATUS register*/
{
nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE);
register_new_value = register_current_value | (1 << RX_DR);
nrf24_write(STATUS_ADDRESS, ®ister_new_value, 1, CLOSE);
}
return OPERATION_DONE;
}
else
{
return RECEIVE_FIFO_EMPTY;
}
}
else
return OPERATION_ERROR;
}
/*function which uses TX_FLUSH or RX_FLUSH command to flush the fifo buffers. if successful, output is OPERATION_DONE.
if not successful (wrong input or wrong mode of operation) output will be OPERATION_ERROR*/
uint8_t nrf24_flush(uint8_t fifo_select)
{
switch (fifo_select)
{
case TX_BUFFER:
if (current_mode == PTX)
{
nrf24_SPI(SPI_ON);
SPI_command = FLUSH_TX;
SPI_send_command(SPI_command);
nrf24_SPI(SPI_OFF);
return OPERATION_DONE;
}
else
return OPERATION_ERROR;
case RX_BUFFER:
if (current_mode == PRX)
{
nrf24_SPI(SPI_ON);
SPI_command = FLUSH_RX;
SPI_send_command(SPI_command);
nrf24_SPI(SPI_OFF);
return OPERATION_DONE;
}
else
return OPERATION_ERROR;
default:
return OPERATION_ERROR;
}
}
/*must be called atleast once, which happens with calling nrf24_device function*/
void nrf24_reset() {
reset_flag = 1;
nrf24_CE(CE_OFF);
register_new_value = CONFIG_REGISTER_DEFAULT;
nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE);
register_new_value = EN_AA_REGISTER_DEFAULT;
nrf24_write(EN_AA_ADDRESS, ®ister_new_value, 1, CLOSE);
register_new_value = EN_RXADDR_REGISTER_DEFAULT;
nrf24_write(EN_RXADDR_ADDRESS, ®ister_new_value, 1, CLOSE);
register_new_value = SETUP_AW_REGISTER_DEFAULT;
nrf24_write(SETUP_AW_ADDRESS, ®ister_new_value, 1, CLOSE);
register_new_value = RF_CH_REGISTER_DEFAULT;
nrf24_write(RF_CH_ADDRESS, ®ister_new_value, 1, CLOSE);
register_new_value = RF_SETUP_REGISTER_DEFAULT;
nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE);
register_new_value = STATUS_REGISTER_DEFAULT;
nrf24_write(STATUS_ADDRESS, ®ister_new_value, 1, CLOSE);
nrf24_mode(PTX);
nrf24_flush(TX_BUFFER);
nrf24_mode(PRX);
nrf24_flush(RX_BUFFER);
nrf24_read(STATUS_ADDRESS, ®ister_current_value, 1, CLOSE);
register_new_value = register_current_value | (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT);
nrf24_write(STATUS_ADDRESS, ®ister_new_value, 1, CLOSE);
nrf24_interrupt_mask(ENABLE, ENABLE, ENABLE);
nrf24_crc_configuration(ENABLE, 1);
nrf24_address_width(ADDRESS_WIDTH_DEFAULT);
nrf24_rf_datarate(RF_DATARATE_DEFAULT);
nrf24_rf_power(RF_PWR_DEFAULT);
nrf24_rf_channel(RF_CHANNEL_DEFAULT);
nrf24_datapipe_enable(NUMBER_OF_DP_DEFAULT);
nrf24_datapipe_address_configuration();
nrf24_datapipe_ptx(1);
nrf24_prx_static_payload_width(STATIC_PAYLOAD_WIDTH_DEFAULT, NUMBER_OF_DP_DEFAULT);
nrf24_automatic_retransmit_setup(RETRANSMIT_DELAY_DEFAULT, RETRANSMIT_COUNT_DEFAULT);
nrf24_auto_acknowledgment_setup(NUMBER_OF_DP_DEFAULT);
nrf24_dynamic_payload(DISABLE, NUMBER_OF_DP_DEFAULT);
nrf24_dynamic_ack(ENABLE);
}
/*used by firmware to set the nrf24 mode in TRANSMITTER, RECEIVER, POWER_SAVING or TURN_OFF states, and reseting the device
if it has not been done yet. This is the initializer, and everything starts by calling nrf24_device first.It has a higher
level of abstraction than nrf24_mode and must be used by user*/
void nrf24_device(uint8_t device_mode, uint8_t reset_state)
{
SPI_Initializer();
pinout_Initializer();
delay_function(STARTUP_DELAY);
if ((reset_state == RESET) || (reset_flag == 0))
{
nrf24_reset();
}
switch (device_mode)
{
case TRANSMITTER:
nrf24_mode(POWER_DOWN);
nrf24_interrupt_mask(ENABLE, DISABLE, DISABLE); /*disabling tx interrupt mask*/
nrf24_mode(PTX);
break;
case RECEIVER:
nrf24_mode(POWER_DOWN);
nrf24_interrupt_mask(DISABLE, ENABLE, ENABLE); /*disabling rx interrupt mask*/
nrf24_mode(PRX);
delay_function(PRX_MODE_DELAY); /*100ms for PRX mode*/
break;
case POWER_SAVING:
nrf24_mode(POWER_DOWN);
nrf24_interrupt_mask(ENABLE, ENABLE, ENABLE);
nrf24_mode(STANDBYI);
break;
case TURN_OFF:
nrf24_mode(POWER_DOWN);
nrf24_interrupt_mask(ENABLE, ENABLE, ENABLE);
break;
default:
nrf24_mode(POWER_DOWN);
nrf24_interrupt_mask(ENABLE, ENABLE, ENABLE);
break;
}
}
/*setting automatic retransmit delay time and maximum number of retransmits*/
void nrf24_automatic_retransmit_setup(uint16_t delay_time, uint8_t retransmit_count)
{
register_new_value = 0x00;
for (; (delay_time > 250) && (register_new_value < 0X0F); delay_time -= 250)
register_new_value++;
register_new_value <<= ARD_0;
if ((retransmit_count > 0) && (retransmit_count < 16))
register_new_value |= retransmit_count;
else
register_new_value |= 0;
nrf24_write(SETUP_RETR_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*setting auto acknoledgement on datapipes*/
void nrf24_auto_acknowledgment_setup(uint8_t datapipe)
{
if (datapipe < 7)
register_new_value = (1 << datapipe) - 1;
nrf24_write(EN_AA_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*turns on or off the dynamic payload width capability*/
void nrf24_dynamic_payload(uint8_t state, uint8_t datapipe)
{
nrf24_auto_acknowledgment_setup(datapipe); /*setting auto acknowledgment before setting dynamic payload*/
nrf24_read(FEATURE_ADDRESS, ®ister_current_value, 1, CLOSE);
if (state == ENABLE)
{
register_new_value = register_current_value | (1 << EN_DPL); /*EN_DPL bit turns dynamic payload width on or off on all datapipes*/
nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE);
if (datapipe < 7)
register_new_value = (1 << datapipe) - 1; /*turning on dynamic payload width on chosen datapipes, using DYNPD register*/
nrf24_write(DYNPD_ADDRESS, ®ister_new_value, 1, CLOSE);
dynamic_payload = ENABLE;
}
else
{
register_new_value = register_current_value & (~(1 << EN_DPL));
nrf24_write(FEATURE_ADDRESS, ®ister_new_value, 1, CLOSE);
dynamic_payload = DISABLE;
}
}
/*on nrf24l01+ there is only one address for PTX device which must be the same as PRX data pipe address 0*/
void nrf24_datapipe_ptx(uint8_t datapipe_number)
{
nrf24_write(TX_ADDR_ADDRESS, &datapipe_address[datapipe_number - 1][0], current_address_width, CLOSE);
}
/*setting the 6 datapipe addresses using the datapipe_address[][]*/
void nrf24_datapipe_address_configuration()
{
uint8_t address = RX_ADDR_P0_ADDRESS;
for (uint8_t counter = 0; counter < 6; counter++)
{
nrf24_write(address, &datapipe_address[counter][0], current_address_width, CLOSE);
address++;
}
}
/*function to change static payload width, from 1 to 32 bytes in each payload*/
void nrf24_prx_static_payload_width(uint8_t static_payload_width, uint8_t number_of_datapipes)
{
for (uint8_t address = RX_PW_P0_ADDRESS; number_of_datapipes; number_of_datapipes--)
{
nrf24_write(address, &static_payload_width, 1, CLOSE);
address++;
}
current_payload_width = static_payload_width;
}
/*datapipes are turned on and off using EN_RXADDR register, PRX datapipe addresses are located in RX_ADDR_Pn, TX address is located inside TX_ADDR*/
void nrf24_datapipe_enable(uint8_t number_of_datapipes)
{
register_new_value = (1 << number_of_datapipes) - 1;
nrf24_write(EN_RXADDR_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*function to set the nrf24l01+ address width, from 3 to 5 bytes*/
void nrf24_address_width(uint8_t address_width)
{
if ((address_width <= 5) && (address_width >= 3))
{
write_pointer = address_width - 2;
}
else
{
write_pointer = 3;
}
nrf24_write(SETUP_AW_ADDRESS, &write_pointer, 1, CLOSE); /*5 bytes is the maximum address width available*/
current_address_width = address_width;
}
/*datarate settings, you can choose between 2mbps, 1mbps, 250kbps*/
void nrf24_rf_datarate(uint8_t rf_datarate)
{
nrf24_read(RF_SETUP_ADDRESS, ®ister_current_value, 1, CLOSE);
register_current_value &= ~((1 << RF_DR_LOW) | (1 << RF_DR_HIGH));
switch (rf_datarate)
{
case 2000:
register_new_value = register_current_value | (1 << RF_DR_HIGH);
break;
case 1000:
register_new_value = register_current_value;
break;
case 250:
register_new_value = register_current_value | (1 << RF_DR_LOW);
break;
default:
register_new_value = register_current_value;
break;
}
nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*nrf24l01+ RF power settings. 0dbm, -6dbm, -12dbm, -18dbm*/
void nrf24_rf_power(uint8_t rf_power)
{
nrf24_read(RF_SETUP_ADDRESS, ®ister_current_value, 1, CLOSE);
register_current_value &= ~((1 << RF_PWR_1) | (1 << RF_PWR_0));
switch (rf_power)
{
case 0:
register_new_value = register_current_value | ((1 << RF_PWR_1) | (1 << RF_PWR_0));
break;
case 6:
register_new_value = register_current_value | (1 << RF_PWR_1);
break;
case 12:
register_new_value = register_current_value | (1 << RF_PWR_0);
break;
case 18:
register_new_value = register_current_value;
break;
default:
register_new_value = register_current_value | (1 << RF_PWR_1);
break;
}
nrf24_write(RF_SETUP_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*nrf24l01+ RF channel selection, from 1 to 125*/
void nrf24_rf_channel(uint8_t rf_channel)
{
if ((rf_channel <= 125) && (rf_channel >= 1))
{
uint8_t write_pointer = rf_channel;
nrf24_write(RF_CH_ADDRESS, &write_pointer, 1, CLOSE);
}
else
{
uint8_t write_pointer = 1;
nrf24_write(RF_CH_ADDRESS, &write_pointer, 1, CLOSE);
}
}
/*interrupt mask settings. 3 seperate masks for RX, TX, and RT (maximum numbers of retransmission reached*/
void nrf24_interrupt_mask(uint8_t rx_mask, uint8_t tx_mask, uint8_t max_rt_mask)
{
nrf24_read(CONFIG_ADDRESS, ®ister_current_value, 1, CLOSE);
if (rx_mask)
register_new_value = (register_current_value) | (1 << MASK_RX_DR);
else
register_new_value &= (~(1 << MASK_RX_DR));
if (tx_mask)
register_new_value |= (1 << MASK_TX_DS);
else
register_new_value &= (~(1 << MASK_TX_DS));
if (max_rt_mask)
register_new_value |= (1 << MASK_MAX_RT);
else
register_new_value &= (~(1 << MASK_MAX_RT));
nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*enabling or disabling crc in payload; setting crc encoding scheme between 1 or 2 bytes*/
void nrf24_crc_configuration(uint8_t crc_enable, uint8_t crc_encoding_scheme)
{
nrf24_read(CONFIG_ADDRESS, ®ister_current_value, 1, CLOSE);
if (crc_enable)
register_new_value = (register_current_value) | (1 << EN_CRC);
else
register_new_value &= (~(1 << EN_CRC));
if (crc_encoding_scheme == 2)
register_new_value |= (1 << CRCO);
else
register_new_value &= (~(1 << CRCO));
nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE);
}
/*mode selector: power down, standby i, standby ii, ptx, prx. used by nrf24_device function*/
void nrf24_mode(uint8_t mode)
{
nrf24_read(CONFIG_ADDRESS, ®ister_current_value, 1, CLOSE);
switch (mode)
{
case POWER_DOWN:
nrf24_CE(CE_OFF);
register_new_value = (register_current_value) & (~(1 << PWR_UP));
delay_function(POWER_DOWN_DELAY);
break;
case STANDBYI: /*standby I is defined by 'PWR_UP = 1' and 'CE pin LOW'*/
nrf24_CE(CE_OFF);
register_new_value = (register_current_value) | (1 << PWR_UP);
delay_function(STANDBYI_DELAY);
break;
case STANDBYII: /*standby ii is related to a ptx device*/
nrf24_CE(CE_ON);
register_new_value = ((register_current_value) | (1 << PWR_UP)) & (~(1 << PRIM_RX));
delay_function(STANDBYI_DELAY);
break;
case PTX:
nrf24_CE(CE_ON);
register_new_value = ((register_current_value) | (1 << PWR_UP)) & (~(1 << PRIM_RX));
delay_function(STANDBYI_DELAY);
break;
case PRX:
nrf24_CE(CE_ON);
register_new_value = (register_current_value) | (1 << PWR_UP) | (1 << PRIM_RX);
delay_function(STANDBYI_DELAY);
break;
default:
nrf24_CE(CE_OFF);
register_new_value = (register_current_value) & (~(1 << PWR_UP));
delay_function(POWER_DOWN_DELAY);
break;
}
nrf24_write(CONFIG_ADDRESS, ®ister_new_value, 1, CLOSE);
current_mode = mode;
}
/*reads the number of bytes (data_length) from the register in nrf24l01+ (address) and stores them inside an array (value),
then closes the spi connection (spi_state = CLOSE) or leaves it open (spi_state = OPEN)*/
void nrf24_read(uint8_t address, uint8_t *value, uint8_t data_length, uint8_t spi_state)
{
nrf24_SPI(SPI_ON);
SPI_command = R_REGISTER | address; /*in order to read CONFIG, then change one bit*/
SPI_send_command(SPI_command);
SPI_command = NOP_CMD;
for (; data_length ; data_length--)
{
*value = SPI_send_command(SPI_command);
value++;
}
if (spi_state == CLOSE)
nrf24_SPI(SPI_OFF);
}
/*writes the number of bytes (data_length) from an array (value) inside registers in nrf24l01+ (address),
then closes the spi connection (spi_state = CLOSE) or leaves it open (spi_state = OPEN)*/
void nrf24_write(uint8_t address, uint8_t *value, uint8_t data_length, uint8_t spi_state)
{
nrf24_SPI(SPI_ON);
SPI_command = W_REGISTER | address; /*in order to read CONFIG, then change one bit*/
SPI_send_command(SPI_command);
for (; data_length ; data_length--)
{
SPI_command = *value;
value++;
SPI_send_command(SPI_command);
}
if (spi_state == CLOSE)
nrf24_SPI(SPI_OFF);
}