Help - using semaphores with inline assembly on spark core

I have a function that sets up a DMA transfer and starts it. Then it blocks using a semaphore until the interrupt handler indicating that the DMA transfer has completed unblocks the semaphore.

When I enter the blocking semaphore the core appears to stop executing code and within a second the RGB led goes white and then flashes blue, cyan to breathing cyan. However I am unable to reconnect to the serial port to determine if the core is still running or if it has hung.

I am very confused by inline assembly. I have read this thread -

and it looks like a mixture of AT&T and Intel format. The registers are prefixed with % but the source and destination registers are reversed.

I'm trying to implement a semaphore to act as a messaging system allowing a blocked function to continue from an interrupt handler.

Here is the ARM assembly code on page 19 from ARM Synchronization Primitives

; sem_dec
; Declare for use from C as extern void sem_dec(void * semaphore);
    EXPORT sem_dec
sem_dec PROC
  1 LDREX r1, [r0]
    CMP r1, #0         ; Test if semaphore holds the value 0
    BEQ %f2            ; If it does, block before retryingARM Synchronization Primitives
    SUB r1, #1         ; If not, decrement temporary copy
    STREX r2, r1, [r0] ; Attempt Store-Exclusive
    CMP r2, #0         ; Check if Store-Exclusive succeeded
    BNE %b1            ; If Store-Exclusive failed, retry from start
    DMB                ; Required before accessing protected resource
    BX lr
  2                    ; Take appropriate action while waiting for semaphore to be incremented
    WAIT_FOR_UPDATE    ; Wait for signal to retry
    B %b1
ENDP

; sem_inc
; Declare for use from C as extern void sem_inc(void * semaphore);
    EXPORT sem_inc
sem_inc PROC
  1 LDREX r1, [r0]
    ADD r1, #1         ; Increment temporary copy
    STREX r2, r1, [r0] ; Attempt Store-Exclusive
    CMP r2, #0         ; Check if Store-Exclusive succeeded
    BNE %b1            ; Store failed - retry immediately
    CMP r0, #1         ; Store successful - test if incremented from zero
    DMB                ; Required before releasing protected resource
    BGE %f2            ; If initial value was 0, signal update
    BX lr
2                      ; Signal waiting processors or processes
    SIGNAL_UPDATE
    BX lr
ENDP

Here is my inline assembly code

// sem_dec
// Declare for use from C as extern void sem_dec(void * semaphore);
void sem_dec(volatile uint32_t *semaphore) {

asm volatile ("@sem_dec      \n"
"1: LDREX   r1, [r0]         \n"
"   CMP	    r1, #0           \n"   // ; Test if semaphore holds the value 0
"   BEQ     2f               \n"   // ; If it does, block before retrying
"   SUB     r1, #1           \n"   // ; If not, decrement temporary copy
"   STREX   r2, r1, [r0]     \n"   // ; Attempt Store-Exclusive
"   CMP     r2, #0           \n"   // ; Check if Store-Exclusive succeeded
"   BNE     1b               \n"   // ; If Store-Exclusive failed, retry from start
"   DMB                      \n"   // ; Required before accessing protected resource
"   BX      lr               \n"
"2:                          \n"   // ; Take appropriate action while waiting for semaphore to be incremented
"   WAIT_FOR_UPDATE          \n"   // ; Wait for signal to retry
"   B       1b               \n"
    : [r0] "=r" (semaphore));   
}

// sem_inc
// Declare for use from C as extern void sem_inc(void * semaphore);
void sem_inc(volatile uint32_t *semaphore) {

asm volatile ("@sem_inc        \n"
"1:  LDREX   r1, [r0]          \n"
"    ADD     r1, #1            \n"   // ; Increment temporary copy
"    STREX   r2, r1, [r0]      \n"   // ; Attempt Store-Exclusive
"    CMP     r2, #0            \n"   // ; Check if Store-Exclusive succeeded
"    BNE     %b1               \n"   // ; Store failed - retry immediately
"    CMP     r0, #1            \n"   // ; Store successful - test if incremented from zero
"    DMB                       \n"   // ; Required before releasing protected resource
"    BGE     %f2               \n"   // ; If initial value was 0, signal update
"    BX      lr                \n"
"2:                            \n"   // ; Signal waiting processors or processes
"    SIGNAL_UPDATE             \n"
"    BX      lr                \n"
     : [r0] "=r" (semaphore): );
}

I'm a bit confused as to if I have the assembly correct. I don't have a debugging environment setup yet so it's very difficult to determine what the assembly language is doing.

You might have better luck using the built-in synchronization primitives. I used them in the spark core driver code to implement a semaphore for the internal spi bus.

https://github.com/spark/firmware/blob/feature/hal/platform/MCU/STM32F1xx/SPARK_Firmware_Driver/src/spi_bus.c

1 Like