This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF24L01+: Not Receiving ACK at PTX

Hi, I am interfacing a TI TM4C123 microcontroller to the AddiCore nRF24L01+ Transceiver Module. I can consistently transmit and receive data with the microcontroller/nRF24L01+ modules, however the PTX does not receive the ACK from PRX. Using UARTs connected to each of the PTX and PRX, I can see the PRX receives the packet correctly but I don't get the ACK at the PTX. I have included the code to set-up the nRF24L01+ in PTX or RTX modes. Any help would be appreciated.

// Switch has been pressed.
// Initialize Wireless Interface (nRF24L01+)
// ************************************************************
// Transmitter
// ************************************************************
if (PF_In & 0x10) {
	// Switch 2 has been pressed to configure as transmitter.
	// Set up Nordic nRF24L01+ in transmit mode
    // Initialize the 24L01+ to the debug configuration as TX, x data byte, and auto-ack enabled
	nrf24l01_initialize_debug(false, NUMBYTES_PERPACKET, true);
		
    GPIO_PORTF_DATA_R |= 0x04;       // turn on blue LED
		
	// Display message by sending to UART
	UART_OutString((unsigned char*)"Transmit Mode Selected *");
	UART_sendCRLF( );
		
	// ***********************************************************************
	// ***********************************************************************
	// Transmitter Loop
	while(1) {
        UART_sendCRLF( );
		UART_sendCRLF( );
		UART_OutString((unsigned char*)"----------------------------  *");
		UART_sendCRLF( );
        UART_OutString((unsigned char*)"Transmission Cycle =  *");   // tx_cycle
		UART_OutChar(tx_cycle);
		UART_sendCRLF( );
		tx_cycle++;

        // Wait until either switch is pressed
        PF_In = GPIO_PORTF_DATA_R&0x11;       // read Sw1 & SW2
        while (PF_In == 0x11) { 
            PF_In = GPIO_PORTF_DATA_R&0x11;   // Check SW1 and SW2
        };
			
		// Load data array
		for (indx=0; indx<NUMBYTES_PERPACKET; indx++) {
			operator_input[indx] = tx_cycle + indx;
		}
			
		UART_OutString((unsigned char*)"Assigned input:  *");
		UART_OutChar(operator_input[0]);
		UART_sendCRLF( );
			
		nrf24l01_write_tx_payload(operator_input, pack_length, true); // write data to TX Fifo
			
		// wait until the nRF24L01+ IRQ pin is active (either RX_DR or MAX_RT flags active)
        while(!nrf24l01_irq_pin_active()) {};

		// Read status register
		nrf24l01_read_register(nrf24l01_STATUS, &status_reg, 1);
		status_reg &= nrf24l01_CONFIG_MASK_RX_DR;    // mask all bits but RX_DR
				
		if(status_reg == nrf24l01_CONFIG_MASK_RX_DR) {
            nrf24l01_irq_clear_all(); //clear all interrupts in the 24L01

			nrf24l01_read_rx_payload(&data_transmit, pack_length); //get the payload into data
                
            nrf24l01_irq_clear_all(); //clear interrupts again
			UART_sendCRLF( );
			UART_OutString((unsigned char*)"Transmit Done. *");
			UART_sendCRLF( );
			UART_OutString((unsigned char*)"Ack Data Received:  *");
			UART_OutChar(data_transmit);
			UART_sendCRLF( );
					
			delay_us(130);  //wait for receiver to come from standby to RX
			
			delay_us(200000); // debounce switches
			GPIO_PORTF_DATA_R ^= 0x04;       // toggle blue LED
        }
		// Maximum number of retries has been reached.
        else {
            nrf24l01_flush_tx(); //get the unsent character out of the TX FIFO
            nrf24l01_irq_clear_all(); //clear all interrupts
			UART_OutString((unsigned char*)"Max num of retries reached. Ack was not received. *");
			UART_sendCRLF( );
			delay_us(200000); // debounce switches
			GPIO_PORTF_DATA_R ^= 0x04;       // toggle blue LED
        }
	}	
}
			
