Thursday, January 9, 2014

nrf24l01+ control with 3 ATtiny85 pins

Nrf24l01+ modules are a cheap and low-power option for MCU wireless communication.  Libraries are available for Arduino, and for arduino compatible MCUs like the ATTiny85.  Controlling the nrf modules usually requires power plus 5 pins - CE, CSN, SCK, MOSI, & MISO.  With pin-limited MCUs like the ATtiny85, 5 pins is a lot to tie up.  On something like the Digispark, with PB3 and PB4 hard-wired to USB+ and USB-, using the nrf24l01+ modules might seem impossible.  Another issue is that although the nrf inputs are 5v tolerant, Vcc must be between 1.9 and 3.6V.  I've designed a simple solution to provide 3V power as well as control the modules with just 3 of the pins on the ATtiny85.

For powering the nrf24l01+ module, a 3.3v regulator could be used, but a cheaper and simpler way is to drop a 5V supply to 3V using a 20mA-rated red led.  Most red LEDs have a forward voltage drop between 1.8 and 2.2V, leaving 3.2-2.8V for the nrf, which is well within the 1.9-3.6V requirement.

Controlling CE without using a pin on the AVR is also easy: just tie it high.  In my setup function, I set Mirf.cePin = 7 as a dummy since the tiny85 only has pins 0-6.  I later commented out the digitalWrite calls in Nrf24l::ceHi() and ceLow(), and removed the Mirf.cePin line from setup() which cut down on the size of my compiled sketch.

I initially thought the CSN line could be tied low, but when I tried it my test sketch was not getting a valid status back from the nrf module.  I also found section 8.3.1 of the datasheet: "Every new command must be started by a high to low transition on CSN."  So in order to control the nrf with just 3 pins, CSN needs to be multiplexed with one (or more) of SCK, MOSI, or MISO.  After a few different ideas, I came up with this circuit:
When SCK on the ATtiny85 goes high for several microseconds, C1 will charge through R1 and bring CSN high.  If SCK is brought low for several microseconds before being used to clock the SPI data, C1 will discharge through D1 and bring CSN low.  High pulses on SCK of less than a few microseconds during communication with the nrf won't last long enough to charge C1, so CSN will stay low.

To support the multiplexed SCK/CSN, I modified Mirf.cpp as follows:
void Nrf24l::csnHi(){
PORTB |= (1<<PINB2); // SCK->CSN HIGH
delayMicroseconds(64);  // allow csn to settle
}

void Nrf24l::csnLow(){
PORTB &= ~(1<<PINB2);  // SCK->CSN LOW
delayMicroseconds(8);  // allow csn to settle
}

The circuit still worked with a 32us delay in csnHi and 8us in csnLow, but I doubled those values to have a good safety margin.  The delays could be reduced with a smaller capacitor for C1.  Going lower than .01uF could risk CSN going high during the high clock pulses of SCK.

When connecting the nrf module to a tiny85, connect MISO(pin7) on the module to MOSI/DI(PB0), and not MISO/DO(PB1).  Here's the connections required:
nrf module  ATtiny85 pin
SCK(5)      PB2 (physical pin 7)
MOSI(6)     PB1 (physical pin 6)
MISO(7)     PB0 (physical pin 5)

I also changed TinyDebugSerial.h to define TINY_DEBUG_SERIAL_BIT 5, and connected pb5 to the Rx line of my ttl serial module.

Finally, here's my test sketch.  When it runs, it reports a status of 'E', which is the reset value of the status register according to the datasheet.  If you connect things wrong it will usually report 0 or FF.
#include <SPI85.h>
#include <Mirf.h>
#include <MirfHardwareSpi85Driver.h>

void setup()
{
  Serial.begin(115200);

  Mirf.spi = &MirfHardwareSpi85;
  Mirf.init();
}

void loop()
{
  uint8_t nrfStatus;
  delay(3000);
  Serial.print("\nMirf status: ");
  nrfStatus = Mirf.getStatus();
  // do back-to-back getStatus to test if CSN goes high
  nrfStatus = Mirf.getStatus();
  Serial.print(nrfStatus, HEX);
}

Update 2014/06/12:
I've noticed that power usage on the nRF modules shoots up if I leave any inputs (CSN, SCK, MOSI) floating.  With my circuit above CSN will never float, but SCK and MOSI should be pulled high or low when not in use, especially for battery-powered devices.

Update 2014/10/04:
I've written another post titled nRF24l01+ reloaded with more details on controlling these modules.

Update 2015/05/23:
I've figured out a way to control nRF modules with just 2 pins using custom bit-banged SPI routines.

