B4R Question Simple interrupt in B4R

johnf2013

Member
Licensed User
I have a C++ app running on an Arduino Nano which has at its core a fast A/D read triggered by a pin interrupt. So, a shaft running at around 3000rpm has a sensor which triggers the interrupt every revolution. I then need to save the time this occurs and then do several hundred fast A/D converter reads of each of two other sensors, noting the time of each read. The values are saved for later use.

Sensing the interrupt is the only time critical job. Since I need better than one degree of resolution, the interrupt latency variation cannot exceed 28uS, which it appears I cannot achieve with the polled mechanism in B4R. Note, I can calibrate out the interrupt latency but I must have a latency variation of less than 28uS.

The A/D is read as fast as possible for many revolutions and the data stashed away. After enough revolutions there is data for every degree of position. If not it doesn't matter because it is all done again the next time the interrupt is enabled at which time the stale data is updated with new. A little bit of randomness goes a long way!!

This code works very well on an Arduino Nano, plodding along at 16MHz. It sends the data in packets on a USB link to a PC and a BC++ program does the number crunching and display. All very pretty but not very useful in a workshop environment.

I have rewritten the PC code in B4A to run an a mobile device and use WiFi/BT. This too works very well and is almost complete. It has the data structures to receive the data, but currently fills them with simulated data. Async streams looks like the best solution since there is some other data to be packaged as well as the raw sensor data.

I had planned to write the Arduino/ESP8266/ESP32/??? code in C++ but looking through the B4R documentation I seemed clear I could do this much more quickly with B4R - except for one problem....

How to manage the pin interrupt. It is a simple bit of code. The ISR just gets a system uS timer value and saves it somewhere that B4R can find it. The readings of the A/D can be handled by B4R as long as the timer can be read reliably and this does not need to happen in the ISR. No B4R code will be called from the ISR - I just need to know where B4R keeps its system timer and how to get a pin interrupt to work without annoying B4R.

So, after a lot of reading I am no closer to figuring this out than when I started. It is clear I need to use an object called pollers but I cannot work out how to use it. Reading source on GitHub is no help either. Some of the headers I searched for unsuccessfully for hours and without them I have no clue what some of the functions do, or how. Even experienced C++ programmers need a kickstart in the right direction to solve some problems.

Does anyone have any idea how I may go about this?

I could of course write it in C++ but that would mean figuring out how to duplicate the protocol used by B4A and AsyncStreams. Maybe this will be easier. I will take advice on this. B4R certainly makes the WiFi stuff easier to program.

I would also like to avoid a hardware solution. It's not difficult but makes the product more expensive and seems such a waste when I have perfectly good micro.
 

Erel

Administrator
Staff member
Licensed User
Running code inside interrupts is problematic as the interrupt could be raised at any given point and you don't have any reasonable way to control it. Its a bit like running multithreaded code without locks or any other synchronization features.

The fastest polling mechanism is AddLooper. I'm not sure that it is fast enough for your requirements. You can see some performance numbers here: https://www.b4x.com/android/forum/threads/timers-loopers-and-callsubplus.65989/#content

You can add an interrupt handler with inline C code.
Store the data in a global variable and then write it in the next loop from the B4R code.
 

bdunkleysmith

Active Member
Licensed User
When I ported an app which I had running on a Freetronics Leostick and used an interrupt to an ESP8266 based shield, this is the skeleton of what I used in lieu of an interrupt:

B4X:
Sub Process_Globals
    Public Serial1 As Serial

    Private PIN_CLK As Pin
    Private Time As ULong

End Sub

'Subroutine to process fall on clock input
Sub PIN_CLK_StateChanged (State As Boolean)
    If State = False Then                            'Clock has fallen

        Time = Micros

    End If
End Sub
It may not be suitable for you, but I found polling using AddLooper was problematic for me and the above worked for me.
 

johnf2013

Member
Licensed User
...the interrupt could be raised at any given point...
That's the whole point of it.

You can add an interrupt handler with inline C code.
Store the data in a global variable and then write it in the next loop from the B4R code.
That is what I had in mind. This is a very quick in and out - interrupt, get the system timer value, save it somewhere, and get out. At 3000rpm it does not happen very often but the response must be quick.
How do I access B4A's system timer?
Also, what is the pollers object and where does it fit into this problem?
Thanks.
 

Erel

Administrator
Staff member
Licensed User
How do I access B4A's system timer?
Also, what is the pollers object and where does it fit into this problem?
You don't need to do anything special with timers or pollers.

Implement the interrupt in the C code and update a global variable with the data you want to send.

Use AddLooper to run a sub every loop. Check the global variable(s) in this sub and send the data.

https://www.b4x.com/android/forum/threads/65714/#content
 
Top