// ***********************************************************************
// ***********************************************************************
// Receiver
else {
	// Switch 1 has been pressed to configure as receiver.
	// Set up Nordic nRF24L01+ in receive mode
    // Initialize the 24L01+ to the debug configuration as RX, 1 data byte, and auto-ack enabled
	nrf24l01_initialize_debug(true, NUMBYTES_PERPACKET, true);
	
	GPIO_PORTF_DATA_R |= 0x08;       // turn on green LED
	
	UART_OutString((unsigned char*)"Receive Mode Selected *");
	UART_sendCRLF( );
	
    //main RX program loop
    while(1) {			
		UART_OutString((unsigned char*)"Waiting for Receiver command. *");
		UART_sendCRLF( );
		recd_cmd = 0x00;  // clear received command
			
		// clear all interrupts and flush both TX and RX Fifos
		nrf24l01_clear_flush();    // ab July 28, 2014
			
		//wait until a packet has been received; IRQ pin will go low
		while(!nrf24l01_irq_pin_active()) {};
		delay_us(230);   //wait for the other 24L01 to come from standby to RX
        
		// Read one extra byte from the RX Fifo.  The first is the Status Register,
		// the rest of the bytes are the received data.
		nrf24l01_read_rx_payload(buf_array, NUMBYTES_PERPACKET+1); //read the packet into data
			
		UART_OutString((unsigned char*)"Status Register value: *");
		UART_OutChar(buf_array[0]);     // send received data to UART
		UART_sendCRLF( );
			
		// Now send data received to display
		for (indx=0; indx < NUMBYTES_PERPACKET; indx++) {
			UART_OutString((unsigned char*)"Received Data: *");
			UART_OutChar(buf_array[indx+1]);     // send received data to UART
			UART_sendCRLF( );
		}

		nrf24l01_irq_clear_all(); //clear interrupts again
		GPIO_PORTF_DATA_R ^= 0x08;       // toggle green LED
	}
}

}