128 comments:

  1. Brilliant! This opens up all sorts of possibilities. Need to resurrect that tray of ATtiny chips ...

    ReplyDelete
  2. Very Clever, i was just thinking the same of dropping off some wires, but, i was so lazy to think of it :-)

    I will try your solution with my digispark

    ReplyDelete
    Replies
    1. I tested the circuit with a digispark, so you should have no problems.

      Delete
    2. I've duplicated this circuit with a digispark. I'll update after end to end testing.

      Delete
  3. It's probably worth mentioning that tying CE high throws away the ability to switch to low-power TX modes, which may be a problem if you're running on batteries. Otherwise, clever hack!

    ReplyDelete
    Replies
    1. I don't think low power modes are completely lost. Looking at the datasheet, and from my testing it can go into low power mode with CE high. The side benefit of using the red LED to drop the voltage is that it is a simple power usage indicator. When first powered up the module uses ~10mA and the LED glows bright. After initialization with nothing to transmit and rx mode off, the LED is quite dim, indicating well under 1mA of power consumption. Going from memory, I think there are a few low power modes, so possibly the lowest power mode may require CE low.

      Delete
    2. Hi, great concept. I was also trying to come up with a solution to multiplex pins on my ATTiny85 to use the nRF24L01+. I was going to multiplex SCK and CE with a low-pass filter on CE so one could keep SCK high when idle, and the cap would keep CE high during transfers. Your solution would free another pin though as compared to my idea which still has a discrete CSN pin.

      Have you confirmed that the PTX and PRX modes both work properly using your circuit? According to the datasheets, one must make a low-hi-low pulse of >= 10us to initiate a transmission.. I'm curious as to how keeping CE tied high still allows one to transmit. How is the transfer initiated (is it by totally powering down the nRF24L01+ with a PWR_UP = 0 command, followed by a PWR_UP = 1, or is it sufficient to just set PRIM_RX = 0, with CE already high, after loading the TX FIFO)?

      The state diagrams in the datasheet, and support replies I have gotten from Nordic Semi, suggest that the low-hi CE transition is essential to initiating TX mode.


      Delete
    3. Tieing CE high isn't my idea - I saw it on another NRF example circuit when I was researching how to use them. It's been a few months since I was playing with them, but what I remember is you HAVE to toggle CSN - when tied low, it would only respond to the first command. After I wrote aspspi I was able to figure out that it is only after CSN goes high that the NRF processes the SPI command. Not only that, but for a register write, you can include a bunch of junk bytes between the command and the data you want to write, so for a single byte register it will only write the last byte of the SPI sequence.
      I agree the NRF datasheet can be a bit confusing as to the combinations of CE, CSN and register settings. If you read the datasheet from beginning to end (perhaps more than once) you can figure it out. After I figured out CE can be tied high and CSN has to be toggled, I re-read the manual and realized 6.1.6 does confirm what I found. It specifies a 10us high pulse to empty one level of the TX fifo (normal mode) or hold CE high to empty all levels of the TX fifo.
      Its also clear from the table (15) that for power down mode the state of CE doesn't matter - only the PWR_UP register has to be set to 0.
      p.s. it's even possible to toggle CSN with just a resistor and capacitor attached to SCK. SCK needs to be held low for a longer period, so I think it's easier with a diode.

      Delete
    4. Aha, I see what you mean - Table 15, "nRF24L01+ main modes" makes it all clear.

      So in the state diagram, if CE is held high the device can still go into Standby-II mode whenever there's no TX FIFO data, which saves almost as much power as Standby-I (not a big deal). Thanks!

      Delete
  4. Absolutely !!! Fantastic Thanks for Sharing Ralph....

    ReplyDelete
  5. I'm sure it's an stupid question, but PB0 (physical pin 5) it's the only one in Attiny with HW PWM and I need to use it in one of my projects involving attiny plus nrf24l01.
    Is it possible to use physical pin 2 or 3 in attiny to connect MISO(7) from the nrf24l01 ?

    Very ingenious trick by the way! Be sure I'll be using it !

    ReplyDelete
    Replies
    1. Pin 5 is USI data in, but if you use bitbang (software) SPI instead of USI, then you should be fine.

      Delete
  6. This comment has been removed by a blog administrator.

    ReplyDelete
  7. Have you transmitted anything between two modules? I'm interested in getting one up and talking to another Arduino but I'm not getting anywhere. I got the E status back but I haven't been able to communicate with another module. Any help would be great.

    Thanks.
    Steve

    ReplyDelete
    Replies
    1. Did you make sure they're both set to the same channel?
      If you use the red LED to drop the power like I show in the circuit, it gets quite dim when the NRF is not receiving because power use drops from ~10mA in active receive or transmit mode to <1mA idle. The sample sketch I posted does not put the module in receive mode. If you've think you've it set to receive mode but the LED is not glowing bright, then it probably isn't really in receive mode.

      Delete
    2. All I have managed to do was get the E status from the sketch you included. I'm not very familiar with the MIRF library and haven't been able to get it to run on my mega with any reliability let alone transmit from the attiny. There has to be something basic I'm doing wrong. I have gotten the nrf library to work and transmit.

      Delete
    3. You won't be able to get the same library working for an ATMega and an ATtinyx5 since the the x5 doesn't have hardware SPI - the SPI communications is done using USI instead.
      Since you're getting the E status result back, the communication is working, so it's just a matter of programming the nrf it to transmit. At a minimum that means you need to write the tx payload (W_TX_PAYLOAD command), and set the PWR_UP of register address 0 to 1. See sections 8.3 and 9 of the datasheet for more details.

      Delete
  8. Hey Ralph,

    I had downloaded the attiny core from here: https://code.google.com/p/arduino-tiny/ and the mirf/spi85 libraries here: https://github.com/samuelclay/doormonitor

    everything compiles fine before modifying the .cpp file, but when i do your modification, I receive the folllowing errors:

    /Applications/Arduino.app/Contents/Resources/Java/libraries/Mirf/Mirf.cpp:288: error: stray '\302' in program
    /Applications/Arduino.app/Contents/Resources/Java/libraries/Mirf/Mirf.cpp:288: error: stray '\240' in program
    /Applications/Arduino.app/Contents/Resources/Java/libraries/Mirf/Mirf.cpp:293: error: stray '\302' in program
    /Applications/Arduino.app/Contents/Resources/Java/libraries/Mirf/Mirf.cpp:293: error: stray '\240' in program
    /Applications/Arduino.app/Contents/Resources/Java/libraries/Mirf/Mirf.cpp:294: error: stray '\302' in program
    /Applications/Arduino.app/Contents/Resources/Java/libraries/Mirf/Mirf.cpp:294: error: stray '\240' in program

    ReplyDelete
    Replies
    1. Those look like unicode character escapes. I'd look at it in an editor like vim to see where you have accidentally inserted any non-ascii characters.

      Delete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Thanks Ralph for sharing.

    I am just starting out trying to it to work on my digispark. Which pins did you use when you tested it with your digi? I am trying to figure out which pins on the nrf24l01 to solder to the pins of the digi,

    Thank you in advance

    ReplyDelete
    Replies
    1. I used jumper wires between the header pins instead of soldering - much easier to fix if you make a wrong connection.
      Connect PB0(DI) to MISO, PB1(DO) to MOSI, and PB2 to SCK.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. Hi Ralph,

      Thanks for replying. When looking at your diagram, I wonder what C1, D1 and D2 is, since I don't find them on the diagram on the Digispark or the nrf24l01..

      In order to make it work I need to connect PB0(DI) to MISO, PB1(DO) to MOSI, and PB2 to SCK AND make the above circuit, right?

      Do you have a github repo where the changes you mention in this post have already been made?

      Thank you in advance

      Delete
    4. They're standard schematic symbols.
      D1 is a 1N4148 diode.
      D2 is a red LED.
      C1 is a ceramic capacitor, 0.1uF (100nF)

      You are correct about the pin connections.

      I haven't re-packaged the code changes, though given the problems some people seem to be having getting it to work, I think I will clean up library, make sure it's setting the right nrf registers to both transmit and receive with CE tied high, and add it to my google code repository.

      Delete
    5. Hi Ralph,

      Thank you for taking the time to answer my newbie questions :-).

      One final question though: You said to wire PB2 to SCK, however the circuit above also mentions to connect to SCK through a 1N4148 diode. So they both need to connect to SCK?

      Thanks

      Delete
    6. Yes, PB2 connects to SCK and the diode. The other side of the diode connects to CSN and the capacitor.

      Delete
  11. This comment has been removed by the author.

    ReplyDelete
  12. Hello,
    I have found these library for the Attiny85, https://github.com/stanleyseow/attiny-nRF24L01, and I was wondering if it works the same with your circuit and changing the Mirf.cpp lines (in that case Mirf85.cpp).

    I have uploaded the example sketch that comes with that library (attiny-nRF24L01) and I get the led flashing (the one between CE and Vcc) but I am not sure if it is sending anything.

    ReplyDelete
    Replies
    1. Yes, that's the link that is in the first paragraph of my post.

      Delete
  13. Hello Ralph,

    Thanks a lot for your hack, I tried to tie the CE PIN to VCC but the modules don't work anymore. I didn't use your hack for the CSN PIN (I am using a ATMEGA328, i just needed one more pin for my project), so the CSN pin is still used as before (on D7).

    I tried the mirf library, and the maniacbug's one. The nRF won't send any data with either library (I commented out all references CE pin in the code).

    Can you help me ? Did anyone encounter this problem ?

    Thanks in advance.

    Arnaud.

    ReplyDelete
    Replies
    1. The CE pin can be used to control the transmit. When it's tied high, PWR_UP must be set in order to transmit (see my discussion above with DangerRuss).
      I have only tried the version of the Mirf library modified to use the ATtiny's USI instead of SPI. I have been planning to test the modules with an Attiny88 which has hardware SPI, but haven't got around to it yet.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. Hi Ralph, thank you for your answer.
      I got my circuit to work thanks to your help and mvdbro's answer. As mvdbro stated, I had to add :
      Nrf24_configRegister(CONFIG, mirf_CONFIG );
      before:
      Nrf24_powerUpTx(); // Set to transmitter mode , Power up

      I then managed to get your hack working with Maniacbug's RF24 library (http://maniacbug.github.io/RF24).
      I had to create a new method that replaces the "write" one. I followed the same scheme as the Mirf one.

      Method :
      http://pastebin.com/RUhug7NF

      Usage :

      //radio.stopListening(); // USELESS NOW, handled in "send()" method
      boolean sent = radio.send( dataToSend, sizeof(Data) ); // sent = true → no error, false otherwise

      Thank you again Ralph for your trick, and help.

      Delete
    4. After looking at the datasheet state diagram again (after enhancing it so I could see some of the very faint lines), this makes sense. There is no direct transition between the Rx and Tx state. It either has to go through Standby-I state by bringing CE low, or Power Down state by setting PWR_UP=0. It also supports my idea that tieing CE & CSN should work (without having to set PWR_UP=0 between Rx & Tx)

      Delete
    5. I tried this chromatix code and first it didn't work, it successfully received packets by attiny85, but couldn't send it with this send function. Then after several hours of investigation I found out that both AutoAck and CRC must be disabled on both receiver and transmitter if you want to have CE pin tied high.
      Then I tried to free CSN pin by using diode, cap and resistor but I fried my arduino mega somehow. I used arduino mega as serial link from tiny to pc.

      Delete
    6. Interesting. I'll do some more testing with AA & CRC enabled. If confirmed, that may be a reason to prefer tying CE & CSN together instead of tying CE high.

      Delete
    7. I think the issue is auto-ack, not CRC. Auto-ack requires switching between Tx and Rx, which according to the nRF state diagram requires either CE low or setting the config register PWR_UP bit to 0.
      If you need auto-ack, tying CE high is not a feasible option.

      Delete
    8. Looking at figure 16 in the datasheet (pg 43) indicates a receiver can keep CE tied high with auto-ack. Figure 10 seems to indicate that AA should work with CE high. Section 6.1.6 a. states:
      " If CE is held high all TX FIFOs are emptied and all necessary ACK and possible retransmits are car-
      ried out."
      I don't have my modules setup for testing right now, but the next time I do I'll test AA with CE tied high.

      Delete
    9. I tried again and every time I turn on CRC check, Attiny won't send when CE pin is tied high. Maybe some more modifications are necessary but this just doesn't work as it is now if CRC is enabled. Anyway, I gave up trying to use hardware CRC and implemented software CRC check instead. It's good enough for my project. I also had to change resistor value to 1K5 otherwise it didn't work for me even without CRC check. It's possible that my capacitor is not really 100nF, it's quite old.

      Delete
    10. I finally got around to testing this, and I have no problems transmitting with CE high and CRC enabled.
      I set register 1 to 0 (disable aa)
      I set register 0x11 to 2 (pipe width = 2)
      I sent a 2-byte payload (command 0xa0,1, 2)
      I set register 0 to 10 (PWR_UP, EN_CRC)
      Immediately after PWR_UP, the IRQ line went low, and then the status register 7 was 0x2e (TX_DS & RX empty)

      Delete
  14. Hi Ralph, fantastic work, I think I got my head round it !! - just one question, I want to use the nRF with an ATTiny85 in receive mode only, are there any specifics I need to consider with your code ? I intend to use 3 x 1.2v rechargables, so I would get 3.6v which is just what you were discussing in your text, can I just connect up without the LED in that case ? - Thanks in advance for your reply. Bob

    ReplyDelete
    Replies
    1. I didn't write any of the original nrf code - just the mods to mux CSN & SCK. For receive, make sure PWR_UP and PRIM_RX are set. If you're using Stefan Engelke's library that I linked to, the powerUpRx() function does this.
      For battery power, I'd go with 2x NiMH batteries instead of 3 since they are ~1.35V fully-charged. If you run the t85 at 8Mhz, it will be fine off the 2.5-2.7V from 2 batteries. It's slightly outside spec, but it will likely work fine at 8Mhz down to 2.2V where the NiMH would be close to fully drained.

      Delete
    2. Thanks Ralph, I was going to use a single 3.6v NiHM cell (PCB version) with a 78L33 regulator, looking forward to trying out the code !

      Delete
    3. HI Ralph, I got an E !! so far it all seems to work, I am going to push forward to receiving packets next. I have previously used the Nrf library for my transmitter/receiver projects, so the Mirf is a little different, I just hope i can combine a Nrf transmitter with a Mirf Receiver !! thanks again

      Delete
  15. Right, I have got a bit further, I am getting comms with the nRF board now, adapted some of the example code to give me address/channel info back from the board which I can serial print to monitor @ 19200.. I have set my pre-made TX board (which uses a 328 and RF24 lib) to the same channel and address as my new ATTiny85+nRf+Mirf lib. I am just using a small bit of code in Loop() to print out the data as it arrives... but there is nothing :(
    if(Mirf.dataReady()){
    mySerial.println("Got packet");
    Mirf.getData(data);
    for (uint8_t x=0; x<32; x++) {
    mySerial.print(data[x]);
    mySerial.print(" ");
    }
    }

    ReplyDelete
    Replies
    1. I'm guessing you call Mirf.config() earlier on in your code? It's where powerUpRx() gets called.

      Delete
    2. Thanks for your reply Ralph, I called it pretty much at the end of my setUp() code

      Delete
  16. I have also connected an LED so I can monitor when the unit is in RX, which at the moment, the LED glows bright constantly, so I guess that is correct ? I just cant see what I have done wrong, my TX board is the version with an antenna, I even have another 328+nrf+RF24 board receiving and that works perfectly !! its just my receiver that cant hear, I am even scanning all channels to see if I can see data, the address/pipe is the same as the transmitter (with the reversed bytes difference between RF24 and Mirf of course). Bob

    ReplyDelete
    Replies
    1. Check the voltage on the CE pin, and make sure it's at least 3V.
      Do you know if you have genuine nrf24l01+ modules? I've read about at least one clone chip (Si24R1). I haven't found an english datasheet for them, to check, but if they might not be identical. If your modules are old (i.e. just nrf24l01, not the + version), then that could be a problem too - I never tried to dig up the datasheet for the plain 24l01 to see if switching between tx and rx is supported with CE tied high.
      You could try tying CE low instead of high - it would mean the module wouldn't be able to transmit, but it could narrow down the problem.

      In the coming weeks I'm hoping to get my hands on a couple of the si24R1 modules, and do some in-depth testing including range - they are supposed to have higher power output than the nrf24l01.

      Delete
    2. Thanks Ralph, thats a few things for me to probe into, I spent most of the day wiring things up and getting it sort-of-working, Im glad at least I got a response back from the module, that shows its working. I saw a information dump on the RF24 library, it shows lots of data about the module, printDetails() or something, it was very useful. I didnt use the tinydebug in the end, I used softserial which seemed to work just fine.. time for more testing I think :)

      Delete
    3. I tried CE low and it made no difference, but I did find this little gem... "When you are receiving packets, CE is held high. Once you have received a packet you MUST bring CE low to disable the receiver" - so basically I have got to control the CE line with the ATTiny85, so I will be up to 4 pins used but will still have one pin left on the '85

      Delete
    4. The datasheet doesn't say that, and the stock mirf code (with CE control) doesn't bring CE low in the dataReady() method. See line 133.
      https://github.com/aaronds/arduino-nrf24l01/blob/master/Mirf/Mirf.cpp
      Short of doing full debugging on the issue, you could try tying CE & CSN. This would disable tx/rx briefly during SPI commands. This is something I tried myself, and as I remember it seemed to work, but tying CE high was simpler.

      Delete
    5. I'm guessing you read that on the sparkfun forum:
      https://forum.sparkfun.com/viewtopic.php?f=13&t=30253

      Note that later in the thread Brennan says:
      "As long as you're OK with flushing the RX FIFO after a read, though, then I see no reason you can't tie CE to VCC"

      and at the end of the thread:
      "This last sentence suggests that you don't have to leave RX mode while reading RX payload, which means that CE_pin can remain high while reading the rx payload.

      I tested this with my nrf24l01+ chip and it really is true.
      And the chip itself sets the RX_EMPTY flag in FIFO register, so there is no need to flush."

      Delete
    6. Right ok, well I have tested CE toggled from a pin (after reinstating the remmed out code in Mirf.cpp and giving Mirf.cePin a value)
      I am starting to think i've done something else wrong..
      Just to recap..
      I can write to and read from the module [tick]
      I am sending data from a RF24 source with address/channel/speed set [tick]
      I am not sure what I am doing with CRC and dynamic payload stuff [hmm]

      If the channel and address match then surely something will appear at the buffer ?

      Can you please just clarify which SPI85 and MIRF libraries I should be using, perhaps thats the problem ?

      Thanks

      Delete
    7. It certainly could be the libraries - I used the version on Stanley's github, but didn't test receive mode.
      https://github.com/stanleyseow/arduino-nrf24l01

      Delete
    8. Strange, but I get notifications when someone posts on here, but the comments dont show up !!
      I couldnt get the library to work on receive, so I found an RF24 library that someone had converted to 85 compatability, I made similar code mods as you proposed with the Mirf and up to a point it works with the hardware trick. I got the a scanner program working which tells me communications are working and I can see a transmitting node, but as yet I have not been able to get read the data thats arriving !!

      Delete
    9. Could you post a link to the RF24 library so if other people hare having problems with Mirf they can try an alternative?

      Delete
  17. https://github.com/WSUEECSEE5851213Team12/haf/tree/master/ATtiny/libraries

    I still havent yet got it working to get data out of it, although I can see the carrier signal, I will check the power etc just incase I am low on voltage

    ReplyDelete
    Replies
    1. All checked, and I just cant find anything wrong with it, I am wondering if there is some confusion over the pipe-address between tx and rx, that is the only other reason I can find that the data isnt getting through.. i'm going to build a test transmitter identical to the receiver and change the software flow, see if that will work !

      Delete
  18. Ralph, I forked the repository you linked to in your paragraph and made the changes as per your guide. The repo is here: https://github.com/bjensen/arduino-nrf24l01 please let me know if I overlooked any changes. I get a 'E' back when I use the code :-)

    ReplyDelete
  19. After a huge amount of testing I finally got it all to work on receive !!!! I used the libraries above but changed the so that I had control over CE, I am pretty sure you cant recieve unless this pin is waggled, anyway, I built CE control back in and tested with a matching TX and RX boards into tinydebug serial.. I do have one question though.... I think I am transmitting at 250kbs (0x27 sent to RF_SETUP) but when it is read back it reports as 0x26 - anyone know why ??

    ReplyDelete
    Replies
    1. Interesting. I've got a module setup with CE tied high running a constant rx loop. I'm going to play with a transmitter using interactive SPI so it's easier to do some experiments. I'm still not 100% convinced toggling CE is required for Rx mode, and even if it is, I'd like to know exactly when it has to be toggled. If I can't get it to receive with CE tied high, I'll do some more testing with CE & CSN tied together.
      Regarding RF_SETUP, 0x27 sets bit 0 which is listed as "Obsolete" in the datasheet. Bit 5 (RF_DR_LOW) is set, so that should be 250kbps. RF_PWR is 11, so it should be 0dBm transmit power.

      Delete
    2. Just got things wired up for testing. I think my modules are genuine - they have a laser etched NRF 24L01+ and a date code on them. Register 6 was 0x0f at startup, and writing 0x27 reads back as 0x27. Writing 0x26 reads back as 0x26. I'm also getting a second byte, as if it is a 2-byte register...
      avrdude> send 6 0 0 0
      >>> send 6 0 0 0
      results: 0e 0f 00 0f

      avrdude> send 0x26 0x26 0x26 0x26
      >>> send 0x26 0x26 0x26 0x26
      results: 0e 00 00 00

      avrdude> send 6 0 0 0
      >>> send 6 0 0 0
      results: 0e 26 00 26

      avrdude> send 0x26 0x27 0x27 0x27
      >>> send 0x26 0x27 0x27 0x27
      results: 0e 00 00 00

      avrdude> send 6 0 0 0
      >>> send 6 0 0 0
      results: 0e 27 01 27

      avrdude> send 0x26 0 0 0x27
      >>> send 0x26 0 0 0x27
      results: 0e 00 00 00

      avrdude> send 6 0 0 0
      >>> send 6 0 0 0
      results: 0e 27 00 27

      Delete
  20. Thanks for that Ralph, now I have it working really well on RX with CE control, it would be easy for me to just set it high in software are test again, it would be nice if it works so I can get that pin back again :) - as for the 26/27 business, I shall look more into that, sound like you modules are the same as mine. Regards

    ReplyDelete
  21. I just tested with CE high in software, seems to work - I have no idea why it didnt work before, I have been round the houses do many times changing libraries/hardware etc, I even have a batch of attiny85's that I cant program via ISP, so I am down to my last 2 working ones. I shall keep testing and see where I get to. Thanks Ralph

    ReplyDelete
    Replies
    1. Last night's testing consistently shows CE will sink current when CSN is low. I've measured >30mA draw on CE while CSN is low. Without a really stable power supply, that could cause enough of a drop in Vcc to cause all kinds of flaky behavior. I still have more testing to do. I'll probably end up doing another blog post with all the new details.

      Re programming your t85's, try reducing the SCK frequency using the -B parameter with avrdude (-B 4 is what I usually use).
      If that doesn't work, you could have messed up fuse settings, and a fuse resetter may help.
      http://www.simpleavr.com/avr/hvsp-fuse-resetter

      Delete
    2. I did some more testing on the CE current draw, and it's actually just the issue I referred to in my 2014/06/12 update. If CSN is floating, CE will draw a lot of current, so just make sure CSN doesn't float.

      Delete
    3. Here's a project using the t85 & nRF with CE tied high:
      https://github.com/solarkennedy/equail
      Here's the schematic:
      https://picasaweb.google.com/lh/photo/iOjelseBqVh6TIMGalWnQOnROep4a-1c8dwXpIi0d-0?feat=directlink

      Delete
    4. Cheers for the Info Ralph, I shall be back on it now after a weekend away !!

      Delete
  22. Have any of you guys managed to send a for example array of integers from one arduino using this library to another?

    I have no succes, regardless of the sample library I use. Can anyone please share the sample client/server program they use so I can validate that things are wired up properly. Thank you in advance

    ReplyDelete
    Replies
    1. I've been playing with the t88's lately instead of t85s - they have more IO, real SPI, and the qfp versions are cheaper than the SOIC t85's.
      I have a few things I still want to do with the code, but it works for a small transmitter powered off a coin cell, so I committed the code.
      https://code.google.com/p/nerdralph/source/browse/#svn%2Ftrunk%2Favr%2Fmirf
      It has no CE control, and the transmitter (txRf.c) works fine with CE tied high.

      One debugging tip: connect a LED (& resistor) between IRQ and Gnd. The LED will turn off when the nRF receives or transmits a packet.

      Delete
  23. I have been using the library to send and receive data using attiny85 - I am sending 544 bytes every 40ms @250kbps, everything seems to be fine, when I receive the data I recompile it into DMX data and output it as differential data on 2 pins. The ONLY difference I have made is on the transmitter side I am having to control the CE line manually (in software) rather than tieing it high, I would like a similar solution to the RX/tie-high I am doing, but this is fine for now

    ReplyDelete
  24. Bob: Could you please share the sketches your testing with? on gist.github.com for example

    ReplyDelete
    Replies
    1. I dont use github, although I can put something simple on here - there is no need for me to show all the app, I will just put up the tx/rx code

      Delete
    2. UNTESTED cut down copy of my code...

      // Data transmitter using Nrf24l01 and ATtiny85

      #include
      #include
      #include
      #include

      #define BURSTTIMER 40 // 40ms between blasts of radio data
      #define MAXPAYLOAD 32

      TinyDebugSerial mySerial = TinyDebugSerial();

      uint8_t payload[MAXPAYLOAD];
      unsigned long timeslot;

      // ATTiny85
      // RESET 1 - - 8 VCC
      // SerTX/A3/Pin3 2 - - 7 Pin2/A1/SCK
      // CE/A2/Pin4 3 - - 6 Pin1/MISO
      // GND 4 - - 5 Pin0/MOSI


      void setup(){
      mySerial.begin( 115200 );
      Mirf.spi = &MirfHardwareSpi85;
      Mirf.cePin = 4;
      Mirf.init();
      byte TADDR[] = {0xe1, 0xf0, 0xf0, 0xf0, 0xf0};
      Mirf.baseConfig = _BV(EN_CRC) | _BV(CRCO);
      Mirf.payload = 32;
      Mirf.configRegister( RF_SETUP, 0x27 );
      Mirf.channel = 0x00;
      Mirf.setTADDR(TADDR);
      Mirf.config();
      delay(1000);
      }

      void loop(void)
      {
      if (millis() - timeslot > BURSTTIMER) {
      timeslot = millis();
      for (uint8_t data = 0; data<MAXPAYLOAD; data++) {
      payload[data] = 0xff; // fill payload with dummy data
      }
      Mirf.send((byte *) payload);
      while( Mirf.isSending() ) { }
      }
      }

      Delete
    3. I am controlling CE from digitalpin 3, hence the line "Mirf.cePin = 4;" - in Mirf.cpp I have adjusted Nrf24l::Nrf24l() {} to that cePin setting has been remmed out // - this way I can set it in RX too by giving Mirf.cePin a value out of range (like 8), that way I can use the 3-fingered-toad hack above.

      Incidentally, I am running at 8mhz, I have tried it at 16mhz and tried adjusting the sclk/csn timings but decided in the end not to mess with it

      The RX code is almost identical to the TX code, dont forget these lines in setup()
      Mirf.cePin=8; // out of harms way !
      byte RADDR[] = {0xe1, 0xf0, 0xf0, 0xf0, 0xf0};
      Mirf.setRADDR(RADDR);

      and in loop() :
      while (!Mirf.dataReady());
      Mirf.getData( (uint8_t *) &payload);


      Delete
  25. I think it is beyond my reach to contribute to this discussion regarding receive mode. I will just wait patiently and see if you guys manage to get it working. I will keep an eye on this thread and I won't mind help testing on digisparks.

    ReplyDelete
    Replies
    1. They certainly can be tricky to get working. I found it easiest to start with basic communication first, then turn on things like CRC and AA.
      1: Set the register EN_AA (R01) = 0x00 to disable Enhanced ShockBurst
      2: Disable CRC CONFIG (R00) bit 3 (EN_CRC) off
      3: Set packet size RX_PW_P0 to 32 (maximum)

      Leave everything else (address width, etc) at the defaults.

      Delete
    2. In my code I have the following:
      Mirf.baseConfig = _BV(EN_CRC) | _BV(CRCO);
      Mirf.payload = 32;
      Mirf.configRegister( RF_SETUP, 0x27 );

      I am not actually sure if this is all correct, but what I am after is 250kbps on high power, with no CRC or Acknowledgements

      I have read the datasheet a few times but it just confuses the hell out of me !!

      I have a feeling that Mirf.baseConfig = _BV(EN_CRC) | _BV(CRCO) should be ~ _BV(EN_CRC) | ~_BV(CRCO) or something like that to disable the CRC stuff ???

      Delete
    3. Hi Ralph,

      Thanks for the advice.

      Have you managed to send and receive data with the information you provided in the blog post?

      Delete
    4. Yup. I was running txRf.c that I committed to my google code repository, on a battery-operated tiny88. For receiving I was using manual SPI (see my aspspi blog post). Both sender and receiver had CE tied high.
      I'm using the cheap nrf modules with the small PCB antenna, and still got decent range. I put my transmitter node on top of my wife's car in the driveway and could receive inside the house ~20m away.

      I just finished writing up some code for reliable temperature sensing using the on-die temperature sensor, and plan to add that to the transmitter node, so it will send temperature and battery level information.

      Delete
  26. Hi Ralph, what do you think the changes might be if we wanted to run the ATTiny85 at 16mhz ? timing/cap changes ? regards Bob

    ReplyDelete
  27. I was interrested in de CE pin tied high. Did not work as the unit would not switch between receive/send. I had to add this line:

    Nrf24_configRegister(CONFIG, mirf_CONFIG ); // power down trick to workaround CE pin tied high!

    Before this one

    Nrf24_powerUpTx(); // Set to transmitter mode , Power up

    in the Mirf Send function.

    With that change, it works both sending/receiving with CE high all the time.

    ReplyDelete
    Replies
    1. Thats really interesting information mvdbro, thank you !!

      Delete
    2. Bob: Have you managed to get it working as well with this? :-)

      Delete
    3. I havent tried mvdbro's suggestion yet as I am not doing tx/rx with one unit, I have one unit as permanent tx and several units as permanent rx - I am still in testing, but it is going well :)

      Delete
  28. Thanks for the great post.
    I'm trying to get 2 trinkets to talk to each other, but they aren't cooperating so far.
    I've wired them both up using your diagram, and confirmed that nrfStatus is 14 for both, so I believe that they're wired up correctly.
    The only change I made was skipping the LED, because I'm powering it from the 3.3v output of the trinket, rather than 5v.

    I found the edited mirf library in your google code account, but when I compile an example using it, I get a series of error beginning with:
    \libraries\mirf\spi.c: In function 'spi_init':
    \libraries\mirf\spi.c:47: error: 'SPCR' undeclared (first use in this function)
    Plus a bunch of similar undeclared errors.

    I've read through all the comments, and tried some of the other examples, without errors, but also without success.

    Did I miss a step?
    Is there any chance you - or anyone else - could post a working example to send one byte from one attiny85 to another? (I only want to send one way, so I won't need to switch between TX and RX.)

    ReplyDelete
    Replies
    1. It looks like you're using my mirf code that is not for the t85 - that version is for the tiny88 and the atmega series that have hardware SPI. For the t85, use Stanley Seow's code that I linked to in the post, along with the mods to the CE function.
      It also might help to look at Kyle's project that uses a t85 and ties CE high to save a pin.
      https://github.com/solarkennedy/equail

      Delete
    2. Ah, I see.

      I've also been trying Stanley Seow's code with your mods, and Mirf.getStatus() is returning 14, but when I try to send and receive data:
      On the sender, Mirf.isSending() is never false.
      and on the receiver, mirf_data_ready() is never true.

      solarkennedy is using RF24 instead of Mirf, do you think I should just give up on trying to get Mirf to work and just use RF24 instead?

      Here's how I've got it wired: http://s9.postimg.org/658j3zkv3/trinket_nrf24l01.png - hopefully this will be of use to someone.

      Delete
    3. Because I was out of other ideas, I re-enabled the digitalWrite calls in ceHi and ceLow and attached CE on the sending circuit to a pin instead of tying it high, and it finally works.

      send() calls ceLow() and ceHi(), so I believe this is why it wasn't working.

      setRADDR() and powerUpRx() also call ceLow() - but apparently that was unnecessary, as I have left the receiver tied high and it's working fine.

      Although it's now working - I now have one less pin available on the sending trinket, and I needed that.

      I took a look at the equail project - but that only uses an attiny85 as a receiver, not a sender.

      I'm surprised that no-one else has ever run into this problem, so I have to ask: Has anyone else successfully sent FROM an attiny85 using only 3 pins?

      Delete
    4. After a slight modification of your original schematic, I've gotten it working as intended with only 3 pins:
      http://goo.gl/AUysbx

      I noticed that send() calls csnLow() and csnHi() at almost the same time as calling ceLow and ceHi(), so instead of tying CE high, I've attached CE to the same place as CSN, so that it's toggled via csnHi() and csnLow()

      I made the same change to the receiving circuit, and my test sketch still works.

      I've posted my test sketch here: http://testing20141124.blogspot.com/2014/11/communicating-between-2-trinkets-with.html

      I'd still like to hear if anyone else was able to send data using the original circuit.

      Delete
    5. Jackson,
      Sending definitely works, at least with enhanced shockburst disabled. The coin-cell operated transmitters I made have CE tied high (tied in to RST). http://nerdralph.blogspot.ca/2014/10/nrf24l01-reloaded.html
      Although it's not indicated in the datasheet, based on Johnny's comments CRC may have to be disabled as well. I still haven't got around to testing that myself.
      If you're doing transmit only, then tying CE & CSN is something that works well, as you also found out. For a receiver it's not so good unless you use IRQ for notification. If you poll, every time CE goes low the nRF briefly goes out of Rx mode.

      Delete
    6. This comment has been removed by the author.

      Delete
    7. Then disabling enhanced shockburst was the step I was originally missing, thank you.

      I'll leave my blog post up for now, since it has complete instructions which work.. Hopefully someone else can figure out a better way and post complete instructions themselves.

      Delete
  29. This comment has been removed by the author.

    ReplyDelete
  30. Hi Ralph, one strange thing is disturbing me.

    If I touch a little gound pin of my RF24 (only ground pin without doing any short with Vcc pin), the led begins to light continuosly (I only transmit every hour so I can see the led blink each hour, as you suggested the led is usefull to check when RF24 is working).

    But why if I touch a little ground pin it begins to light ?? I have seen the RF24 module schema and it has decoupling capacitors so I dont know what is happening?

    Could you test by yourself ?

    Best regards,

    ReplyDelete
  31. I have also try directly with a 3.3V linear converter and I have also the same problem

    Could you test ? I have also check with TWO RF24 modules (both from ebay) and with Attiny84 and ATmege328p

    Sometimes you need to scratch few seconds (better with a multimeter probe), some times, ony with one second.

    I have also check with a ampmeter, it is 1.50 mA. (I you have a multimeter, only touching RF24 ground pin with one of the two probes of the multimeter makes the led light. This is how I found this strange behaviour. The multimeter can be on or off)

    What do you think is it ?

    Best regards,

    ReplyDelete
    Replies
    1. I still haven't tested it out, so I'll just make my guess rather than waiting till I get around to setting up a nRF module on a breadboard again. If you are *only* touching the ground pin, then you are effectively adding an antenna to the board. 100uF decoupling caps are good for dampening up to ~20Mhz, so RF noise above 100Mhz may be strong enough to raise the noise floor voltage on ground high enough that CSN is considered low, activating the SPI engine in the nRF and raising the power consumption.

      Delete
  32. I have been using this method for a while (CE pulled high, etc...) to broadcast data from a trinket temperature sensor in the blind to another NRF receiver. Works great most of the time, with one strange quirk. On initial power up of the trinket, it will not start sending data; I have to send, from another NRF transmitter, one packet, which the NRF connected to the temperature sensor apparently receives, and only then will it start transmitting in the blind, forever, until power is interrupted. After a power interruption, the process must be repeated.

    Any ideas what may be going on here? Seems like some sort of a hung startup state for the NRF board. Any ideas on workarounds?

    ReplyDelete
    Replies
    1. Is shockburst enabled? It needs to be turned off (EN_AA=0) for transmit to work with CE tied high. Another option that I played with a bit and has worked for other is to tie CE & CSN together.

      Delete
  33. When I try to upload the sketch i'm getting the following message:
    error: 'MirfHardwareSpi85' was not declared in this scope
    Any idea about what am I doing wrong?

    ReplyDelete
    Replies
    1. Hi Vincente, due to the holidays I'm just getting around to your comment.
      It looks like you haven't installed the Mirf library: https://github.com/stanleyseow/arduino-nrf24l01
      You'll also need to modify the csnHi and csnLow functions as I described.

      Delete
  34. I'm using a tiny85 with 3 pin connection to NRF module, both sending and receiving with enhanced shockburst enabled. Only added the powerdown trick before changing to send mode.

    Added this:

    Nrf24_configRegister(CONFIG, mirf_CONFIG ); // power down trick to workaround CE pin tied high!

    Before this one

    Nrf24_powerUpTx(); // Set to transmitter mode , Power up

    in the Mirf Send function.

    ReplyDelete
  35. All answers lie in this thread....

    ReplyDelete
  36. Hello, I've read most of the comments but I've lost myself, I want to use rf24network + nrf with a digispark, so two pin are used to pass data towards the pc, what's the best approach?

    Thanks

    ReplyDelete
    Replies
    1. I'm not familiar with rf24network, but this fork of RF24 is an arduino-compatible library that includes my 3-pin control hack:
      https://github.com/TMRh20/RF24
      I find it's rather bloated, but that seems par for the course for people writing Arduino code instead of straight AVR code with just avr-gcc and avr-libc.
      I'm not aware of any arduino libs that have incorporated my 2-pin control circuit.
      http://nerdralph.blogspot.ca/2015/05/nrf24l01-control-with-2-mcu-pins-using.html

      Delete
  37. Hi, does this mean that you could use the attiny to transmit, receive and also have a pin or two spare for doing something useful? As far as I can see I can only receive at the moment. I am really loving your work and want to get my head around this for use in a home cheap automation project.

    ReplyDelete
    Replies
    1. Yes, you can transmit and receive. As discussed above, with CE tied high you need to need to go to power down and then power up mode (PWR_UP) to switch between tx and rx.
      You can even do it with 2 pins using my latest technique:
      http://nerdralph.blogspot.ca/2015/05/nrf24l01-control-with-2-mcu-pins-using.html

      I also have an idea for doing transmit only using one pin. I hope to have it worked out early in the new year.

      Delete
    2. Hello.

      Can you get out of the RX mode with CE pin held high? The state diagram says you can power down, but how would you do that? Specs also say that you can issue the W_REGISTER command only in the power down or standby modes. So it seems you would not be able to write into the CONFIG register while in RX.

      Delete
    3. Once a packet is transmitted, it automatically goes to standby. So writing to the CONFING register to set PWR_UP = 0 should be no problem. It's worked fine for me and a few other people that have made comments, although with so many clone chips out there it is possible it may not work with some.

      Delete
    4. Thanks for your reply. I am worried about switching the other way around: What if the device is in RX? The state diagram shows that there are two ways out of there - either CE=0 (which I do not want) or PWR_UP=0, which I cannot do because I am not allowed to write into the CONFIG register while in RX. If that can be done in spite of what the specs say, that would be great - I am trying to save one more precious i/o line on an 8 pin PIC.

      Thanks again..

      Delete
    5. I've been thinking of this some more, and after going through my notes (and my previous comments), I think if you tie CE & CSN, it should work OK. You'll just have to poll for the Rx packet. You might want to check out my 2-pin solution as well.

      Delete
  38. Hi Ralph, using the your 3 pin wiring scheme for my nrf24l01 and attiny85, but not getting anything to transmit. I have wired exactly like your diagram provided but still no luck. I'm using the "TMRh20" R24 library and the example "rf24tiny85" example slightly modified for my magnetic reed switch. I've tested this same sketch with the "rf24tiny85" 5 pin wiring scheme on the transmitter and "Getting started" on the receiver and it worked flawlessly. However when I wire everything up for the 3 wire on the transmitter and uncomment the CSN pin define to use 3 and comment the CSN pin 4 define. It does not work. What am I doing wrong?

    ReplyDelete
    Replies
    1. Did you try using the IRQ line for debugging (I mentioned it in previous comments).
      Also check the status register 7 is 0x2e (TX_DS & RX empty) after transmit. If it is not, then check if the CSN line is going low. If you don't have an oscilloscope or logic analyzer, you could try using the audio input on a PC.
      http://nerdralph.blogspot.ca/2014/05/pc-storage-oscilloscope-and-logic.html

      Or use a USBasp as a logic analyzer:
      http://nerdralph.blogspot.ca/2014/05/24-megasamples-per-second-continuous.html

      Delete
    2. Hi Ralph. Came back to this tiny project to try to make it work. Turns out that out of the 10 NRF24L01+ radios that I purchased the 1 that I was working with in the "Tiny85 3 Pin Solution" ended up being a bad apple. I started to measure the temps on the board and the board and components were extremely hot. No smoke which is probably why I had no inclination of the issue. Tried this evening with a different board out of the bunch and it works flawlessly. I appreciate your advice on this and the work that you have done to provide the 3 and 2 Pin Solutions for this chip.

      I have one simple question though. If I define CE and CSN, both with the pin map 3, I know I can use pin mapping 4 for a sensor, but what would the pin mapping be for the 2nd sensor if I wanted to use it? Reason I ask is because with the 3 Pin Solution, minus the Reset pin, that should leave me with 2 pins available for GPIO. I defined 4 for my Reed Switch, but according to the ATTiny85 Pinout diagrams I have seen online, pin mapping 3 is physically empty but CE and CSN are defined as 3.

      Delete
    3. In the code snippets, I show how I modified the csnHi csnLow functions so they don't actually use the CSN pin definition. In other words, you can remove the CSN pin definition from the code. I think it would be bad coding style to define them as a dummy pin number, but if that's what you want to do then you could use PB7, which would be bit 7 of portb, which doesn't exist as a real pin on the t85.

      Delete
  39. This comment has been removed by the author.

    ReplyDelete
  40. This comment has been removed by the author.

    ReplyDelete
  41. "When connecting the nrf module to a tiny85, connect MISO(pin7) on the module to MOSI/DI(PB0), and not MISO/DI(PB1). "

    Why is the nrf module MISO pin not connected to the attiny MISO pin?

    ReplyDelete
    Replies
    1. On the tinyx5 the MOSI label is for ICSP programming; it doesn't have a real SPI interface. For USI, PB0 is the data in pin, and PB1 is the data out. I corrected the typo to: "not MISO/DO(PB1)"

      Delete
  42. Hello,
    i am planing to make a device consisting of a digispark (attini85 mcu based board) a nrf240 module, one or two adressable rgb leds and a lipo and its charging/protecting/boost circuit. Googling around i found a picture of a similar device with an trinket board that led me to this great blog. Sadly i cant find that picture on the blog. On the attiny i want to predefine some color/blinking modes for the leds, and cycle the color/blinking modes via the nrf240. is this possible (pin configuarion) ?
    Hope someone can help me out, never woked with digispark or similar attiny85 based board before) nor with the nrf module. I have some project with the arduino uno, but still a noob.

    ReplyDelete
  43. Hello! Can anyone come in handy version of the PCB for NRF2L01 + ATtiny85 (View from the side of the parts)
    http://s009.radikal.ru/i309/1710/4e/6ec0623d032d.jpg

    ReplyDelete
  44. Hello,
    I test nrf24l01 with attiny84.
    I use an HLK-PM01 for regulate 220->5V and I use linear regulate ( AMS117 ) 5V -> 3.3V.
    But I have a problem, data is send correctly but I don't receive data.
    Have you ever had this problem ?

    ReplyDelete
  45. Hello,
    I know this is an old topic, but anyway. I have worked setup with 3 pins using 1k resistor and 100nf cap. Everything work fine when i power it with 3v (2xAA batteries), but when Vcc goes below 2.8v it stop works. So my question: is there any chance to get this setup working in wide range of vcc eg 2.5-3,3v ?

    ReplyDelete