1

I am writting a C code for Atmega Microcontroller and I want to use Mutex in it. What library to include? and how to implement the code?

I want this Mutex to prevent a Timer interrupt from changing a variable during a function.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Abuzaid
  • 853
  • 8
  • 28

3 Answers3

3

A mutex is not the right thing to use between a regular interrupt handler and the main program, resp. a thread. Main problem is that the interrupt handler cannot be suspended and later continued once it gets the mutex.

A deferred interrupt handler is different and for this it may work if the OS provides the corresponding features (but it is still uncommon). A a mutex is part of a multi-threading operating system and therefore does not come as isolated library. If you use an OS, you should find information how/when/were to use them in its documentation.

As stated in a comment, disable that interrupt while modifying the variable is one alternative. As nothing is for free (except FOSS, of course;-), this increases interrupt latency by the duration of the locked portion.

You might alternaitvely use atomic operations from C11 standard, but not sure if they are available for this platform (they are optional). @Clifford has shown an alternative if these are not available.

Regarding interrupt control: If you have an interrupt handler, you already must have enabled the interrupt, so it should be straight-forward how to disable it. However, a better way would be to use the CPU instructions which enable/disable the global interupt signal (might be something like dint/eint - just look into the reference manual). Most toolchains provide intrinsic functions for C(++) either built-in or in a header file, eliminating the need for assembler.

A solution without interrupt locking would be to use a helper flag:

volatile uint8_t modified;  // global like ticks

ticksInterrupt() {
    modified = 1;
    // update ticks
}

uint32_t getTicks() {
    uint32_t result;
    do {
        modified = 0;
        result = ticks;
    } while ( modified ) ;
    return result;
}

This is faster and likely less code than a 32bit compare on 8bit CPUs at the cost of an additional flag-byte in RAM and the additional write to modified in the int-handler (IIRC, this is a single instruction on AVR).

This approach assumes non-nested interrupts (which is standard on AVR and other 8-/16-bitters, but not mandatory - you need to know this anyway, however).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • Probably because this line is just wrong: " A a mutex is part of a multi-threading operating system and therefore does not come as isolated library". Anybody can use a mutex for protection of a shared resource, whether or not you are running on top of an OS. Yes, they are most commonly used w.r.t. threading, but can be used in other places too. – asmvolatile Feb 23 '18 at 21:33
  • @Brett: Maybe you have typical desktop/server OS in mind. This is about bare-metal, resp. low-level embedded systems. OS covers much simpler frameworks. A mutex always requires some multi-threaded environment, which is the OS on such embedded systems. It still is not the correct object to use for the discussed job. Also notice the time-stamp of my comment. As I learnt those are hardly useful, I removed it. – too honest for this site Feb 23 '18 at 21:43
  • "A mutex always requires some multi-threaded environment" nope, I've implemented my own mutexes for plenty of embedded systems without an OS/RTOS. You are correct that it is *usually* not the best tool for the job, but the principle of a mutext doesn't require a "thread" in the OS sense. As long as you appropriately handle priority exclusion, you can still use them within interrupt handlers (even if this is seen as bad form). Especially if you use a non-blocking mutex....i.e. Interrupt-->Attempt to acquire lock--> fail-->bail out of the IRQ. – asmvolatile Feb 23 '18 at 21:47
  • @Brett: However you call it, it **is** some kind of OS and multi-threading. AWithout multiple threads and concurrency, it just does not make sense to use a mutex. That does not imply you always have to use mutexes to coordinate shared resources. There are much better ways using e.g. actor-based approaches. Answers here are **always** in context of the questions. And for that, a mutex just does not make any sense. Nor does it between an interrupt handler and main code. You might do it, but this results in spaghetti code and debugging hell. It's just a very bad idea. – too honest for this site Feb 23 '18 at 22:07
  • I'll leave this here, because comments are not for extended discussions. Please feel free to provide your own answer or ask another question if you feel you have to. – too honest for this site Feb 23 '18 at 22:10
