2

質問を明確にするために、次のものがあると仮定します。

  1. 静的ボタン オブジェクト:static Button_T sButton = {0};
  2. Button を取得する関数:メイン ループ コンテキストvoid GetButton(Button_T * p_button);から呼び出される
  3. ISR ハンドラ:void ButtonISRHandler(void);

仮定:

  1. GetButton実行は、実行されない割り込みによって中断される可能性がありますButtonISRHandler
  2. ButtonISRHandler実行は他の割り込みによって中断される可能性があります
  3. GetButtonButtonISRHandler実行にかかる時間は、2 つの割り込み呼び出し間の最小時間よりも短くなります。
  4. ボタン割り込みは、たとえば 10 ミリ秒ごとにトリガーされる周期的な割り込みです。
  5. ButtonISRHandlerボタンの PIN 状態の確認や、ボタンがタッチされたかどうかの検出 (タッチ ボタンの場合) などの手順があります。特定の PIN 状態が、たとえば 5 回の連続した呼び出しで安定している場合、sButtonオブジェクトの状態が更新されます。
  6. Button_Tは一般的なオブジェクトです。従来のタクト スイッチやタッチ ボタンなどの可能性があります。
  7. ScanButtonAndUpdateButton_T オブジェクトのリストを処理できますが、GetButton関数は 1 つのボタン オブジェクトに対してのみ動作します。

問題は次のとおりです。プログラムカウンターが内部にあるときに割り込みが発生する可能性がある古典的なケースGetButton

質問は次のとおりです。割り込みを無効にせずGetButtonに同期する方法は?ButtonISRHandler

私のターゲット プロセッサは LDREX/STREX 操作のない Cortex M0 であるため、この場合の優れたソリューションとなる C11 のアトミックを使用できません。

私の提案する解決策

でクリティカル セクションを使用しGetButtonます。

プログラム カウンタがクリティカル セクション内にあるときに割り込みが発生した場合は、割り込みでは処理せずScanButtonAndUpdate、割り込みで処理しExitCriticalSectionます。実行を延期ScanButtonAndUpdateします。

ScanButtonAndUpdate割り込みとメイン コンテキストから同時に関数を呼び出す可能性はありません。この動作はセマフォによって保護されています。

実装

#define SEMAPHORE_GIVEN                             0
#define SEMAPHORE_TAKEN                             1

typedef uint32_t BaseType_T;
typedef struct Button_T;

static volatile BaseType_T sSemaphore = SEMAPHORE_GIVEN;
static volatile bool sIsPendingISR = false;
static volatile Button_T sButton = {0};

void GetButton(Button_T * p_button)
{
    EnterCriticalSection();

    memcpy(p_button, &sButton, sizeof(Button_T))
    /* Other procedures on sButton... */

    ExitCriticalSection();
}

/* Cyclic executed handler */
void ButtonISRHandler(void)
{
    if (!BinarySemaphoreTake()) {
        SetISRPending();
    }
    else {
        ScanButtonAndUpdate();

        BinarySemaphoreGive();
    }
}

void ScanButtonAndUpdate(void)
{
    /* Scan for instance a current PIN state and update sButton object
       if state is stable in next calls */
}

static void EnterCriticalSection(void)
{
    while(false == BinarySemaphoreTake()) continue;
}

static void ExitCriticalSection(void)
{
    BinarySemaphoreGive();

    if (IsPendingISR()){
        ScanButtonAndUpdate();
        ResetISRPending();
    }
}

static bool BinarySemaphoreTake(void)
{
    if (SEMAPHORE_GIVEN == sSemaphore) {
        /* Value Store operation is atomic on the architecture native type */
        sSemaphore = SEMAPHORE_TAKEN;
        return true;
    }
    else {
        return false;
    }
}

static void BinarySemaphoreGive(void)
{
    sSemaphore = SEMAPHORE_GIVEN;
}

static void SetISRPending(void)
{
    sIsPendingISR = true;
}

static void ResetISRPending(void)
{
    sIsPendingISR = false;
}

static bool IsPendingISR(void)
{
    return sIsPendingISR;
}

このソリューションはテスト済みで、問題なく動作しますが、これが隠れたバグのない最適なソリューションであるかどうかはわかりません。

EDIT 1:仮定を更新し、不足しているScanButtonAndUpdate機能を追加しました

4

1 に答える 1