Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP8266 and ExternalInterruptHandler #25

Closed
littleyoda opened this issue May 22, 2019 · 10 comments
Closed

ESP8266 and ExternalInterruptHandler #25

littleyoda opened this issue May 22, 2019 · 10 comments

Comments

@littleyoda
Copy link
Contributor

littleyoda commented May 22, 2019

Hi

testing my framework for a esp8266, I found three problems in ExternalInterruptHandler.
Because I'm not sure how to fix the problems platform independent, I have not created a Pull Request.

  1. All Functions called by an interrupt must be declared as ICACHE_RAM_ATTR

=>
ICACHE_RAM_ATTR void ExternalInterruptHandler(void)

  1. millis()
    millis() return a unsigned long on esp8226 and esp32. lastMicros, actMicros and bitMicros are currently declared as word/unsigned int. For the esp8266 and esp32 unsigend long is necessary,

static word lastMicros;
unsigned int actMicros, bitMicros;

=>

static unsigned long lastMicros = 0;
unsigned long actMicros, bitMicros;

@MicroBahner
Copy link
Contributor

MicroBahner commented May 23, 2019

Hi Sven,

All Function called by an interrupt must be declared as ICACHE_RAM_ATTR

Is that different from ESP32, or can we use the same attribute as in ESP32?

millis()
millis() return a unsigned long on esp8226 and esp32. lastMicros, actMicros and bitMicros are currently declared as word/unsigned int. For the esp8266 and esp32 unsigend long is necessary,

micros() returns always unsigned long - even on AVR processors. Because we only need to measure times less then 65000µs, I decided to use unsigend int, because this is faster an an 8-bit processor like ATmega.
On processors with a 32bit Core ( e.g. esp8266 ) 'unsigned int' and 'unsigend long' ist the same.
'unsigend long isn't neccessary, With 'unsingend int' the code is platform independent.

But you are right with the 'static word lastMicros'. To be independent how 'word' is defined, we should use 'unsigned int' there too.
=> static unsigned int lastMicros = 0;

Edit: 'word' seems to be defined as 'uint16_t' on esp and as 'unsigned int' on STM32, which of course is incompatible. On an AVR both is the same. So we should not use 'word' in any place.

@MicroBahner
Copy link
Contributor

MicroBahner commented May 23, 2019

Hi,
When we introduced the support for ESP8266 it worked, so what had changed?
I tried with an older version (2.0.0) of the esp8266 Software, and in this version 'word' came out to be a 32bit variable.
Obviously the definition of 'word' has been changed in one of the following versions.
We must not use 'word' in variable definitions and change that to 'unsigend int'. ( That was my mistake :( )

@kiwi64ajs
Copy link
Contributor

kiwi64ajs commented May 25, 2019 via email

@littleyoda
Copy link
Contributor Author

littleyoda commented May 25, 2019

Great. Thanks. I will test it.

@MicroBahner:
I have tested it with the old arduino framework quite extensive (=using it for my own turnout motors). Some weeks ago I received bug reports that the DCC Part does not work. I spend quite a while to debug this topic and found the problem with the millis(). Your observations explain this problem pretty well. Thanks

EDIT: Meanwhile I found the related Issue

Later crashes were reported. Results from the missing ICACHE_RAM_ATTR.
At the time I added the esp8266 support to NmraDcc, I was not aware of ICACHE_RAM_ATTR and I had no crashes in my application.

@kiwi64ajs
Copy link
Contributor

kiwi64ajs commented May 25, 2019 via email

@MicroBahner
Copy link
Contributor

MicroBahner commented May 30, 2019

Hi Alex,

  1. I’ve change the storage for the Micros() value unsigned long as per the Arduino micros() documentation.

I think we should stay to the solution with unsigned int. On 32bit Cores this is the same as unsigned long. But the AVR is a 8 bit processor, and it's faster with unsigned int than with unsigned long. Unsigned int is sufficient for our needs, it worked pretty well so far.

In an actual project I found another issue. When writing the IRQ without use of timer 0, I allowed nested interrupts, to give short, but timecritical interrupts a chance. Now the problem is the other way round: There is another comparabel long IRQ ( about 50...100µs) which also allows nested interrupts. But if such an IRQ interrupts the DCC IRQ, I run into trouble. So I need a possibility to switch of the nested IRQ feature.
My proposal is to make this feature configurable by a #define in the .h file. If you have timecritical short IRQ's you can enable it, but usually it should be disabled, bacause this is the more safe mode for DCC. It is easy, because you have only to mask out the interrupt-enable statement in the DCC-IRQ by this define.

I'll make a proposal (pull request) the next days after my tests.

Regards
Franz-Peter

@kiwi64ajs
Copy link
Contributor

Ok, I believe I've merged in STM32 Nested Interrupts handling changes as well as the lastMicros type definition into master.

Before I tag the repo to 2.0.2 can you guys check that this doesn't break the STM32, ESP8266 and ESP32 versions as well as the original AVR - that would be very helpful as we've added a bunch of changes since 2.0.0 and it would be good to get them released.

@MicroBahner
Copy link
Contributor

Hi Alex,

I did a first test and recognized that I am no longer able to read CV Values with my Märklin MS2.

I saw in servicemode there is a new callback 'notifyAdvancedCVAck' which is called instead of the old 'notifyCVAck', but only if the RailCom bit in CV29 is set. If this bit is not set, nothing is called at all. I am no RailCom expert, but I cannot imagine that this callback is sufficent to build a RailCom capable decoder. Acknowledgement and feedback in RailCom is completely different from the simple 6ms current pulse in standard decoders.

But in any case, I think if the railcom bit is NOT set, servicemode schould behave just like it was in earlier versions ( and call 'notifyCVAck' if a pulse has to be generated ).

Regards

Franz-Peter

I'll do further tests the next days/weeks ;)

@MicroBahner
Copy link
Contributor

Hi Alex,
the last days I did intensive tests with ESP8266, STM32F103 and AVR. I tested together with my MobaTools what created heavy interrupt load. All worked well.
But I had to roll back the changes regarding 'notifyAdvancedCVAck', because reading of CV values did not work anymore. I'll create a pull request with these changes.

@kiwi64ajs
Copy link
Contributor

See my comments in the other Issue. I've separated the types of Ack so the common code gets passed the function pointer for the correct Ack Function, so this should now work correctly for Service Mode again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants