SparkFun Forums 

Where electronics enthusiasts find answers.

All things pertaining to wireless and RF links
By ssaguiar
#32954
Hi to all.

I changed my tx circuit and, now, I use a pic 16f88.
It's connected as :
Code: Select all
// Control and SPI Pin defines ////////////////////////////////////// 
#byte   PORTB             = 0x06
#bit    CE                = PORTB.6 // output Chip enable to nRF24L01 CE
#bit    CSN               = PORTB.2 // output Chip Select to nRF24L01 CSN
#bit    SCK               = PORTB.5 // serial clock output to nRF24L01 SCK 
#bit    MOSI              = PORTB.3 // serial data out to nRF24L01 MOSI
#bit    MISO              = PORTB.4 // serial data in from nRF24L01 MISO
#bit    IRQ               = PORTB.0 // input valid TX/RX from nRF24L01 IRQ
The circuit of the Rx is based on pic 16f877 as:
Code: Select all
#bit    CE                = PORTC.1 // output Chip enable to nRF24L01 CE
#bit    CSN               = PORTC.2 // output Chip Select to nRF24L01 CSN
#bit    SCK               = PORTC.3 // serial clock output to nRF24L01 SCK 
#bit    MOSI              = PORTC.5 // serial data out to nRF24L01 MOSI
#bit    MISO              = PORTC.4 // serial data in from nRF24L01 MISO
#bit    IRQ               = PORTC.0 // input valid TX/RX from nRF24L01 IRQ
And this is the spi.c include file:
Code: Select all
/*******************************************************************/
//
//  Function: SPI_RW
//
//  Description:
//  Writes one byte to nRF24L01, and return the byte read
//  from nRF24L01 during write, according to SPI protocol
/*******************************************************************/

int SPI_RW (int byte)
{
    int bit_ctr, byte2;
    byte2 = 0;
    #ifndef _TX
    printf ("Byte: %X - ", byte);
    #endif
    for (bit_ctr=0; bit_ctr<8; bit_ctr++)
    {
        byte2 <<= 1;
        MOSI = (byte & 0x80);
        SCK = 1;
        if (MISO) bit_set(byte2,0);
        SCK = 0;
        byte = (byte<<1);
    }
    #ifndef _TX
    printf("Status: %X\n\r", byte2);
    #endif
    return (byte2);
}

/*******************************************************************/
//
//  Function: SPI_Read
//
//  Description:
//  Read one byte from nRF24L01 register, 'reg'
/*******************************************************************/

int SPI_Read(char reg)
{
    int reg_val;
    
    CSN = 0;
    SPI_RW(reg);
    reg_val = SPI_RW(0);
    CSN = 1;
    
    return (reg_val);
}

/*******************************************************************/
//
//  Function: SPI_RW_Reg
//
//  Description:
//  Writes value 'value' to register 'reg'
/*******************************************************************/

int SPI_RW_Reg (char reg, char value)
{
    int status;
    
    CSN = 0;
    status = SPI_RW(reg);
    SPI_RW(value);
    CSN =1;
    
    return (status);
}

/*******************************************************************/
//
//  Function: SPI_Write_Buf
//
//  Description:
//  Writes contents of buffer '*pBuf' to nRF24L01
//  Typically used to write TX payload, Rx/Tx address
/*******************************************************************/

int SPI_Write_Buf(char reg, char *pbuf, char bytes)
{
    int status, byte_ctr;
    
    CSN = 0;
    status = SPI_RW(reg);
    
    for (byte_ctr=0; byte_ctr<bytes; byte_ctr++)
    {
        SPI_RW(*pbuf++);       
    }

    CSN = 1;
    return (status);
}


/*******************************************************************/
//
//  Function: SPI_Read_Buf
//
//  Description:
//  Reads 'bytes' #of bytes from register 'reg'
//  Typically used to read RX payload, Rx/Tx address
/*******************************************************************/

int SPI_Read_Buf(char reg, char *pBuf, char bytes)
{
char status, byte_ctr;

  CSN = 0;                                        // Set CSN low, init SPI tranaction
  status = SPI_RW(reg);                           // Select register to write to and read status byte

  for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
    pBuf[byte_ctr] = SPI_RW(0);                   // Perform SPI_RW to read byte from nRF24L01

  CSN = 1;                                        // Set CSN high again

  return(status);                                 // return nRF24L01 status byte
}

