5

I have a question about using semaphores in cortex m3. I've found a thread "ARM cortex: mutex using bit banding" ARM cortex: mutex using bit banding . There is a short description of the problem, and the last answer would be good for my problem - but I am not sure how can I implement it in c/c++.

"I've never used bit-banding on the ARM; my inclination instead would be to use load-exclusive/store-conditional for all such operations. Use a loop to load-exclusive the old value, compute the new value, and use a conditional store to write it back. Loop until the conditional store succeeds (which it probably will the second time, if it doesn't the first)."

I would be very grateful if someone could post a short code how to use it.

Thanks, Martin

artless noise
  • 21,212
  • 6
  • 68
  • 105
Martin R
  • 113
  • 3
  • 8

1 Answers1

4

Please note that bit-banding is not available on all implementations (most notably, it's missing in NXP's LPC1xxx series).

For an official way of implementing semaphore using LDREX/STREX, see ARM Synchronization Primitives Development Article. It uses ARM assembly.

Below is a simple class I made that uses compiler intrinsics (untested!). The name is probably a misnomer since it actually works like a mutex. It's also missing DMB instructions which might be necessary.

class Semaphore
{
  enum { SemFree, SemTaken };
  // semaphore value
  int s;  

public:
  // constructor
  Semaphore(): s(SemFree) {};

  // try to take the semaphore and return success
  // by default block until succeeded
  bool take(bool block = true)
  {
    int oldval;
#if defined(TARGET_LPC1768) // on Cortex-M3 we can use ldrex/strex
    do {
      // read the semaphore value
      oldval = __ldrex(&s);
      // loop again if it is locked and we are blocking
      // or setting it with strex failed
    }
    while ( (block && oldval == SemTaken) || __strex(SemTaken, &s) != 0 );
    if ( !block ) __clrex(); // clear exclusive lock set by ldrex
#else // on arm7 there's only swp
    do {
      // swp sets the pointed data to the given value and returns the previous one
      oldval = __swp(SemTaken, &s);
      // if blocking, loop until the previous value becomes 0
      // which would mean we have successfully taken the lock
    }
    while (block && oldval == SemTaken);
#endif
    return oldval == SemFree;
  }

  // release the semaphore
  void release()
  {
    s = SemFree;
  }
};
Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • Hi Igor, thanks for your reply. I'm not so sure how can I use your code. All I read about semaphores was that there was a function semop() and you could do something like this: semop() - lock . . - this is secure code? (am I right?) . semop() - unlock So, now I do have to do something like this? a.take() . . - my secure code here . a.release() Thanks, Martin – Martin R Jan 17 '12 at 14:26
  • The code does not become "secure" just because you use semaphores; they should be used if there's a need for that. Normally you use them to protect a common resource from simultaneous access by possibly concurrent code paths. If you don't have some kind of an RTOS or a scheduler it's unlikely that you need semaphores. I would suggest you to make a new question and describe the _actual_ problem you're trying to solve, then we can see if you need semaphores and if so, how to apply them. – Igor Skochinsky Jan 17 '12 at 18:02
  • Hi Igor, thanks for your answer and sorry for not responding for a while... I use freeRTOS and it seems that I need semaphores. After a quick check about semaphores I've understood my problem - and of course my previous question wasn't smart :) Anyway, thanks for your help. – Martin R Jan 23 '12 at 09:49
  • 1
    FreeRTOS has [its own](http://www.freertos.org/Inter-Task-Communication.html) synchronization objects so I would recommend using those. If you think my answer was helpful, you should accept it - more people will be willing to answer your questions if they see you accept answers. – Igor Skochinsky Jan 23 '12 at 11:36