Embedded 手臂皮层:使用位绑定的互斥

Embedded 手臂皮层:使用位绑定的互斥,embedded,arm,mutex,cortex-m3,Embedded,Arm,Mutex,Cortex M3,鉴于此,在手臂上,我可以: 原子读取单个位 原子地设置单个位 原子清除单个位 如何将这些操作组合为互斥体样式的操作集: try lock take lock release lock 似乎try\u lock或take\u lock需要两个非原子操作 我需要更多的控制来完成这项任务吗?禁用全局中断可以做到这一点,但似乎应该有一种更为外科手术的方法。一些搜索后的信息: " ARM-M3位带 ARM的微控制器内核提供了另一种实现信号量的方法。对位带别名区域中变量的写访问会导致在系统总线级别对位

鉴于此,在手臂上,我可以:

  • 原子读取单个位
  • 原子地设置单个位
  • 原子清除单个位
如何将这些操作组合为互斥体样式的操作集:

try lock
take lock
release lock
似乎
try\u lock
take\u lock
需要两个非原子操作


我需要更多的控制来完成这项任务吗?禁用全局中断可以做到这一点,但似乎应该有一种更为外科手术的方法。

一些搜索后的信息:

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

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

/*
 * 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;
        }
    }
}
/*
*释放锁。
*
*@note lock必须指向完全对齐的32位整数。
*(原子设置为0)
*
*@成功返回1
*/
内部rwl\U自由锁(易失性uint32\U t*锁){
*lock=0;
返回1;//始终成功
}
/*
*试图获得锁
*@param谁是获取锁的客户端
*@指向互斥锁的锁指针(内存中的uint32_t值)
*@note lock必须指向完全对齐的32位整数。
*(仅当设置为0时,才自动设置为1)
*/
内部rwl\u TryLock(易失性uint32\u t*lock,内部who){
//锁的初步检查
如果(*lock==0){
Var_SetBit_BB((uint32_t)lock,who);
如果(*lock==(1Your
rwl\u 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;
}
int rwl\u TryLock(volatile uint32\u t*lock,int who){
Var_SetBit_BB((uint32_t)lock,who);

如果(*lock==(1我从未在ARM上使用过位绑定;相反,我倾向于对所有此类操作使用load exclusive/store conditional。使用循环以独占方式加载旧值,计算新值,并使用条件存储将其写回。循环直到条件存储成功(如果不是第一次的话,第二次可能会).

位绑定在这种情况下不起作用。它只是在设备寄存器文件和内存中设置位的一种非常简洁的方法。使用Load Exclusive和Store Exclusive指令来实现信号量/互斥。下面是一个可以使用的示例文档,它使用这些指令实现信号量,并详细说明了如何实现工作


这就是说,您可以通过使用位带来减少互斥锁的内存占用…

如果有两种东西试图访问锁,那么两种访问似乎都会报告失败。更好的方法是使用ldrex/strex spinloop。也就是说,在存在锁的情况下,位带访问在多大程度上保证原子性DMA之类的事情?如果DMA写入和位带写入大致同时发生,DMA写入是否保证不会在位带写入的“读”和“写”方面发生?