Will the following declaration code work for a second RFM69 on Moteino?
radio2(7,3,false,1); //CS on D7, D3 for IRQ
radio2.initialize(FREQUENCY,3,NETWORKID); //Same gateway, because I need to listen to the same node with two gateways.
https://lowpowerlab.com/forum/index.php/topic,648.msg3796.html#msg3796
See the link, I don't think the library supports it, but the thread went dead so not sure what eventually happened
Quote from: donaldhwong on December 17, 2014, 06:29:38 PM
Will the following declaration code work for a second RFM69 on Moteino?
radio2(7,3,false,1); //CS on D7, D3 for IRQ
radio2.initialize(FREQUENCY,3,NETWORKID); //Same gateway, because I need to listen to the same node with two gateways.
Try it, let us know what you find.
Do you want both radios on the same frequency and network, but different IDs? Not sure what that buys you other than more overhead to deal with.
Hi Felix, Thank you.
Are you not concerned about the following from the previous reply from a no-result experiment conducted already with exact same code?
Quote
Interrupt is triggered at the RFM69 which last initialized.
What to do?
This is what I would have expected to happen, based on how the code has been written. The problem (as stated above) is the 'static' declaration of variables. In this case the variable 'static RFM69* selfPointer;'. If you search the code for this variable you will see it is used as part of interrupt handling.
Actually no. Moteinos are not designed to host 2 transceivers and I consider that an outlier experiment which I can try to help with but I can not support or encourage.
Besides the hardware implications there are memory issues you can run into by hosting two transceivers, as you already well know - the atmega only has 2K RAM. This leads to a pandora's box that i'd rather keep closed. If you are endeavoring to do such a project you are welcome to use the base library and modify that to support your experiments.
Thank you Felix. Understood. If you don't mind answer a few questions:
1. How do I upload a modified rfm69.cpp say RFM69x2.cpp into codebender? I only saw the code to include the rfm69.h but not the *.cpp.
2. When I run the sketch, is it running in the 2k RAM, 1k EEPROM or 32k Flash? Can not find any document so far. I assume that that the EEPROM is for the boot loader. Flash is the programming. Ram is temporary storage. Am I right? Why are you worried about the 2k RAM?
Thank you for your kind support.
Donald
1) I think you can upload your own version of a library. For library development I suggest you do it on your PC/desktop and use the Arduino IDE and when you have a working version upload it to your own codebender account.
2) I suggest you do some C++ reading and some Arduino as well. These are vast subjects that can not be answered in a forum post. The 3 memories are fundamentally different. Your code and the bootloader both live in internal flash (32k). The RAM is used for dynamic allocation while your program is running.
Thank you Felix.
If you believe that I may run into a RAM problem. May I then exchange the two Moteino with the Moteino Mega? I am willing to pay for whatever charges that you deem necessary?
Since I just got it and have not done anything other than load the sketch onto them.
Please advise.
As per your advise, I have just downloaded the Arduino and install your library into it. They compiles fine and Serial monitor works.
Thank you for your guidance and support.
Donald, per my store policy (https://lowpowerlab.com/shop/terms), the sales are final and there are no returns for reasons other than DOA. I always try to help people with any questions and ask they do their bit of homework and read about what to expect from these products, what they can and cannot do etc.
Hi Felix,
No problem at all. If I run into ram problem, I just upgrade to Mega. About that purchase I have a few questions:
1. Do you sell a USB adapter or shield for Mega?
2. Do you sell AA or AAA, or any kind of battery shield?
I did not find any such items in your store.
Thank you.
For MEGA use the FTDI Adapter for programming.
There is no AA shield, just connect a battery holder with at least 3xAA or a Lipo to "VIN" and you're good to go.
Will your FTDI adapter work with Moteino Mega?
Thanks,
Donald
Got my breadboard today and hooked up my second RFM69W. Change the declaration as follows:
Quote#define RF69_SPI_CS 7 // SS is the SPI slave select pin, for instance D10 on atmega328
// INT0 on AVRs should be connected to RFM69's DIO0 (ex on Atmega328 it's D2, on Atmega644/1284 it's D2)
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
#define RF69_IRQ_PIN 3
#define RF69_IRQ_NUM 1
Guess what? It works. Now just have to figure out, how to edit the RFM69.cpp to talk to both RFM69W.
Yes the FTDIAdapter works for all non-usb Moteinos.
You will need 2 instances of the RFM69 class in your sketch, one for the native RFM69 on D2/D10 and one for the second one on D3/D7.
Hi Felix,
D3 and D7 was how the second RFM69 were wired. And it is working as per my post.
Now I need to get both of them working. But I keep on having compiler error. Please help.
See my post here: https://lowpowerlab.com/forum/index.php/topic,797.0.html
Many thanks. This is the my last step. Please help.
To follow up on my statements I previously made about interrupt routines
needing to be static. Please read the following, it explains it better than I can:
http://stackoverflow.com/questions/15669017/cant-use-attachinterrupt-in-a-library
For a partial solution I have attached a RFM69.cpp and RFM69.h file which should (but untested) resolve the interrupt handling issue, between two instances of the Class. The main thing is you need to specifically instantiate the second instance with the main constructor passing in the appropriate pin numbers and setting the interruptNum=1. If you search the code for 'selfPointer1' and 'isr1' you can see where I have made the changes.
However there is a bigger issue.
If you search RFM69.h for 'static' you will see many of the key attributes e.g. 'DATA' are declared static. This means they will be shared between both instances, clearly unacceptable. To fix this
- The static keyword wil have to be removed from the attributes in the header file.
- The declarations of the same variables in the cpp will have to be commented out.
I am not sure of the reason for these being static was, or if making this change will have a bigger impact, clearly it will need to be tested.
Kiwi
Dear KiwiSinceBirth,
Thank you so much for helping. I understand what you are saying. When I compile the code, I got the following errors. Can you continue to help? Very much appreciated.
Quote
C:\Users\jmjm\Documents\Arduino\libraries\RFM69\RFM69_original.cpp:44: error: 'RFM69* RFM69::selfPointer' is not a static member of 'class RFM69'
C:\Users\jmjm\Documents\Arduino\libraries\RFM69\RFM69_original.cpp: In member function 'bool RFM69::initialize(byte, byte, byte)':
C:\Users\jmjm\Documents\Arduino\libraries\RFM69\RFM69_original.cpp:107: error: 'selfPointer' was not declared in this scope
C:\Users\jmjm\Documents\Arduino\libraries\RFM69\RFM69_original.cpp:112: error: argument of type 'void (RFM69::)()' does not match 'void (*)()'
C:\Users\jmjm\Documents\Arduino\libraries\RFM69\RFM69_original.cpp: In static member function 'static void RFM69::isr0()':
C:\Users\jmjm\Documents\Arduino\libraries\RFM69\RFM69_original.cpp:330: error: 'selfPointer' was not declared in this scope
the errors would indicate the selfPointer needs to be declared 'static', as per the code I posted.
Hi Again,
I was using your code. And I checked, they were declared as static. Weird..
Thank you for you quick response.
Donald
Strange. I didn't test the code I posted, but it did compile, I used one of the example scetches straight from felix's library to test this. Question: I just noticed in your error list it says RFM69_original.cpp. Is this the right file?
Thank you KiwiSinceBirth. You are my life saver. I have successfully compiled it and run Felix's Gateway code under Arduino IDE.
Will try to run both RFM69W simultaneously after finish my shopping for Christmass gift today.
Thank you again.
Donald
Hi KiwiSinceBirth,
I tried both radio(10,2,false,0); and radio(7,3,false,1) in two separate instance with your edits. Both modules work well. One without antenna showed -60 RSSI and the one with the anntenna showed 43 RSSI.
Then I defined radio(10,2,false,0); and radio2(7,3,fasle,1); and radio2.initialize(FREQUENCY,3,NETWORKID); without any additional command. The default radio still works fine.
But as soon as I inserted "if radio2.receivedDone(){}" The interrupt stop working. I get only one line below at the Serial Monitor:
Listening at 433 Mhz...
SPI Flash Init OK. Unique MAC = [D7:64:44:24:63:5F:71:31:]
#[1][2] FLASH_MEM_ID:0xEF30 [RX_RSSI:-41] - ACK sent. Pinging node 2 - ACK...ok!
That's it.
Please advise what else I needed to do.
Thank you for your continual support.
Hi KiwiSinceBirth,
What I found out just now was both RFM69W were initialized with current code. I suspect that the second RFM69w interrupted only once, because I print out the radio2.readRSSI() after each radio.receiveDone(). I only got the same number.
Just to be clear you removed the static keyword from the following definitions in RFM69.h ? and commented the similar declarations in the cpp file.
volatile byte DATA[RF69_MAX_DATA_LEN]; // recv/xmit buf, including hdr & crc bytes
volatile byte DATALEN;
volatile byte SENDERID;
volatile byte TARGETID; //should match _address
volatile byte PAYLOADLEN;
volatile byte ACK_REQUESTED;
volatile byte ACK_RECEIVED; /// Should be polled immediately after sending a packet with ACK request
volatile int RSSI; //most accurate RSSI during reception (closest to the reception)
volatile byte _mode; //should be protected?
Hi KiwiSinceBrith,
Nop, sorry. I thought you were trying to explain what you did, instead of an assignment for me. :-)
Now I did that. radio2.receiveDone() no longer hang up the program, or stop radio1 from functioning in the loop, but it does not interrupt either.
I commented out "radio1.receiveDone()" and leave only "radio2.receiveDone()". It does not work. I then commented out
Quote/*
if (_interruptNum==0) {
//detachInterrupt(1);
attachInterrupt(_interruptNum, RFM69::isr0, RISING);
selfPointer0 = this;
}
*/
and leave only the
QuoteattachInterrupt(1, RFM69::isr1, RISING);
selfPointer1 = this;
still no trigger.
But, if I reverse radio_1 to the second module and radio_2 to the first/embedded module, it is still radio_1 that triggers. So problem is not in the hardware. It is in the library. My guess.
Please advise.
At this point it would be very hard to work out why this isn't working. The advice so far was how to get the class defined in such a way that two instances are running separately, and receiving interrupts correctly.
A couple of possibilities
- While one instance is interacting with the radio (and disabling interrupts) the other instance doesn't get the interrupt that it needs.
- While one instance is interacting with the radio (calling writereg() ) the other instance gets and interrupt and takes over SPI, when returned from the interrupt the first radio could have timed out.
Another words a race condition, on interrupts and the shared SPI bus. And this is when it gets difficult as the existing library wasn't designed to work this way. Really you are going to have to do a bit of debugging to see where and why things stop working. Primarily the code needs to isolate the use of the SPI bus and handle interrupts with as little impact to the other radio, but again very hard to know.
Hi KiwiSinceBirth,
I understand what you are saying and I also suspected that. Especially when the messages are being sent so fast.
Is there a way that I could Wait for Interrupt 0 and only 0, ignore all other interrupt, process that. Then wait for Interrupt 1, process that, while ignore all other interrupt. Just alternating waiting for 0 and 1 and 0 and 1?
Because for my application, it does not need to be real time. The project can afford to loose some signals.
Please advise. Thank you for your continual help.
I would be possible to modify the code, there are a couple of things of note:
The select() and unselect() functions are responsible for the SPI CS enable and disable, and are placed around use of SPI communications. These functions also disable interrupts, preventing other code from interfering, while in progress.
Currently this happens in the low level functions (e.g. writeReg() and readReg()), but a higher level function could call many low level functions to perform one task. If these select() and unselect() were called in the high level functions, then the exclusivity would be broadened, and potentially block interrupts happening during a single user call to the library.
Another issue which could be a problem is interruptHandler() itself. In the first line of code it calls readReg(), which then calls select() and unselect(). The unselect() method enables interrupts, so potentially from that point forward the interrupthandler() could itself be interrupted. A first step may be to code the interrupt handler so that it never enables or disables interrupts.
My understanding is that interrupts are implicitly disabled before the interrupt handler is called, and then re-enabled when the handler is finished.
Kiwi
Thank you, KiwiSinceBirth,
Got it. I will give it a try.
I have another idea. Since there are success in implementing one RFM12B with one RFM69W working as a bridge, what if we create a second class, say RFM69_1.
What do you think? If you believe it worth a try, then what do I need to pay attention to?
Thank you kindly.
Donald
Answering your question about two classes, Yes it is worth a try but my guess is it won't make too much difference, since we have removed all static (shared) data, except of course the interrupt handler.
Another possibility is 'SRAM' is getting low, here is an article that describes problem, and provides solution https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
ALSO
After my last post I did some work and implemented (compile only) what I stated in My post.
The change is centred around the select() and unselect() functions. These functions perform what I call 'reference counting' which means the first call to select() does the SPI enable and interrupt disable. Then any further call to select() is ignored, except to increment a counter. Then when unselect() is called the counter is decremented, and on the final unselect() when counter reaches zero, the SPI is disabled and interrupts enabled.
This means select() and unselect() can now be placed anywhere in code, so long as they are in matching pairs.
There is only two slight issues millis() and Serial.print(). These functions need interrupts to be functioning, so I have omitted select() and unselect() around code that uses these functions, or code that calls code that uses these functions. This happens quite a bit e.g waiting for an ACK response, where the response is received and handled by the interrupt routine itself. Clearly this sort of code cannot use select() unselect(), as would prevent interrupts from occurring.
I have also fixed interruptHandler(). The first line of code is select(true); the boolean flag tells select() and unselect() to NOT enable/disable interrupts, which (as stated previously) could have been an issue.
receiveDone() specifically sets and clears interrupts. I have left it alone, except to make the enable interrupts explicit, and ensured that any code that calls this function itself has not called select() unselect(), which could have caused a conflict.
Anyway give it a try.
Kiwi
Quote from: kiwisincebirth on December 23, 2014, 05:38:56 PM
...
Another possibility is 'SRAM' is getting low, here is an article that describes problem, and provides solution https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
...
Kiwi
Thanks for the link! I've been wondering how to measure the amount of free SRAM and THERE it is! Also, the article makes one wonder if it's worthwhile exploring 'garbage' collection methods. On the other hand, 'holes' should only occur if you're using dynamically allocated storage and, as far as I know, none of the 'standard' Moteino libraries use malloc, etc. Are you aware of any? Maybe sprintf and a few others?
Tom
Hello KiwiSinceBirth,
Thank you so very much for your continuous support of this very important project of mine.
I understand what you are saying and I read through your edits, though I still am at function level. But I am learning a step at a time.
In short, this time, it did not even go through the setup(). Meaning the following message was not displayed in the Serial Monitor.
Quotesprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
I am thinking of the following. When the Node transmits. Both Gateway will receive and both will interrupt practically at the same time. If we process the first one, will the second one continue to interrupt until it is being processed or not? If not, then it is okay for the project, if we need to alternately listen to one after the other.
Second, I slowed my Node to transmit at 1,000 millisecond, I still don't see any kind of interrupt from the second RFM69W. Even just readRSSI.
I have implemented RAM reporting. There are still 1,316 bytes of Free RAM.
End of report. Waiting for your further advise.
Thank you so much and Merry Christmas.
Donald
Some more research:
http://www.dorkbotpdx.org/blog/paul/spi_transactions_in_arduino
http://www.pjrc.com/teensy/td_libs_SPI.html
Quote from: donaldhwong on December 23, 2014, 11:01:46 PM
...
In short, this time, it did not even go through the setup(). Meaning the following message was not displayed in the Serial Monitor.
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
....
Donald
I have to ask: did you have a
Serial.println(buf); after your sprintf function call above?
Tom
Hi KiwiSinceBirth,
Thank you for SPI information. I will study them.
Thank you Tom.
Yes, these were the original Felix's code. There was a "char [buf]" defined.
Happy Holidays,
Donald
Christmas Eve.
I have attached some updated libraries, (I have no way to test currently). I have put them back to a similar state as original, but left the select() unselect() nested and interrupt handling fixes. Please try them.
The reason I sent you the SPI articles is clearly there are issues with multiple devices on the same channel, especially when they are competing for interrupts and SPI at the same times.
My fixes were basically trying to gain some exclusivity of interrupts and SPI bus, which reading the links is basically the same goal. Really the best outcome would probably to re-write the RFM library using the new transactional features introduced into SPI libraries.
Kiwi.
Quote from: kiwisincebirth on December 30, 2014, 05:57:07 PM
I have attached some updated libraries, (I have no way to test currently). I have put them back to a similar state as original, but left the select() unselect() nested and interrupt handling fixes. Please try them.
The reason I sent you the SPI articles is clearly there are issues with multiple devices on the same channel, especially when they are competing for interrupts and SPI at the same times.
My fixes were basically trying to gain some exclusivity of interrupts and SPI bus, which reading the links is basically the same goal. Really the best outcome would probably to re-write the RFM library using the new transactional features introduced into SPI libraries.
Kiwi.
Kiwi, are you suggesting that 'select' is called more than once before 'unselect' is called? I'm not understanding why you have the counters in the code.
Is this an artifact of trying to get two radios working and wouldn't be a problem in a single radio scenario (ALL known cases but one)?
Tom
Hello Again, KiwiSinceBirth,
So glad to know that you have not given up on me yet. Very much appreciated indeed.
I tried the original Felix's code of Gateway and Node with your modified files. TWICE. But both times, the interrupt did not engage. The Serial Monitor stopped at:
Listening at 433 Mhz...
SPI Flash Init OK. Unique MAC = [D7:64:44:24:63:5F:71:31:]
I thank you for taking the time on holidays trying to address this.
Thank you and Happy New Year,
Donald
Quote from: TomWS on December 30, 2014, 08:48:17 PMKiwi, are you suggesting that 'select' is called more than once before 'unselect' is called? I'm not understanding why you have the counters in the code.
Is this an artifact of trying to get two radios working and wouldn't be a problem in a single radio scenario (ALL known cases but one)?
Tom
Hi Tom.
This was an coding experiment on my behalf to try an get the RFM69 library to operate with two independent radios, as Donald is attempting to do. And yes clearly a single radio has been well tested, and works as per the published code, however I think there is one POTENTIAL issue (below), not sure.
My initial thought that simple removal of static declared variables would be all that was needed, but latter the issue of contention of interrupts (firing simultaneously), and the SPI bus are the main issues.
I introduced the counters in the select() unselect() so that I could call these methods throughout the code, to create larger blocks of exclusive-ness (without worrying about a sub-procedure using these functions also), and prevent a second instance (of the radio) from interfering with the first.
As I said so far this hasn't worked, but let me to one POTENTIAL issue; In the first line of the interrupt handler
if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY))A call is made to readReg() which uses select() and unselect(). select() calls nointerrupts() which is fine because interrupts are disabled anyway, but unselect() call's interrupts() which enables interrupts prior to going back to the RFM69 interrupt handler.
I think it leaves the RFM interrupt handler open to further interrupt, until another select() unselect() pair is encountered, so not a big issue but not totally ideal.
Hope this makes some sense.
Kiwi
Quote from: kiwisincebirth on December 31, 2014, 07:03:29 AM
Hi Tom.
This was an coding experiment on my behalf to try an get the RFM69 library to operate with two independent radios, as Donald is attempting to do. And yes clearly a single radio has been well tested, and works as per the published code, however I think there is one POTENTIAL issue (below), not sure.
My initial thought that simple removal of static declared variables would be all that was needed, but latter the issue of contention of interrupts (firing simultaneously), and the SPI bus are the main issues.
On the two radio solution are you still using the same interrupt pin or did you move the second radio to another pin (like pin 3, for example)?
The tricky part with the interrupt handler is that the pointer to it MUST be to a static function (so it's always in the same place for the interrupt routine to call). Since you now have two instances, each instance COULD be the same code (ie, located within the same static object) IF, and ONLY IF, all references within the code are pointer based references ('this' won't work since 'this' may reference the wrong object). I would think that would require a substantial re-write of the interrupt handler.
My inclination would be to try to externalize the interrupt handler(s) with a static function or functions and make the RFM69 Interrupt handler simply a method of radio (remove interrupt modifier from its declaration/definition). In this way each externalized interrupt handler would be separately attachable and then would be able to call the appropriate instance of radio object (ie radio1.interruptProcessor(), radio2.interruptProcessor()). When they exit, they will return to the interrupt handler that called them and its return would be a proper interrupt handler return.
Quote from: kiwisincebirth on December 31, 2014, 07:03:29 AM
I introduced the counters in the select() unselect() so that I could call these methods throughout the code, to create larger blocks of exclusive-ness (without worrying about a sub-procedure using these functions also), and prevent a second instance (of the radio) from interfering with the first.
As I said so far this hasn't worked, but let me to one POTENTIAL issue; In the first line of the interrupt handler
if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY))
A call is made to readReg() which uses select() and unselect(). select() calls nointerrupts() which is fine because interrupts are disabled anyway, but unselect() call's interrupts() which enables interrupts prior to going back to the RFM69 interrupt handler.
I think it leaves the RFM interrupt handler open to further interrupt, until another select() unselect() pair is encountered, so not a big issue but not totally ideal.
Hope this makes some sense.
Kiwi
It does make sense, good catch! I'll have to look at the code again to see what harm the original code would cause.
Quote from: TomWS on December 31, 2014, 09:46:44 AM
On the two radio solution are you still using the same interrupt pin or did you move the second radio to another pin (like pin 3, for example)?
The tricky part with the interrupt handler is that the pointer to it MUST be to a static function (so it's always in the same place for the interrupt routine to call). Since you now have two instances, each instance COULD be the same code (ie, located within the same static object) IF, and ONLY IF, all references within the code are pointer based references ('this' won't work since 'this' may reference the wrong object). I would think that would require a substantial re-write of the interrupt handler.
My inclination would be to try to externalize the interrupt handler(s) with a static function or functions and make the RFM69 Interrupt handler simply a method of radio (remove interrupt modifier from its declaration/definition). In this way each externalized interrupt handler would be separately attachable and then would be able to call the appropriate instance of radio object (ie radio1.interruptProcessor(), radio2.interruptProcessor()). When they exit, they will return to the interrupt handler that called them and its return would be a proper interrupt handler return.
The requirement/assumption I took was that the second radio, would be wired to Interrupt#1 ( Pin#3 on AtMega328 ). These values would need to be passed in the constructor of the second radio instance.
If you look at the code I posted (#35 above); I have introduced a second static isr1() routine and selfPointer1 variable. isr1() is coded to call the interruphandler() of the selfPointer1 instance. In the initialize() method the appropriate isr0() or isr1() is attached, and the selfPointer0 or selfPointer1 static variable set to this. The only other change is of course to remove the static declaration off all other variables not described above.
The above change I think is all that is need to isolate the two radio object instances, running on two different interrupts (0 and 1), and correctly route interrupts to the appropriate instance.
Kiwi
Quote from: kiwisincebirth on December 31, 2014, 09:20:10 PM
The requirement/assumption I took was that the second radio, would be wired to Interrupt#1 ( Pin#3 on AtMega328 ). These values would need to be passed in the constructor of the second radio instance.
If you look at the code I posted (#35 above); I have introduced a second static isr1() routine and selfPointer1 variable. isr1() is coded to call the interruphandler() of the selfPointer1 instance. In the initialize() method the appropriate isr0() or isr1() is attached, and the selfPointer0 or selfPointer1 static variable set to this. The only other change is of course to remove the static declaration off all other variables not described above.
The above change I think is all that is need to isolate the two radio object instances, running on two different interrupts (0 and 1), and correctly route interrupts to the appropriate instance.
Kiwi
I'm not sure this is enough. If the internal interrupt handler is declared as static, as it needs to be, then the only way to attach a distinct handler is if you externalize it - otherwise you end up attaching the SAME function as both handlers. Without knowing the internals of what the compiler generates for the handler code, my suspicion is that the safest way is to convert the handler within each object so that they are truly unique (ie, NOT static). So, create a separate function that is a static interrupt handler that calls the correct instance.
I could be wrong about this, but I'm pretty sure this 'brute force' approach is safer and more likely to work...
Tom
PS: I'm still confused about the use case for two RFM69 radios in the same Mote, but, at least, this dialog is interesting and productive.
Ok, I looked at your code posted at #35. I agree that this MIGHT work, but, uh, it doesn't (from what you've said). I think it's a tricky thing to contain (in a single object) and attach two ISRs to two different interrupt sources when the 'attach' point has to be a static function. In this case what does 'this' refer to when you are setting up and when you're calling a respective ISR? I don't know - it depends on how the compiler builds the code.
If, on the other hand, you attach your OWN code to be an ISR that calls radio1.interruptHandler or radio2.interruptHandler there is no ambiguity - for you or the the compiler...
Tom
Quote from: TomWS on December 23, 2014, 06:11:33 PMThanks for the link! I've been wondering how to measure the amount of free SRAM and THERE it is! Also, the article makes one wonder if it's worthwhile exploring 'garbage' collection methods. On the other hand, 'holes' should only occur if you're using dynamically allocated storage and, as far as I know, none of the 'standard' Moteino libraries use malloc, etc. Are you aware of any? Maybe sprintf and a few others?
Tom
YES The most common being the Sting Class, which uses dynamic memory allocation when the internal buffer is not large enough. Here is a good description of the problem, and fix. https://code.google.com/p/arduino/issues/detail?id=449
Also the first article I linked to is part of a series, with alot more information about memory. https://learn.adafruit.com/memories-of-an-arduino?view=all
Kiwi
Quote from: TomWS on December 31, 2014, 10:05:49 PM
Ok, I looked at your code posted at #35. I agree that this MIGHT work, but, uh, it doesn't (from what you've said). I think it's a tricky thing to contain (in a single object) and attach two ISRs to two different interrupt sources when the 'attach' point has to be a static function. In this case what does 'this' refer to when you are setting up and when you're calling a respective ISR? I don't know - it depends on how the compiler builds the code.
If, on the other hand, you attach your OWN code to be an ISR that calls radio1.interruptHandler or radio2.interruptHandler there is no ambiguity - for you or the the compiler...
Tom
I agree with your assessment, but I wouldn't want a single radio user to have to write the ISR. Best to pass it as an optional argument in the constructor, with a default which is the internal ISR method, just an opinion, not sure if this is possible.
Not sure what the actual issue is to stop it from working, I suspect contention on interrupts, and SPI bus. To make this work would require some considered effort, and debugging time to get working. I personally don have a use for it, all my Motinos are in the field (more on order) so cannot even test a single radio works with modified code.
Have you read this article ?
http://www.dorkbotpdx.org/blog/paul/spi_transactions_in_arduino
Kiwi
PS. My main interest is improving the RFM69 code base. To that end; Could the last line of readAllRegs() "unselect();" be removed ? To me it looks like redundant code, since "unselect();" is called in the preceding loop.
Quote from: kiwisincebirth on January 03, 2015, 05:53:17 PM
<...snip>
Have you read this article ?
http://www.dorkbotpdx.org/blog/paul/spi_transactions_in_arduino
Kiwi
PS. My main interest is improving the RFM69 code base. To that end; Could the last line of readAllRegs() "unselect();" be removed ? To me it looks like redundant code, since "unselect();" is called in the preceding loop.
Whoa! You're a WEALTH of information! YES! This is exactly what is needed! I've been considering creating my own mutex for this purpose but now I'll have to look at the code referenced in the article. THANKS!
re readAllRegs, I suspect, if you look at that code you'll find a select() in there somewhere, so, no, it's not redundant.uh, I just looked at the code and see the first unselect() nicely tucked behind the SPI.transfer() call so you are right about the second one. It is redundant and could mess up your counter scheme.
Tom
If you do create a new thread, please posted here, so that I can follow up.
I am still waiting for a solution for TWO RFM69 on one Moteino.
Much obliged,
Donald
Rather than two RF69s, have you considered using a Mega for one of them and a standard Moteino output serial to one of the spare serial ports on the Mega.
On one Moteino you just gateway the data from the 1st radio to Serial in both directions. Then on the mega you listen to the second radio and the serial port.
Cost is therefore only an extra $12 for the CPU. And... multi tasking :-)
Quote from: scottpenrose on January 08, 2015, 06:51:19 PM
Rather than two RF69s, have you considered using a Mega for one of them and a standard Moteino output serial to one of the spare serial ports on the Mega.
On one Moteino you just gateway the data from the 1st radio to Serial in both directions. Then on the mega you listen to the second radio and the serial port.
Cost is therefore only an extra $12 for the CPU. And... multi tasking :-)
AND this makes Felix a LOT happier for many reasons! ;D
Good suggestion.
Tom
Hi Scott,
Yes, this is my back up plan. YET,
Imagine we have three interrupts on MEGA, then I could use three RFM69 with one MEGA.
Imagine the ease of coding just one MCU instead of three.
If Kiwi and Tom can pull this off, it will be a blessing for everyone involved with Moteino.
LOL
Donald
Donald .... interrupts can happen randomly and even theoretically at the same time but they cannot be executed at the same time on a 1 core MCU/CPU. That's why there is interrupt management and context switching when multiple threads are running on the same pipelined CPU. Even large CPUs do that. It's called interrupt priority and preemption or context switching. If an interrupt of a higher priority happens while an interrupt or routine is running, the MCU/CPU state is saved on the "stack" - ie context switching (registers, stack pointer, current running address etc). Read more here: http://wiki.osdev.org/Context_Switching
I don't know if any of this makes any sense, I learned all about this stuff in college computer architecture courses.
So I think you are misunderstanding how MCU architecture is designed to work, hence you might be thinking adding more radios will add some kind of parallel or threading capability. Even radios can't all talk at the same time .. or they will only receive garbled messages, ie noise. Adding more wheels and engines to a car will not make it go faster, it will make it more complicated to make all the extra parts work with everything else, I hope this analogy helps the explanation.
Quote from: donaldhwong on January 08, 2015, 07:28:24 PM
Hi Scott,
Yes, this is my back up plan. YET,
Imagine we have three interrupts on MEGA, then I could use three RFM69 with one MEGA.
Imagine the ease of coding just one MCU instead of three.
If Kiwi and Tom can pull this off, it will be a blessing for everyone involved with Moteino.
LOL
Donald
Uh, Donald, I hate to disappoint you but I have absolutely no interest in working on two (or more) RFM69s on a single Moteino. I've been working with the others regarding multiple SPI sources and the like - TOTALLY separate from the dual RFM69 issue (which is why I had the SPI thread separated from this conversation). I don't see a use case for more than one RFM69 radio in a single node and definitely won't be working on it.
I will say that I like Scott's suggestion to use two processors and it would be easiest if both of them are Moteino Megas since they can communicate with each other via the second serial port. This is a great solution for ease of development, maintenance, and uses the SAME RFM69 library as all other Motes... (and I say this based on DECADES of programming experience - this is a very solid solution). No special code (from a library perspective) needs to be developed.
Tom
Thank you, Felix and Tom for your candid feedback.
I am not expecting. I am just exploring into new frontier. Last time that I dealt with MCU was 1968. I am already overwhelmed with everything that I am playing around with right now.
When we are able to manage SPI differently with proper interrupt queuing, I am sure we could connect to three RFM69W or other interrupt devices.
Look forward to that day.
Please keep me informed of your development.
Many Thanks,
Donald
To end this thread on a positive note..
I found Radiohead library. It works fine with two RFM69..