Arduino Fio as SPI slave with ANT+ nRF24AP2

Hi,

I'm trying to get an Arduino Fio running as a synchronous SPI slave of Nordic Semis ANT+ nRF24AP2 transciever chip:

http://www.thisisant.com/images/Resources/PDF/nrf24ap2%20product%20specification.pdf

Although there are a couple of docs around on how to achieve that, I'm lost. My information basis is

Following these docs and despite having tried hard, I have not yet managed to get Byte Sync SPI running. Wiring is as follows:

AP2 - FIO
SOUT - MOSI
SIN - MISO
SCLK - SCK
SEN - GPIO Interrupt 1 (D3) (to account for AP2 anomaly)
SRDY - GPIO (D7)
SMSGRDY - GPIO (D6)
RESET - GPIO (D4)

Moreover, GPIO D5 is connected to D10 (SS), such that I can account for the SEN bug manually. This is the code I'm running:

    #include <SPI.h>

    // specifies messages and events
      #include "nrf24ap2.h"
  
    void SlaveInit(void) {
      // Set MISO output, all others input
      pinMode(SCK_PIN, INPUT);
      pinMode(MOSI_PIN, INPUT);
      pinMode(MISO_PIN, OUTPUT);
      pinMode(SS_PIN, INPUT);          
      pinMode(resetPin, OUTPUT);       

    // Connect:

    /** 1. set up SPI */    
       // Implements LSBFIRST, SPI_MODE3, SPI_CLOCK_DIV16
       SPCR = B11001101;
    
    /** 2. PORTSEL=1 SFLOW=0 RESET=1 SRDY=1 MSGRDY=1 */    
    // portsel and sflow are hard-wired to correct values
    digitalWrite(resetPin, HIGH);
    digitalWrite(srdyPin, HIGH);
    digitalWrite(smsgrdyPin, HIGH);    
    
    /** 3. wait(300μs) */    
    delay(300);   
    
    /** 4. RESET = 0 */    
    digitalWrite(resetPin, LOW);    
    
    /** 5. wait(300μs) */    
    delay(300);
    
    /** 6. RESET = 1 */
    //reset done
    digitalWrite(resetPin, HIGH);        
    
    /** 7. wait(>2ms) */    
    delay(20);    
    
    /** 8. enable SPI */    
    SPI.begin(); // hello, SPI bus
    Serial.println("Finished Reset.");           

    // PROGRAM STOPS HERE =( - infinite loop?
    byte x = SPI.transfer (0); // get response    
     
    if (x == 0xA5) {
        // peripheral is alive
        Serial.print("Hello ANT! - Message ANT - Host: ");                   
        Serial.println(x);                   
    } else if (x == 0xA4)  {              
        Serial.print("Hello ANT! - Message Host - ANT: ");                                    
        Serial.println(x);  
    } else {
        Serial.print("Unknown message: ");                                    
        Serial.println(x);                
    }      
}
    
    // infinite loop in while-part =(
    char spi_transfer(volatile char data)   {
        SPDR = data;			  // Start the transmission

    // Wait for the end of the transmission
    while (!(SPSR & (1<<SPIF)));
    return SPDR;			  // return the received byte
  }

    void setup()  {
      Serial.begin(57600);      
    
      // define pin modes       
      pinMode(smsgrdyPin, OUTPUT);                 
      pinMode(srdyPin, OUTPUT);  
  
      // SEN line cannot be used for SPI’s SSEL as it is released at the beginning of the last byte in a transaction rather 
      // than one clock cycle after the last bit. By the SPI standard, the slave receiving 
      // this signal should immediately abandon the transaction and tri-state the MISO line. 
      // In practice this means that SPI hardware will not be able to send or receive the
      // ANT protocol checksum byte with this configuration.  
     
      // SEN is connected to interrupt 3  
      pinMode(ssInterruptPin, INPUT);
      attachInterrupt(1, slaveSelectInterrupt, FALLING);
      
      // delayed SEN output via dout 5      
      pinMode(ssOutPin, OUTPUT);

      // fix low for now
      digitalWrite(ssOutPin, LOW);
      
      SlaveInit();           
    }
    
    // service routine call has not yet happend =(
   void slaveSelectInterrupt() { 
       Serial.println("Interrupt: Received FALLING SS");
       // wait for last byte received and set SS to high
   }    
       
    void loop() {
       // ANT_rxHandler(); // one day =)    
}

What am I doing wrong? As I'm pretty stuck at the moment I would appreciate any ideas of you guys.

This is not your full code, is it? Where do you have the definition of resetPin for example.

Don't use the Serial inside an interrupt handler. This will no work.

    /** 3. wait(300?s) */    
    delay(300);

This waits for 300ms not 300us.

You enable the SPI interrupt but you don't have an interrupt service routine.

You write to the SPDR when reading a value. Although this is correct in master mode it may destroy a read value if in slave mode.

Hi pylon,

many thanks. You're right, for sake of clarity I left out some bits of the code, e.g., defines. If this matters let me know and I will totally provide it.

I know I'm waiting too long, will reduce. During reset-sequence it should not matter.

You enable the SPI interrupt but you don't have an interrupt service routine.

How can I specify an ISR for SPI?

You write to the SPDR when reading a value. Although this is correct in master mode it may destroy a read value if in slave mode.

What would be the better alternative?

Many thanks,

twelve02

How can I specify an ISR for SPI?

ISR(SPI_STC_vect) {
  // do you interrupt stuff here
}

What would be the better alternative?

Just don't write to the register:

char spi_read()   {
    // Wait for the end of the transmission
    while (!(SPSR & (1<<SPIF)));
    return SPDR;			  // return the received byte
  }

or use the interrupt handler as above but for your case this is probably not necessary.

Any progress on this?
I'm trying to achieve the same but still no luck.

What I noticed in your code, anyway, is that after you set up the arduino SPI as a slave you then call SPI.begin(), which efectively reconfigures the SPI again as a master, so I find that a bit confusing.

Yes, progress!

Didn't manage the SPI though... solution now uses async mode and hardware UART (which is a bit sad as it eats up Arduino's USB lines). Important bit is a decent hardware reset on the nRF24AP2, as it freezes when config goes wrong.

Please let me know whether you have specific questions.

Best

Ok, I'll abandon SPI, I think I'll be ok with that.
In arduino nano is not possible to use the serial monitor while using the UART, am I right? how do you debug your code then?

What is the wiring you are finally using? I suppose TXD -> RX0 & RXD -> TX1, and then a line for the AP2 reset but, where do you connect pin 17 (RTS/SEN), 6(SUSPEND) & 7(SLEEP)of the AP2?

Are you using a logic level converter from 5v to 3.3v or simply a voltage divider with a couple of resitors?

Thanks!!

I also abandoned SPI ideas early, especially since on my board is was already used at both sides (one Ethernet and one RF). Since the D0-D1 Serial is used for monitoring, you may want to use SoftwareSerial, apparently in 1.0 it have become better and standard library. I plan to do that, but didn't yet start that part of my project, so feedback is welcome.

Any more info about the wireing for the AP2 chip??

Thanks!

Any news on your projects?
did you see these libraries?

ANTPlus_Arduino