Search code examples
carmsemaphorecortex-m

Cortex M3 - how to use semaphores


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


Solution

  • 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;
      }
    };