Parents
  • Hi Hakon, I found code for the nRF24L01 on the web, written by Brennen Ball. I had to make a few changes port the code to the TI microcontroller but most of the original code is still used. Thanks, Al

    void nrf24l01_initialize_debug(bool rx, unsigned char p0_payload_width, bool enable_auto_ack) { unsigned char config; unsigned char en_aa;

    config = nrf24l01_CONFIG_DEFAULT_VAL | nrf24l01_CONFIG_PWR_UP | nrf24l01_CONFIG_CRCO;
    
    if(enable_auto_ack != false)
        en_aa = nrf24l01_EN_AA_ENAA_P0;
    else
        en_aa = nrf24l01_EN_AA_ENAA_NONE;
    
    if(rx == true)
        config = config | nrf24l01_CONFIG_PRIM_RX;
        
    nrf24l01_initialize(config, 
                        true,
                        en_aa, 
                        nrf24l01_EN_RXADDR_DEFAULT_VAL, 
                        nrf24l01_SETUP_AW_DEFAULT_VAL, 
                        nrf24l01_SETUP_RETR_DEFAULT_VAL, 
                        nrf24l01_RF_CH_DEFAULT_VAL, 
                        nrf24l01_RF_SETUP_DEFAULT_VAL,  
                        NULL, 
                        NULL, 
                        nrf24l01_RX_ADDR_P2_DEFAULT_VAL, 
                        nrf24l01_RX_ADDR_P3_DEFAULT_VAL, 
                        nrf24l01_RX_ADDR_P4_DEFAULT_VAL, 
                        nrf24l01_RX_ADDR_P5_DEFAULT_VAL, 
                        NULL, 
                        p0_payload_width, 
                        nrf24l01_RX_PW_P1_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P2_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P3_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P4_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P5_DEFAULT_VAL);  }
    

    void nrf24l01_initialize(unsigned char config, unsigned char opt_rx_active_mode,
    unsigned char en_aa, unsigned char en_rxaddr, unsigned char setup_aw, unsigned char setup_retr, unsigned char rf_ch, unsigned char rf_setup, unsigned char * rx_addr_p0, unsigned char * rx_addr_p1, unsigned char rx_addr_p2, unsigned char rx_addr_p3, unsigned char rx_addr_p4, unsigned char rx_addr_p5, unsigned char * tx_addr, unsigned char rx_pw_p0, unsigned char rx_pw_p1, unsigned char rx_pw_p2, unsigned char rx_pw_p3, unsigned char rx_pw_p4, unsigned char rx_pw_p5) { unsigned char data[5];

    data[0] = en_aa;
    nrf24l01_write_register(nrf24l01_EN_AA, data, 1);
    
    data[0] = en_rxaddr;
    nrf24l01_write_register(nrf24l01_EN_RXADDR, data, 1);
    
    data[0] = setup_aw;
    nrf24l01_write_register(nrf24l01_SETUP_AW, data, 1);
    
    data[0] = setup_retr;
    nrf24l01_write_register(nrf24l01_SETUP_RETR, data, 1);
    
    data[0] = rf_ch;
    nrf24l01_write_register(nrf24l01_RF_CH, data, 1);
    	
    data[0] = rf_setup;
    nrf24l01_write_register(nrf24l01_RF_SETUP, data, 1);
    	
    if(rx_addr_p0 != NULL)
        nrf24l01_set_rx_addr(rx_addr_p0, 5, 0);
    else
    {
        data[0] = nrf24l01_RX_ADDR_P0_B0_DEFAULT_VAL;
        data[1] = nrf24l01_RX_ADDR_P0_B1_DEFAULT_VAL;
        data[2] = nrf24l01_RX_ADDR_P0_B2_DEFAULT_VAL;
        data[3] = nrf24l01_RX_ADDR_P0_B3_DEFAULT_VAL;
        data[4] = nrf24l01_RX_ADDR_P0_B4_DEFAULT_VAL;
        
        nrf24l01_set_rx_addr(data, 5, 0);
    }
    
    if(rx_addr_p1 != NULL)
        nrf24l01_set_rx_addr(rx_addr_p1, 5, 1);
    else
    {
        data[0] = nrf24l01_RX_ADDR_P1_B0_DEFAULT_VAL;
        data[1] = nrf24l01_RX_ADDR_P1_B1_DEFAULT_VAL;
        data[2] = nrf24l01_RX_ADDR_P1_B2_DEFAULT_VAL;
        data[3] = nrf24l01_RX_ADDR_P1_B3_DEFAULT_VAL;
        data[4] = nrf24l01_RX_ADDR_P1_B4_DEFAULT_VAL;
        
        nrf24l01_set_rx_addr(data, 5, 1);
    }
    
    data[0] = rx_addr_p2;
    nrf24l01_set_rx_addr(data, 1, 2);
    
    data[0] = rx_addr_p3;
    nrf24l01_set_rx_addr(data, 1, 3);
    
    data[0] = rx_addr_p4;
    nrf24l01_set_rx_addr(data, 1, 4);
    
    data[0] = rx_addr_p5;
    nrf24l01_set_rx_addr(data, 1, 5);
    
    if(tx_addr != NULL)
        nrf24l01_set_tx_addr(tx_addr, 5);
    else
    {
        data[0] = nrf24l01_TX_ADDR_B0_DEFAULT_VAL;
        data[1] = nrf24l01_TX_ADDR_B1_DEFAULT_VAL;
        data[2] = nrf24l01_TX_ADDR_B2_DEFAULT_VAL;
        data[3] = nrf24l01_TX_ADDR_B3_DEFAULT_VAL;
        data[4] = nrf24l01_TX_ADDR_B4_DEFAULT_VAL;
        
        nrf24l01_set_tx_addr(data, 5);
    }
    
    data[0] = rx_pw_p0;
    nrf24l01_write_register(nrf24l01_RX_PW_P0, data, 1);
    	
    data[0] = rx_pw_p1;
    nrf24l01_write_register(nrf24l01_RX_PW_P1, data, 1);
    	
    data[0] = rx_pw_p2;
    nrf24l01_write_register(nrf24l01_RX_PW_P2, data, 1);
    	
    data[0] = rx_pw_p3;
    nrf24l01_write_register(nrf24l01_RX_PW_P3, data, 1);
    	
    data[0] = rx_pw_p4;
    nrf24l01_write_register(nrf24l01_RX_PW_P4, data, 1);
    	
    data[0] = rx_pw_p5;
    nrf24l01_write_register(nrf24l01_RX_PW_P5, data, 1);
    	
    if((config & nrf24l01_CONFIG_PWR_UP) != 0)
        nrf24l01_power_up_param(opt_rx_active_mode, config);
    else
        nrf24l01_power_down_param(config);
    

    }

