// Checks if data is available for reading bool nrf24l01_dataReady() { // See note in getData() function - just checking RX_DR isn't good enough uint8_t status = nrf24l01_read_register(NRF24L01_STATUS_REG); // We can short circuit on RX_DR, but if it's not set, we still need // to check the FIFO for any pending packets if (status & NRF24L01_RX_DR_BM) return true; // return true if rx fifo is not empty uint8_t fifoStatus = nrf24l01_read_register(NRF24L01_FIFO_STATUS_REG); return !(fifoStatus & NRF24L01_RX_EMPTY_BM); }
//clears the PLOS_CNT field of the OBSERVE_TX register //this function makes a read of the current value of RF_CH and // simply writes it back to the register, clearing PLOS_CNT void nrf24l01_clear_plos_cnt() { unsigned char data; nrf24l01_read_register(nrf24l01_RF_CH, &data, 1); nrf24l01_write_register(nrf24l01_RF_CH, &data, 1); }
void nrf24l01_power_off() { // TODO: Wait that nrf finish rx_read, tx_send or tx_wait_ack uint8_t config_reg = nrf24l01_read_register(NRF24L01_CONFIG_REG); config_reg &= ~NRF24L01_PWR_UP_BM; nrf24l01_write_register(NRF24L01_CONFIG_REG, config_reg); }
//powers up the 24L01 with all necessary delays //this function takes the existing contents of the CONFIG register and sets the PWR_UP //the argument rx_active_mode is only used if the user is setting up the // 24L01 as a receiver. If the argument is false, the receiver will remain in // standby mode and not monitor for packets. If the argument is true, the CE // pin will be set and the 24L01 will monitor for packets. In TX mode, the value // of this argument is insignificant. //note: if the read value of the CONFIG register already has the PWR_UP bit set, this function // exits in order to not make an unecessary register write. void nrf24l01_power_up(bool rx_active_mode) { unsigned char config; nrf24l01_read_register(nrf24l01_CONFIG, &config, 1); if((config & nrf24l01_CONFIG_PWR_UP) != 0) return; config |= nrf24l01_CONFIG_PWR_UP; nrf24l01_write_register(nrf24l01_CONFIG, &config, 1); delay_us(1500); if((config & nrf24l01_CONFIG_PRIM_RX) == 0) nrf24l01_clear_ce(); else { if(rx_active_mode != false) nrf24l01_set_ce(); else nrf24l01_clear_ce(); } }
//returns the value of the OBSERVE_TX register unsigned char nrf24l01_get_observe_tx() { unsigned char data; nrf24l01_read_register(nrf24l01_OBSERVE_TX, &data, 1); return data; }
//returns the current RF channel in RF_CH register unsigned char nrf24l01_get_rf_ch() { unsigned char data; nrf24l01_read_register(nrf24l01_RF_CH, &data, 1); return data; }
//returns the value of the CONFIG register unsigned char nrf24l01_get_config() { unsigned char data; nrf24l01_read_register(nrf24l01_CONFIG, &data, 1); return data; }
//returns the current PLOS_CNT value in OBSERVE_TX register unsigned char nrf24l01_get_plos_cnt() { unsigned char data; nrf24l01_read_register(nrf24l01_OBSERVE_TX, &data, 1); return ((data & nrf24l01_OBSERVE_TX_PLOS_CNT) >> 4); }
//returns the status of the CD register (true if carrier detect [CD] is // active, false if not) bool nrf24l01_cd_active() { unsigned char data; nrf24l01_read_register(nrf24l01_CD, &data, 1); return data; }
//returns the value of the FIFO_STATUS register unsigned char nrf24l01_get_fifo_status() { unsigned char data; nrf24l01_read_register(nrf24l01_FIFO_STATUS, &data, 1); return data; }
//returns true if TX_REUSE bit in FIFO_STATUS register is set, false otherwise bool nrf24l01_fifo_tx_reuse() { unsigned char data; nrf24l01_read_register(nrf24l01_FIFO_STATUS, &data, 1); return (bool)(data & nrf24l01_FIFO_STATUS_TX_REUSE); }
//returns true if RX_FULL bit in FIFO_STATUS register is set, false otherwise bool nrf24l01_fifo_rx_full() { unsigned char data; nrf24l01_read_register(nrf24l01_FIFO_STATUS, &data, 1); return (bool)(data & nrf24l01_FIFO_STATUS_RX_FULL); }
//returns the current ARC_CNT value in OBSERVE_TX register unsigned char nrf24l01_get_arc_cnt() { unsigned char data; nrf24l01_read_register(nrf24l01_OBSERVE_TX, &data, 1); return (data & nrf24l01_OBSERVE_TX_ARC_CNT); }
//returns true if RX_EMPTYE bit in FIFO_STATUS register is set, false otherwise bool nrf24l01_fifo_rx_empty() { unsigned char data; nrf24l01_read_register(nrf24l01_FIFO_STATUS, &data, 1); return (bool)(data & nrf24l01_FIFO_STATUS_RX_EMPTY); }
// Power Up in TX Mode void nrf24l01_primary_tx() { PTX = 1; uint8_t config_reg = nrf24l01_read_register(NRF24L01_CONFIG_REG); config_reg |= NRF24L01_PWR_UP_BM; // Power Up config_reg &= ~NRF24L01_PRIM_RX_BM; // PTX mode nrf24l01_write_register(NRF24L01_CONFIG_REG, config_reg); //nrf24l01_write_register(NRF24L01_CONFIG_REG,NRF24L01_EN_CRC_BM | NRF24L01_PWR_UP_BM); }
// Initialize Pin and SPI like specified into config file void nrf24l01_init() { // Init SPI pins ioport_set_pin_dir(CONF_NRF24L01_SS_PIN, IOPORT_DIR_INPUT); ioport_set_pin_mode(CONF_NRF24L01_SS_PIN, IOPORT_MODE_PULLUP); ioport_set_pin_dir(CONF_NRF24L01_MOSI_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_mode(CONF_NRF24L01_MOSI_PIN, IOPORT_MODE_PULLUP); ioport_set_pin_high(CONF_NRF24L01_MOSI_PIN); ioport_set_pin_dir(CONF_NRF24L01_MISO_PIN, IOPORT_DIR_INPUT); ioport_set_pin_dir(CONF_NRF24L01_SCK_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_high(CONF_NRF24L01_SCK_PIN); // Init nrf24l01 pins ioport_set_pin_dir(CONF_NRF24L01_CE_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_dir(CONF_NRF24L01_CSn_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_dir(CONF_NRF24L01_IRQ_PIN, IOPORT_DIR_INPUT); ioport_set_pin_low(CONF_NRF24L01_CE_PIN); spi_deselect_device(&CONF_NRF24L01_SPI, &nrf24l01_spi_device_conf); spi_master_init(&CONF_NRF24L01_SPI); spi_master_setup_device(&CONF_NRF24L01_SPI, &nrf24l01_spi_device_conf, SPI_MODE_0, CONF_NRF24L01_CLOCK_SPEED, 0); spi_enable(&CONF_NRF24L01_SPI); // Wait nrf24l01 power on reset delay_ms(Tpor); nrf24l01_power_off(); // Reset registers to default state nrf24l01_write_register(NRF24L01_CONFIG_REG, NRF24L01_CONFIG_REG_DEF); nrf24l01_write_register(NRF24L01_STATUS_REG, NRF24L01_STATUS_REG_DEF); // TODO: reset all registers // Config parameters sets in CONF_NRF24L01 nrf24l01_set_power_amplifier(CONF_NRF24L01_PA); nrf24l01_set_data_rate(CONF_NRF24L01_DATA_RATE); nrf24l01_set_crc(CONF_NRF24L01_CRC); nrf24l01_set_addr_len(CONF_NRF24L01_ADDR_LEN); uint8_t nrf24l01_rx_addr[5] = { CONF_NRF24L01_RX_ADDR }; uint8_t nrf24l01_tx_addr[5] = { CONF_NRF24L01_TX_ADDR }; nrf24l01_set_rx_addr(nrf24l01_rx_addr); nrf24l01_set_tx_addr(nrf24l01_tx_addr); nrf24l01_write_register(NRF24L01_RF_CH_REG, CONF_NRF24L01_RF_CHANNEL); nrf24l01_write_register(NRF24L01_RX_PW_P0_REG, CONF_NRF24L01_PAYLOAD); nrf24l01_write_register(NRF24L01_RX_PW_P1_REG, CONF_NRF24L01_PAYLOAD); // Power-up (Power Down -> Standby-I) uint8_t configReg = nrf24l01_read_register(NRF24L01_CONFIG_REG); nrf24l01_write_register(NRF24L01_CONFIG_REG, configReg | NRF24L01_PWR_UP_BM); delay_us(Tpd2stby); }
//returns true if the pipe is enabled that is offset by rxpipenum //unsigned char rxpipenum is the pipe number (zero to five) whose address is being // specified. If an invalid address (greater than five) is supplied, the function // returns false. bool nrf24l01_rx_pipe_enabled(unsigned char rxpipenum) { unsigned char data; if((rxpipenum > 5)) return false; nrf24l01_read_register(nrf24l01_EN_RXADDR, &data, 1); return (data & (0x01 << rxpipenum)); }
//returns true if auto-ack is enabled on the pipe that is offset by rxpipenum //unsigned char rxpipenum is the pipe number (zero to five) whose address is being // specified. If an invalid address (greater than five) is supplied, the function // returns false. bool nrf24l01_aa_enabled(unsigned char rxpipenum) { unsigned char data; if(rxpipenum > 5) return false; nrf24l01_read_register(nrf24l01_EN_AA, &data, 1); return (data & (0x01 << rxpipenum)); }
//gets the RX payload width on the pipe offset by rxpipenum //unsigned char rxpipenum is the pipe number (zero to five) whose address is being // specified. If an invalid address (greater than five) is supplied, the function // does nothing. unsigned char nrf24l01_get_rx_pw(unsigned char rxpipenum) { unsigned char data; if((rxpipenum > 5)) return 0; nrf24l01_read_register(nrf24l01_RX_PW_P0 + rxpipenum, &data, 1); return data; }
// Power Up in RX Mode void nrf24l01_primary_rx() { PTX = 0; ioport_set_pin_low(CONF_NRF24L01_CE_PIN); uint8_t configReg = nrf24l01_read_register(NRF24L01_CONFIG_REG); nrf24l01_write_register(NRF24L01_CONFIG_REG, configReg | NRF24L01_PWR_UP_BM | NRF24L01_PRIM_RX_BM); ioport_set_pin_high(CONF_NRF24L01_CE_PIN); delay_us(Tstby2a); //uint8_t statusReg = nrf24l01_read_register(NRF24L01_STATUS_REG); nrf24l01_write_register(NRF24L01_STATUS_REG, NRF24L01_TX_DS_BM | NRF24L01_MAX_RT_BM); }
//sets up the 24L01 as a transmitter //this function takes the existing contents of the CONFIG register and simply // clears the PRIM_RX bit in the CONFIG register. //note: if the read value of the CONFIG register already has the PRIM_RX bit cleared, this // function exits in order to not make an unecessary register write. void nrf24l01_set_as_tx() { unsigned char config; nrf24l01_read_register(nrf24l01_CONFIG, &config, 1); if((config & nrf24l01_CONFIG_PRIM_RX) == 0) return; config &= (~nrf24l01_CONFIG_PRIM_RX); nrf24l01_write_register(nrf24l01_CONFIG, &config, 1); nrf24l01_clear_ce(); }
// Test if chip is still sending. When sending has finished return chip to listening. bool nrf24l01_isSending(){ if(PTX){ uint8_t status = nrf24l01_read_register(NRF24L01_STATUS_REG); //#define NRF24L01_TX_DS_BM (1 << 5) //#define NRF24L01_MAX_RT_BM (1 << 4) // if sending successful (TX_DS) or max retries exceded (MAX_RT). if((status & (NRF24L01_TX_DS_BM | NRF24L01_MAX_RT_BM))){ nrf24l01_primary_rx(); return false; } return true; } return false; }
//powers down the 24L01 //this function takes the existing contents of the CONFIG register and simply // clears the PWR_UP bit in the CONFIG register. //note: if the read value of the CONFIG register already has the PWR_UP bit cleared, this // function exits in order to not make an unecessary register write. void nrf24l01_power_down() { unsigned char config; nrf24l01_read_register(nrf24l01_CONFIG, &config, 1); if((config & nrf24l01_CONFIG_PWR_UP) == 0) return; config &= (~nrf24l01_CONFIG_PWR_UP); nrf24l01_write_register(nrf24l01_CONFIG, &config, 1); nrf24l01_clear_ce(); }
//enables auto-ack is enabled on the pipe that is offset by rxpipenum //unsigned char rxpipenum is the pipe number (zero to five) whose address is being // does nothing. void nrf24l01_aa_enable(unsigned char rxpipenum) { unsigned char data; if(rxpipenum > 5) return; nrf24l01_read_register(nrf24l01_EN_AA, &data, 1); if((data & (0x01 << rxpipenum)) != 0) return; data |= 0x01 << rxpipenum; nrf24l01_write_register(nrf24l01_EN_AA, &data, 1); }
//disables the pipe that is offset by rxpipenum //unsigned char rxpipenum is the pipe number (zero to five) whose address is being // specified. If an invalid address (greater than five) is supplied, the function // does nothing. void nrf24l01_rx_pipe_disable(unsigned char rxpipenum) { unsigned char data; if(rxpipenum > 5) return; nrf24l01_read_register(nrf24l01_EN_RXADDR, &data, 1); if((data & (0x01 << rxpipenum)) == 0) return; data &= ~(0x01 << rxpipenum); nrf24l01_write_register(nrf24l01_EN_RXADDR, &data, 1); }
void nrf24l01_set_crc(enum nrf24l01_crc crc) { uint8_t config_reg = nrf24l01_read_register(NRF24L01_CONFIG_REG); switch(crc) { case NRF24L01_CRC_DISABLED: config_reg &= ~NRF24L01_EN_CRC_BM; break; case NRF24L01_CRC_1B: config_reg |= NRF24L01_EN_CRC_BM; config_reg &= ~NRF24L01_CRCO_BM; break; case NRF24L01_CRC_2B: config_reg |= NRF24L01_EN_CRC_BM | NRF24L01_CRCO_BM; break; } nrf24l01_write_register(NRF24L01_CONFIG_REG, config_reg); };
//sets up the 24L01 as a receiver with all necessary delays //this function takes the existing contents of the CONFIG register and sets the PRIM_RX // bit in the CONFIG register. //if the argument rx_active_mode is false, the receiver will remain in standby mode // and not monitor for packets. If the argument is true, the CE pin will be set // and the 24L01 will monitor for packets. //note: if the read value of the CONFIG register already has the PRIM_RX bit set, this function // exits in order to not make an unecessary register write. void nrf24l01_set_as_rx(bool rx_active_mode) { unsigned char config; unsigned char status; status = nrf24l01_read_register(0, &config, 1); if((config & nrf24l01_CONFIG_PRIM_RX) != 0) return; config |= nrf24l01_CONFIG_PRIM_RX; nrf24l01_write_register(nrf24l01_CONFIG, &config, 1); if(rx_active_mode != false) nrf24l01_set_ce(); else nrf24l01_clear_ce(); }
void nrf24l01_set_data_rate(enum nrf24l01_data_rate dataRate) { uint8_t rf_setup_reg = nrf24l01_read_register(NRF24L01_RF_SETUP_REG); switch (dataRate) { case NRF24L01_250kbps: rf_setup_reg |= NRF24L01_RF_DR_LOW_BM; rf_setup_reg &= ~NRF24L01_RF_DR_HIGH_BM; break; case NRF24L01_1Mbps: rf_setup_reg &= (~NRF24L01_RF_DR_HIGH_BM) & (~NRF24L01_RF_DR_HIGH_BM); break; case NRF24L01_2Mbps: rf_setup_reg |= NRF24L01_RF_DR_HIGH_BM; rf_setup_reg &= ~NRF24L01_RF_DR_LOW_BM; break; } nrf24l01_write_register(NRF24L01_RF_SETUP_REG, rf_setup_reg); }
void nrf24l01_set_power_amplifier(enum nrf24l01_power_amplifier pa) { uint8_t rf_setup_reg = nrf24l01_read_register(NRF24L01_RF_SETUP_REG); switch (pa) { case NRF24L01_PA_0dBm: rf_setup_reg |= NRF24L01_RF_PWR_BM; break; case NRF24L01_PA_less_6dBm: rf_setup_reg |= ((NRF24L01_RF_PWR_BM) & (0x02)); break; case NRF24L01_PA_less_12dBm: rf_setup_reg |= ((NRF24L01_RF_PWR_BM) & (0x01)); break; case NRF24L01_PA_less_18dBm: rf_setup_reg &= (~NRF24L01_RF_PWR_BM); break; } nrf24l01_write_register(NRF24L01_RF_SETUP_REG, rf_setup_reg); };
//unsigned char * data must be at least 35 bytes long void nrf24l01_get_all_registers(unsigned char * data) { unsigned int outer; unsigned int inner; unsigned int dataloc = 0; unsigned char buffer[5]; for(outer = 0; outer <= 0x17; outer++) { nrf24l01_read_register(outer, buffer, 5); for(inner = 0; inner < 5; inner++) { if(inner >= 1 && (outer != 0x0A && outer != 0x0B && outer != 0x10)) break; data[dataloc] = buffer[inner]; dataloc++; } } }