2

If you are using an RTOS or threading library, it almost certainly includes a mutex API, and if you are not then you don't need a mutex. In any case you cannot use a mutex in an interrupt handler in any case.

Instead, if your timer variable is modified in the interrupt context and is non-atomic, then a solution is to ensure the same value is read twice in succession to be sure it is consistent. For example:

volatile uint32_t tick ;

__interrupt timerISR()
{
    tick++ ;
}

uint32_t getTick()
{
    uint32_t tickval = tick ;
    while( tickval != tick )
    {
        tickval = tick ;
    }
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • On AVR dint/eint wrapped around the read is an acceptable alternative. Increases interrupt latency slightly, but avoids the looping overhead and inherent indeterminism. Less invasive might be locking just this interrupt, but that might be result in even longer latency for the actual handler. – too honest for this site May 10 '15 at 20:38
  • 1
    @Olaf : Whether disabling interrupts is acceptable is application specific. A marginal delay in obtaining a tick reading in the thread context may be better than delaying a critical interrupt by a few microseconds - almost be definition, a task operating at tick resolution can probably stand the delay; while an interrupt may not. – Clifford May 10 '15 at 20:46
  • Ok, I missformulated it: and I should have not as you seem to be pretty nit-picky about phrases. Replace "is an" by "can be", You, however, might be a bit more relaxed and possibly think twice commenting aggressively if a non-native speaker used few slightly missleading words. If you read my comment completely, you will find that I very well addressed the problem of increased latency. – too honest for this site May 10 '15 at 20:51
  • 1
    @Olaf : I did not intend to appear aggressive - my apologies if you interpreted my response that way - although I am not sure why you did. I entirely agree with you; but in most cases I would select the approach in my answer; but that may be entirely down to the kind of applications I am involved in developing. I am no more nit-picky on semantics than a compiler - this is a domain where such things matter. The interrupt disable solution is attractively simple, but because of that one might choose it over my suggestion without perhaps being clear of the consequences. – Clifford May 10 '15 at 21:00
  • You might not have wanted to, but fact is that's how it sounded to me. I for myself am also pretty nit-picky, but I also tend to challenge the reader to think for himself, not just present a final solution. Instead, I triy to give him all required information, so he can dicide by himself. Your answer, btw. did very well also state this approach as the only solution; you did not even mention different approaches (like a "modified" flag for instance: this would be even faster than the compare on AVR and atomic (I'll update my answer accordingly). – too honest for this site May 10 '15 at 21:07
  • @Olaf : Yes there are other solutions; the critical thing I felt was that a mutex was not one of them. This solution allows the ISR to remain minimally short. This is a Q&A site - I think direct answers are appropriate. Please do elaborate your answer with your equally valid solutions. I will change mine to be slightly less emphatic - fair point. – Clifford May 10 '15 at 21:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77460/discussion-between-olaf-and-clifford). – too honest for this site May 10 '15 at 21:27
  • @Clifford, I read your post and i noticed " you cannot use a mutex in an interrupt handler ", could you please clarify why and what are the alternatives if we want create a synchronous communication between 2 interrupt driven systems? – fedi Jan 26 '16 at 07:01
  • @fedi : You need to post a question; SO is not a discussion forum. – Clifford Jan 26 '16 at 07:28
  • could you pls help me : http://stackoverflow.com/questions/35011322/why-not-to-use-mutex-inside-an-interrupt?noredirect=1#comment57751148_35011322 – fedi Jan 26 '16 at 11:13
0

Mutex management functions cannot be called from interrupt service routines (ISR), unlike a binary semaphore that can be released from an ISR. CMSIS-RTOS uses reentrant/recursive mutexes only.

Semaphore tokens can be acquired from threads and released from threads and ISRs.

KEIL CMSIS

xuuncle
  • 1
  • 1