So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By McChubby007
#79997 Also, I forgot to mention... This is an advenced topic which also finds much use in operating system development, kernel code and operating system device drivers, which is where a lot of my experience comes from. Since you are interested the more general topics to look for are "lock free programming" which is the 'holy grail' of optimising system performance and there are many theories and concepts many of which cannot even be mathematically proven and so remain unassured but "probably might work". As I say it's complicated haha. There are youtube videos of C++ presentations which are very good indeed.

Other things to search for are "copy on write" or COW and "compare and swap" or CAS. CAS could be used for the esp8266 and there are algorithms available to do this. In addition, operating systems provide locks (such as mutexes), and indeed espressif Os-sdk which uses freeRTOS has mutexes available by application code. Mutexes need to be carefully used as 'deadlocks' can occur which then opens up a new topic which is "priority inversion". This is only relevant when using mutexes and RTOS's with threads and priority/scheduler schemes, but I may as well totally overload you with information in case you ever want to research it.

Sadly, because basic computer architecture, machine instructions and assembler programming are not taught widely and so rarely used by 'mainstream' programmers nowadays there are few people who venture into this area of programming. Luckily there is a growing number of self-taught Linux programmers some of which maintain the kernel and so we have hope not to lose this expertise. I am old enough to have started working when assembler programming was normal and that was my first programming language and so these concepts are easy to grasp, but for those not used to low-level computing this all comes as a great shock and hence why the 'Arduino crowd' get scared off or are just too lazy.

Luckily, since it is your job you will benefit from all of this.
User avatar
By lucasromeiro
#79998
McChubby007 wrote:There are three strategies you can use :
1. Use a read/write operation which cannot be interrupted. This is the best option but in the case of esp8266 is not available.
2. Turn off interrupts in main code when modifying shared variable. This is fine because interrupts are not missed they are just not 'serviced' by the system until re-enabled. It is not my preferred option but I think you could do this and many many other code does this. It would be a bad option if interrupts were off for long periods but this is not the case for your example code. EDIT 1 : However, if interrupts are disabled for longer than the interrupt frequency then interrupts will be lost as you would get one isr call even though multiple interrupts have occurred. CPUs such as ARM have an NVIC (nested interrupt controller) which handles this for the user and is a fantastic piece of hardware!
3. Only write in one place, read from the other place into a temporary/other variable. This is what I tend to use when it is a simple data type like an int, which is what you use. The ISR will do the 'var++'. The main code reads this value and compares to a local copy to determine the interrupt count, eg
Code: Select all===
ISR:
===
isrCount++;

=======
non-ISR:
=======
//--------------------------------------
// globals:
uint32_t isrCount = 0;

//--------------------------------------
// code body in regular periodic loop etc...
static uint32_t copyOfCount = 0;  // local copy of isr counter

uint32_t newCount = isrCount;  // atomic read of isr counter

// note using unsigned ints means count still works after isrCount rolls back to 0, it would not work for signed values
uint32_t numInterrupts = newCount - copyOfCount;  // get number of interrupts since last checked

copyOfCount = newCount;  // update local copy of isr counter

if (numInterrupts > 0) {
   // process ...
}


Very interesting!
I am evaluating whether to use option 2 or 3.

I was a bit confused in your explanation of option 3.
Exactly in this part:
uint32_t newCount = isrCount; // atomic read of isr counter
At the moment I am copying a variable that is being incremented in the interrupt to another global variable, can not there be an interruption between the assignment operations? since they are 2 32bit variables, and when copying from one register to the other of 8 bits, generate several instructions. Between these instructions could there be no interruption and cause me problems?

But if this works fine, I can copy the variable that increment the interrupt to a temporary variable, without errors, my problem has been solved! So it will be better to use the third option, it's simple and I do not need to stop the interruptions !!

I would like to comment on something else:
The test I told you would do up.
Increment a variable and not use anywhere.
That solved the problem! Do not worry anymore!
However, if I reset manually while there is a frequency above 10hz the equipment goes into a resets loop. It keeps resetting until I take out the pulses or decrease the frequency to 1hz or less.
I'll now investigate why this reset occurs, I believe I'll handle the interrupts very early and come into conflict with loading something else.
User avatar
By lucasromeiro
#80000
McChubby007 wrote:Also, I forgot to mention... This is an advenced topic which also finds much use in operating system development, kernel code and operating system device drivers, which is where a lot of my experience comes from. Since you are interested the more general topics to look for are "lock free programming" which is the 'holy grail' of optimising system performance and there are many theories and concepts many of which cannot even be mathematically proven and so remain unassured but "probably might work". As I say it's complicated haha. There are youtube videos of C++ presentations which are very good indeed.

Other things to search for are "copy on write" or COW and "compare and swap" or CAS. CAS could be used for the esp8266 and there are algorithms available to do this. In addition, operating systems provide locks (such as mutexes), and indeed espressif Os-sdk which uses freeRTOS has mutexes available by application code. Mutexes need to be carefully used as 'deadlocks' can occur which then opens up a new topic which is "priority inversion". This is only relevant when using mutexes and RTOS's with threads and priority/scheduler schemes, but I may as well totally overload you with information in case you ever want to research it.

Sadly, because basic computer architecture, machine instructions and assembler programming are not taught widely and so rarely used by 'mainstream' programmers nowadays there are few people who venture into this area of programming. Luckily there is a growing number of self-taught Linux programmers some of which maintain the kernel and so we have hope not to lose this expertise. I am old enough to have started working when assembler programming was normal and that was my first programming language and so these concepts are easy to grasp, but for those not used to low-level computing this all comes as a great shock and hence why the 'Arduino crowd' get scared off or are just too lazy.

Luckily, since it is your job you will benefit from all of this.


These techniques are very interesting.
At the moment I do not understand anything about it.
At university they are not teaching more assembler.
I confess that I'm afraid of the assembler.
Only by pure ignorance of language.
I do not know anyone who develops in assembler.
It's a rare thing to find. Unfortunately.
This level is so low, there are very few people who can. Only those who have this knowledge or are more experienced. From the time they taught assembler at universities.
Thanks for the COW and CAS tips, I'll read something about it!
Everything that involves ESP interests me!
Because eventually I need to use these things to do something new.
User avatar
By McChubby007
#80001 Well I am glad you have moved forward in solving the whole problem. It is always worthwhile trying to isolate code/functions in order to find the fault, but of course depends on the code whether you can do that or not.

In answer to yor question:

The main code (in the assignment) can be iunterrupted, you are correct. However, perhaps it might be considered a 'trick' but because it becomes a rollover counter the value will always be valid and consistent because it is an atomic 32 bit operation, so if the main code was interrupted between the load and store then the counter would be one less than it should be after the isr runs, but that would be the case even when the isr ran just after the main code too. Because the main code took a copy (which will be one less than the isr sets it to) the next iteration of the main code will find it to be an updated value and thus process the new count. I might not have explained it very well, but it does work and is a common technique. It is important that the main code 'polls' this count frequently enough for your purposes: This would depend whether you must process each interrupt after it has happened or you can handle multiple at one time. You might be tempted to also set a 'flag' in the isr after the increment and clear it in the main code but you would just introduce another 'window' for inconsistent data since you now have two variables that may be interrupted part way through one or both.

If I think of a better explanation I will write it here later :-)