/*******************************************************************/
//
//  Function: TX_Mode
//
/*******************************************************************/

void TX_Mode(void)
{
        // Setup RX/TX address width
        SPI_RW_Reg(WRITE_REG + SETUP_AW, (TX_AW-2));        
        // Writes TX_Address to nRF24L01
        SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_LENGTH);       
        // RX_Addr0 same as TX_Adr for Auto.Ack
        SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_LENGTH);         
        // Just in case, flush TX FIFO
        SPI_RW_Reg(FLUSH_TX,0);        
        // and RX FIFO
        SPI_RW_Reg(FLUSH_RX,0);        
        // read status & clear IRQ flag's
        SPI_RW_Reg(WRITE_REG + STATUS, 0x70);        
        // Writes data to TX payload
        SPI_Write_Buf(WR_TX_PLOAD, TX_PAYLOAD, TX_PLOAD_WIDTH);         
        // Enable Auto.Ack:Pipe0
        SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);                    
        // Enable Pipe0
        SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);                
        // 500µs + 86µs, 10 retrans
        SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a);        
        // Select RF channel 40
        SPI_RW_Reg(WRITE_REG + RF_CH, 40);        
        // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
        SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);        
        // Set PWR_UP bit, enable CRC(2 bytes) & Prim:TX. MAX_RT & TX_DS enabled   
        SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);
        
        
/*******************************************************************/
// Add a delay of 1.5ms before toggling CE high if the device was 
// in power down mode.
// This device is now ready to transmit one packet of 16 bytes 
// payload to a RX device at address '3443101001', with auto 
// acknowledgment, retransmit count of 10(retransmit delay of 
// 500µs+86µs)RF channel 40, datarate = 2Mbps with TX power = 0dBm.
}

/*******************************************************************/
//
//  Function: RX_Mode
/*******************************************************************/
        
        void RX_Mode(void)
        {
        // Setup RX/TX address width
        SPI_RW_Reg(WRITE_REG + SETUP_AW, (TX_AW-2));        
        // Use the same address on the RX device as the TX device
        SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_LENGTH);        
        // Just in case, flush TX FIFO
        SPI_RW_Reg(FLUSH_TX,0);        
        // and RX FIFO
        SPI_RW_Reg(FLUSH_RX,0);        
        // read status & clear IRQ flag's
        SPI_RW_Reg(WRITE_REG + STATUS, 0x70);        
        // Enable Auto.Ack:Pipe0
        SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);        
        // Enable pipe0
        SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);        
        // 250µs+86µs, 10 retrans...
        SPI_RW_Reg(WRITE_REG + SETUP_RETR,0x0a);        
        // Select RF channel 40
        SPI_RW_Reg(WRITE_REG + RF_CH, 40);        
        // Select same RX payload width as TX Payload width  
        SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);        
        // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR    
        SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);                 
        // Set PWR_UP bit, enable CRC(2 bytes) & Prim:RX. RX_DR enabled
        SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);           
}

/*******************************************************************/
//
//  Function: PWR_DWN_Mode
//
//  Power down the nrf24l01 module.
//
/*******************************************************************/
void PWR_DWN_Mode(void)
{
   SPI_RW_Reg(WRITE_REG + CONFIG, 0x00);// Power down...
}
The tx start code is:
Code: Select all
       CE = 0;
       TX_Mode();
       // This device is now ready to transmit one packet of 16 bytes 
       // payload to a RX device at address '3443101001', with auto 
       // acknowledgment, retransmit count of 10(retransmit delay of 
       // 500µs+86µs)RF channel 40, datarate = 2Mbps with TX power = 0dBm.

       delay_ms (2);// Add a delay of 2ms before setting CE high if the 
                    // device was in power down mode.
       CE = 1;      // Set CE pin high to enable TX device
       delay_ms(5); // Wait till all TX done (could pool register or use int pin...).
       CE = 0;      // Finish TX.
       //PWR_DWN_Mode();// Sleep, baby...
       delay_ms(2000);