Reply
  • Hi Hakon, I found code for the nRF24L01 on the web, written by Brennen Ball. I had to make a few changes port the code to the TI microcontroller but most of the original code is still used. Thanks, Al

    void nrf24l01_initialize_debug(bool rx, unsigned char p0_payload_width, bool enable_auto_ack) { unsigned char config; unsigned char en_aa;

    config = nrf24l01_CONFIG_DEFAULT_VAL | nrf24l01_CONFIG_PWR_UP | nrf24l01_CONFIG_CRCO;
    
    if(enable_auto_ack != false)
        en_aa = nrf24l01_EN_AA_ENAA_P0;
    else
        en_aa = nrf24l01_EN_AA_ENAA_NONE;
    
    if(rx == true)
        config = config | nrf24l01_CONFIG_PRIM_RX;
        
    nrf24l01_initialize(config, 
                        true,
                        en_aa, 
                        nrf24l01_EN_RXADDR_DEFAULT_VAL, 
                        nrf24l01_SETUP_AW_DEFAULT_VAL, 
                        nrf24l01_SETUP_RETR_DEFAULT_VAL, 
                        nrf24l01_RF_CH_DEFAULT_VAL, 
                        nrf24l01_RF_SETUP_DEFAULT_VAL,  
                        NULL, 
                        NULL, 
                        nrf24l01_RX_ADDR_P2_DEFAULT_VAL, 
                        nrf24l01_RX_ADDR_P3_DEFAULT_VAL, 
                        nrf24l01_RX_ADDR_P4_DEFAULT_VAL, 
                        nrf24l01_RX_ADDR_P5_DEFAULT_VAL, 
                        NULL, 
                        p0_payload_width, 
                        nrf24l01_RX_PW_P1_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P2_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P3_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P4_DEFAULT_VAL, 
                        nrf24l01_RX_PW_P5_DEFAULT_VAL);  }
    

    void nrf24l01_initialize(unsigned char config, unsigned char opt_rx_active_mode,
    unsigned char en_aa, unsigned char en_rxaddr, unsigned char setup_aw, unsigned char setup_retr, unsigned char rf_ch, unsigned char rf_setup, unsigned char * rx_addr_p0, unsigned char * rx_addr_p1, unsigned char rx_addr_p2, unsigned char rx_addr_p3, unsigned char rx_addr_p4, unsigned char rx_addr_p5, unsigned char * tx_addr, unsigned char rx_pw_p0, unsigned char rx_pw_p1, unsigned char rx_pw_p2, unsigned char rx_pw_p3, unsigned char rx_pw_p4, unsigned char rx_pw_p5) { unsigned char data[5];

    data[0] = en_aa;
    nrf24l01_write_register(nrf24l01_EN_AA, data, 1);
    
    data[0] = en_rxaddr;
    nrf24l01_write_register(nrf24l01_EN_RXADDR, data, 1);
    
    data[0] = setup_aw;
    nrf24l01_write_register(nrf24l01_SETUP_AW, data, 1);
    
    data[0] = setup_retr;
    nrf24l01_write_register(nrf24l01_SETUP_RETR, data, 1);
    
    data[0] = rf_ch;
    nrf24l01_write_register(nrf24l01_RF_CH, data, 1);
    	
    data[0] = rf_setup;
    nrf24l01_write_register(nrf24l01_RF_SETUP, data, 1);
    	
    if(rx_addr_p0 != NULL)
        nrf24l01_set_rx_addr(rx_addr_p0, 5, 0);
    else
    {
        data[0] = nrf24l01_RX_ADDR_P0_B0_DEFAULT_VAL;
        data[1] = nrf24l01_RX_ADDR_P0_B1_DEFAULT_VAL;
        data[2] = nrf24l01_RX_ADDR_P0_B2_DEFAULT_VAL;
        data[3] = nrf24l01_RX_ADDR_P0_B3_DEFAULT_VAL;
        data[4] = nrf24l01_RX_ADDR_P0_B4_DEFAULT_VAL;
        
        nrf24l01_set_rx_addr(data, 5, 0);
    }
    
    if(rx_addr_p1 != NULL)
        nrf24l01_set_rx_addr(rx_addr_p1, 5, 1);
    else
    {
        data[0] = nrf24l01_RX_ADDR_P1_B0_DEFAULT_VAL;
        data[1] = nrf24l01_RX_ADDR_P1_B1_DEFAULT_VAL;
        data[2] = nrf24l01_RX_ADDR_P1_B2_DEFAULT_VAL;
        data[3] = nrf24l01_RX_ADDR_P1_B3_DEFAULT_VAL;
        data[4] = nrf24l01_RX_ADDR_P1_B4_DEFAULT_VAL;
        
        nrf24l01_set_rx_addr(data, 5, 1);
    }
    
    data[0] = rx_addr_p2;
    nrf24l01_set_rx_addr(data, 1, 2);
    
    data[0] = rx_addr_p3;
    nrf24l01_set_rx_addr(data, 1, 3);
    
    data[0] = rx_addr_p4;
    nrf24l01_set_rx_addr(data, 1, 4);
    
    data[0] = rx_addr_p5;
    nrf24l01_set_rx_addr(data, 1, 5);
    
    if(tx_addr != NULL)
        nrf24l01_set_tx_addr(tx_addr, 5);
    else
    {
        data[0] = nrf24l01_TX_ADDR_B0_DEFAULT_VAL;
        data[1] = nrf24l01_TX_ADDR_B1_DEFAULT_VAL;
        data[2] = nrf24l01_TX_ADDR_B2_DEFAULT_VAL;
        data[3] = nrf24l01_TX_ADDR_B3_DEFAULT_VAL;
        data[4] = nrf24l01_TX_ADDR_B4_DEFAULT_VAL;
        
        nrf24l01_set_tx_addr(data, 5);
    }
    
    data[0] = rx_pw_p0;
    nrf24l01_write_register(nrf24l01_RX_PW_P0, data, 1);
    	
    data[0] = rx_pw_p1;
    nrf24l01_write_register(nrf24l01_RX_PW_P1, data, 1);
    	
    data[0] = rx_pw_p2;
    nrf24l01_write_register(nrf24l01_RX_PW_P2, data, 1);
    	
    data[0] = rx_pw_p3;
    nrf24l01_write_register(nrf24l01_RX_PW_P3, data, 1);
    	
    data[0] = rx_pw_p4;
    nrf24l01_write_register(nrf24l01_RX_PW_P4, data, 1);
    	
    data[0] = rx_pw_p5;
    nrf24l01_write_register(nrf24l01_RX_PW_P5, data, 1);
    	
    if((config & nrf24l01_CONFIG_PWR_UP) != 0)
        nrf24l01_power_up_param(opt_rx_active_mode, config);
    else
        nrf24l01_power_down_param(config);
    

    }

Children
  • You're pushing alot of arguments into the init function "nrf24l01_initialize". I would strongly recommend using a pointer to a struct to pass to the function instead. This will make the code alot more readable.

    Is define nrf24l01_TX_ADDR_Bx_DEFAULT_VAL equal to nrf24l01_RX_ADDR_P0_Bx_DEFAULT_VAL defines? The TX_ADDR must be equal to PIPE0 in order for the autoacking to work.

  • I simplified the code so that only two registers are modified during configuration: CONFIG and RX_PW_P0. All other registers are their default values. TX_ADDR and RX_ADDR_P0 should be 0xE7E7E7E7E7. I still get the same results; no ACK. Do you know where I can find generic C code for the nRF24L01+ that I can try with the TI microcontroller? Thanks, for your help.

Related