Arduino have a few times bigger stack and very different memory layout. It is also different in passing pointers and have more registers. Z-Wave chip is based on 8051 arch - much more limited one.
Check this nested call: AcqusitionMotor->ReadForce->ReadResistance->ReadVoltage
Enable Hardware Watchdog
Re: Enable Hardware Watchdog
Arduino boards has AVR microchips installed on it. Z-Uno uses another architecture (i8051). AVR has about 256 bytes of stack and doesn't run another code at the same time. Z-Uno has just about 130bytes of stack and it runs two firmwares in the same time: main firmware that makes all Z-Wave processing and the sketch. So, we have to be shorter. You can simply calc the maximum usage of stack(it's not precise, but gives you a near value of stack usage):
1. For every parameter add its size to sum: byte=1,word=int=2,long=dword=4,float=2 etc.
2. Do the same thing for every inner (local) variable
3. The same thing to return parameter.
4. Every call uses about 4 bytes (2 for return code, 2 to push a base pointer).
For example:
float funcA(float a, float b)
{
float d = 0.5*a;
float c = 0.2878*d;
return d;
}
It will take:
1. Parameters: flota+float = 4 + 4 = 8bytes
2. Local variables: float+float = 4 + 4 = 8 bytes
3. return result: float = 4 bytes
4. return address + previous base pointer (for every call the same): 4bytes
And we have: 8 + 8 + 4 + 4 = 24bytes of stack to call function like this.
If you call the nested (funcA(){ return funcB(...);}, funcB(){ return funcD(); } etc.) 4 functions like this you will have 24*4 (just for example) = 96 and it will be too much
If we have an radio/timer or another interrupt (it's always happen async with your code) in the deep point of your functions the device will die...
1. For every parameter add its size to sum: byte=1,word=int=2,long=dword=4,float=2 etc.
2. Do the same thing for every inner (local) variable
3. The same thing to return parameter.
4. Every call uses about 4 bytes (2 for return code, 2 to push a base pointer).
For example:
float funcA(float a, float b)
{
float d = 0.5*a;
float c = 0.2878*d;
return d;
}
It will take:
1. Parameters: flota+float = 4 + 4 = 8bytes
2. Local variables: float+float = 4 + 4 = 8 bytes
3. return result: float = 4 bytes
4. return address + previous base pointer (for every call the same): 4bytes
And we have: 8 + 8 + 4 + 4 = 24bytes of stack to call function like this.
If you call the nested (funcA(){ return funcB(...);}, funcB(){ return funcD(); } etc.) 4 functions like this you will have 24*4 (just for example) = 96 and it will be too much
If we have an radio/timer or another interrupt (it's always happen async with your code) in the deep point of your functions the device will die...
-
- Posts: 255
- Joined: 26 Jul 2015 17:29
Re: Enable Hardware Watchdog
Can I shamefully self-promote a script of mine?
https://github.com/petergebruers/Z-Uno-BH1750
In that script I wrote:
// Global variables
// Z-Uno is a SOC with limited resources compared to e.g a Raspberry Pi
// or esp-32. To limit stack usage and parameter passing and data shuffling,
// I tend to use global variables instead of local or parameter passing. This goes against
// the idea of "abstraction" and "isolation of data". Whether this is better
// for such a small project is debatable...
This is to avoid stack issues. I bet lots of programmers do not like the code, because of all the globals. For example, look at function:
void CalculateDelay()
It uses no parameters and returns nothing, it only uses global variables. No abstraction at all! My teacher of "Structured Programming" would not be pleased.
Why did I not just move the code of CalculateDelay to the main loop, I use it only once? That would save even more stack space. A separate function is more readable and it allows me to debug the function with another compiler. You could add "inline" to the definition, but I do not think the compiler really inlines it... I have to recheck that with 2.1.1.
Also, memory used in interrupt handler and speed of the handler are optimized...
If you know some assembler, you can have a look at the .lst file, it lists locals, autos, and registers used in function calls...
https://github.com/petergebruers/Z-Uno-BH1750
In that script I wrote:
// Global variables
// Z-Uno is a SOC with limited resources compared to e.g a Raspberry Pi
// or esp-32. To limit stack usage and parameter passing and data shuffling,
// I tend to use global variables instead of local or parameter passing. This goes against
// the idea of "abstraction" and "isolation of data". Whether this is better
// for such a small project is debatable...
This is to avoid stack issues. I bet lots of programmers do not like the code, because of all the globals. For example, look at function:
void CalculateDelay()
It uses no parameters and returns nothing, it only uses global variables. No abstraction at all! My teacher of "Structured Programming" would not be pleased.
Why did I not just move the code of CalculateDelay to the main loop, I use it only once? That would save even more stack space. A separate function is more readable and it allows me to debug the function with another compiler. You could add "inline" to the definition, but I do not think the compiler really inlines it... I have to recheck that with 2.1.1.
Also, memory used in interrupt handler and speed of the handler are optimized...
If you know some assembler, you can have a look at the .lst file, it lists locals, autos, and registers used in function calls...
Meet me here: https://forum.fibaro.com/index.php?/pro ... rgebruers/ or here: memberlist.php?mode=viewprofile&u=564463
-
- Posts: 255
- Joined: 26 Jul 2015 17:29
Re: Enable Hardware Watchdog
-
Last edited by petergebruers on 26 Oct 2017 00:25, edited 1 time in total.
Meet me here: https://forum.fibaro.com/index.php?/pro ... rgebruers/ or here: memberlist.php?mode=viewprofile&u=564463
Re: Enable Hardware Watchdog
Thank you for your reply! I didn't had any information about how big the stack is, and I never though it would be that low. From where I should get this information? Is there a complete datasheet with information for developers?p0lyg0n1 wrote: ↑21 Oct 2017 01:56Arduino boards has AVR microchips installed on it. Z-Uno uses another architecture (i8051). AVR has about 256 bytes of stack and doesn't run another code at the same time. Z-Uno has just about 130bytes of stack and it runs two firmwares in the same time: main firmware that makes all Z-Wave processing and the sketch. So, we have to be shorter. You can simply calc the maximum usage of stack(it's not precise, but gives you a near value of stack usage):
Your method is a good way to estimate it. I'll keep that in mind.p0lyg0n1 wrote: ↑21 Oct 2017 01:561. For every parameter add its size to sum: byte=1,word=int=2,long=dword=4,float=2 etc.
2. Do the same thing for every inner (local) variable
3. The same thing to return parameter.
4. Every call uses about 4 bytes (2 for return code, 2 to push a base pointer).
For example:
float funcA(float a, float b)
{
float d = 0.5*a;
float c = 0.2878*d;
return d;
}
It will take:
1. Parameters: flota+float = 4 + 4 = 8bytes
2. Local variables: float+float = 4 + 4 = 8 bytes
3. return result: float = 4 bytes
4. return address + previous base pointer (for every call the same): 4bytes
And we have: 8 + 8 + 4 + 4 = 24bytes of stack to call function like this.
If you call the nested (funcA(){ return funcB(...);}, funcB(){ return funcD(); } etc.) 4 functions like this you will have 24*4 (just for example) = 96 and it will be too much
If we have an radio/timer or another interrupt (it's always happen async with your code) in the deep point of your functions the device will die...
Thank you!
-
- Posts: 31
- Joined: 07 Sep 2017 00:40
Re: Enable Hardware Watchdog
This would explain the issues I was seeing when I ported my app from Arduino to Z-uno..my gut feel was that it may be a stack issue and this seems to confirm it as a prime candidate, especially as the issue has gone away on the new release and I noticed in the release note there had been a lot of stack optimisation work