And the Rx start code is:
Code: Select all
   CE   = 0;
   RX_Mode();
   //  This device is now ready to receive one packet of 16 bytes 
   // payload from a TX device sending to address '3443101001', 
   // with auto acknowledgment, retransmit count of 10, RF channel 
   // 40 and datarate = 2Mbps.
   delay_ms (2);// Add a delay of 2ms before setting CE high if the 
                // device was in power down mode.
   CE = 1;      // Set CE pin high to enable RX device

   while(1)
   {
        while(IRQ);
        printf("Received data...\n\r");
        // Flush RX FIFO
        SPI_RW_Reg(FLUSH_RX,0);        
        // Read status & clear IRQ flag's
        SPI_RW_Reg(WRITE_REG + STATUS, 0x70);     
   }
In the Rx part, I receive this stuff when init (in hiperteminal):
Code: Select all
Byte: 23 - Status: 0E
Byte: 03 - Status: 08
Byte: 2A - Status: 0E
Byte: 34 - Status: 08
Byte: 43 - Status: 08
Byte: 10 - Status: 08
Byte: 10 - Status: 08
Byte: 01 - Status: 08
Byte: E1 - Status: 0E
Byte: 00 - Status: 08
Byte: E2 - Status: 0E
Byte: 00 - Status: 08
Byte: 27 - Status: 0E
Byte: 70 - Status: 08
Byte: 21 - Status: 0E
Byte: 01 - Status: 08
Byte: 22 - Status: 0E
Byte: 01 - Status: 08
Byte: 24 - Status: 0E
Byte: 0A - Status: 08
Byte: 25 - Status: 0E
Byte: 28 - Status: 08
Byte: 31 - Status: 0E
Byte: 10 - Status: 08
Byte: 26 - Status: 0E
Byte: 0F - Status: 08
Byte: 20 - Status: 0E
Byte: 0F - Status: 08
I still can't get it to work ! I'm getting old, very old...

Can somebody tell me if the init code for tx and rx (TX_Mode routine and
RX_Mode routine) are correct? And the SPI_RW routine?
The TX_mode and the RX_Mode are based on the firmware from Nordic.

Please, help...

Thanks to all for your patience.

Sergio
By lucicop
#32965
First make sure that your hardware is ok. Then make sure that you have configured correctly the interface pins to the nRF, paying much attention to the alternate function of those pins. Maybe you need to disable some peripherals (for example the analog comparator needs to be explicitly disabled, or else the pins will behave different from what you would expect). I see 16F88 has SPI hardware, why don't you use that ?
By ssaguiar
#32975
Thanks lucicop.

I am using bit-bang because I want to learn how to do it and also because I saw in several posts that it´s a bit more tricky to use it.
The other reason is because I will use a clock of 32 KHz, after all is Ok, and I don´t know it hardware spi will work with a clock so low.

My start code is :
Code: Select all
   set_tris_a(00000000);
   set_tris_b(00010001);               // 1 --> Input 0 --> output
   port_b_pullups(FALSE);              //Don't use port B pullups
   setup_adc_ports(NO_ANALOGS);        //Don't use Analog converter
   setup_adc(ADC_OFF);                 //  "    "      "      "    "
   setup_spi(FALSE);                   //No SPI
   setup_timer_1(T1_DISABLED);         //Disable Timer 1
   setup_timer_2(T2_DISABLED,0,1);     //Disable Timer 2
   setup_comparator(NC_NC_NC_NC);      //Disable Comparators
   setup_vref(FALSE);                  //Disable Voltage references
I will use this code, after all is working :
Code: Select all
   while(1)
   {
       setup_oscillator(OSC_31KHZ | OSC_INTRC);
       restart_wdt();
       sleep();
       IOFS=0; 
       setup_oscillator(OSC_2MHZ | OSC_INTRC);
       while(!IOFS){};// Wait oscilator stabilize...
       delay_ms(1);
       CE = 0;
       TX_Mode();

       // This device is now ready to transmit one packet of 16 bytes 
       // payload to a RX device at address '3443101001', with auto 
       // acknowledgment, retransmit count of 10(retransmit delay of 
       // 500µs+86µs)RF channel 40, datarate = 2Mbps with TX power = 0dBm.

       delay_ms (2);// Add a delay of 2ms before setting CE high if the 
                    // device was in power down mode.
       CE = 1;      // Set CE pin high to enable TX device
       delay_ms(5); // Wait till all TX done (could pool register or use int pin...).
       CE = 0;      // Finish TX.
       PWR_DWN_Mode();// Sleep, baby...
       delay_ms(2000);
   }
With this, I will economize more battery (I saw this in a post at CCS, if I´m not wrong - about sleeping at 32KHz and waking up at 2 MHz).

Sergio