ARM皮质:使用位带的互斥锁

时间:2010-05-18 13:01:55

标签: embedded arm mutex cortex-m3

鉴于此,在ARM Cortex M3上,我可以:

  • 原子地读取一位
  • 原子地设置一个位
  • 原子地清除一位

如何将这些组合用于互斥式样式的操作:

try lock
take lock
release lock

似乎try_locktake_lock需要两个不是原子的操作。

我需要更多控制才能完成此任务吗?禁用全局中断会这样做,但似乎应该有更多的手术方法。

4 个答案:

答案 0 :(得分:4)

如果在调用锁时已经保持锁定,则rwl_TryLock()不一定会返回失败(您的编译器应至少提供有关没有返回值的代码路径的警告)。请尝试以下方法:

int rwl_TryLock(volatile uint32_t *lock, int who){

    Var_SetBit_BB((uint32_t)lock, who);
    if(*lock == (1<<who)){ // check that we have exclusive access
        // got the lock!
        return 1;
    } 

    // do not have the lock
    Var_ResetBit_BB((uint32_t)lock, who); // clear the lock flag
    return 0;
}

请注意,上述内容不适用于递归声明相同的锁(即,如果who == 1指定的任务已经锁定并尝试再次声明它,上面的代码将无法正常工作),但你的原作也是如此。

此外,可以很快地在Cortex M3上禁用/启用中断(这是对NVIC寄存器的简单更新)。你确定你的系统不能再使用额外的几个中断延迟周期来保持处理锁定数据结构的代码简单(这通常意味着更容易纠正)吗?

答案 1 :(得分:2)

比特条带不适用于这种情况。它只是在设备寄存器文件和内存中设置位的一种非常简洁的方法。使用Load Exclusive和Store Exclusive指令来实现您的信号量/互斥量。这是一个可以使用的示例文档,它使用这些指令实现信号量,并详细说明了它的工作原理。

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/CHDDIGAC.html

话虽这么说,你可以通过使用位带来减少互斥锁的内存占用...

答案 2 :(得分:1)

一些搜索后的信息:

” ARM Cortex-M3位带 ARM的微控制器内核提供了另一种实现信号量的方法。对位带别名区域中的变量的写访问导致对系统总线级别的位带区域中的存储器位置的原子读 - 修改 - 写访问。 这如何转化为信号量?位带区域中的变量可以用作信号量的容器。每个客户在该容器中“拥有”一点。每当客户端需要声明信号量时,它通过将1写入位带别名区域中的相应位置来设置其自己的位。然后它将读取容器(位带区域)并检查没有设置其他位,这意味着客户端已成功声明了信号量。如果设置了其他位,则客户端必须再次清除其自己的位,然后重试(可能在等待之后)。 “ (source

这是我粗略的(未经测试的)解释:

/*
 * Frees a lock.
 *
 * @note lock must point to a fully aligned 32 bit integer.
 * (atomically set to 0)
 *
 * @returns 1 if successfull
 */
int rwl_FreeLock(volatile uint32_t *lock){
    *lock = 0;
    return 1; // always successful
}

/*
 * Attempts to acquire a lock
 * @param who is the client taking the lock
 * @lock pointer to the mutex (uint32_t value in memory)
 * @note lock must point to a fully aligned 32 bit integer.
 * (atomically set to 1 only if set to 0)
 */
int rwl_TryLock(volatile uint32_t *lock, int who){
    // initial check of lock
    if(*lock == 0){
        Var_SetBit_BB((uint32_t)lock, who);
        if(*lock == (1<<who)){ // check that we still have exclusive access
            // got the lock!
            return 1;
        } else {
                    // do not have the lock
            Var_ResetBit_BB((uint32_t)lock, who); // clear the lock flag
            return 0;
        }
    }
}

Var_Set_BB / Var_Reset_BB:使用位带设置/清除一位。 (原子)

然而,它不起作用!!!

答案 3 :(得分:0)

我从来没有在ARM上使用过bit-banding;相反,我倾向于对所有这些操作使用load-exclusive / store-conditional。使用循环加载 - 保留旧值,计算新值,并使用条件存储将其写回。循环直到条件存储成功(它可能是第二次,如果它不是第一次)。