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/DI(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.

88 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
  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