PSoC 6 のデュアルコアでHello World (5)

##前回のあらすじ
[前回の記事][(4)]では、**Cortex-M4**側のデータを**PIPE**の仕組みを使って**Cortex-M0+**側に送信しました。ところが、頻繁にメッセージを受け取ってしまうと受信側の処理が間に合わないため、**PIPE**全体を止めるという方法で解決をしました。これでは、他の用途に**PIPE**を使うことができません。
今回は、メッセージの送信を**セマフォ**という仕組みを使って管理します。

##ハードウェア
本プロジェクトでは、[前回の記事][(4)]と同様にタイマとしてMCWDTを使用します。

![GS003394.png](https://qiita-image-store.s3.amazonaws.com/0/224737/9eee4742-3461-c273-fe0a-ee7967f173e4.png)

##セマフォの利用方法

**セマフォ**は、[PSoC 6 のデュアルコアでＬチカ (2)][LC(2)]でも使用しました。複数のプロセッサがひとつのリソースを共有する仕組みです。
ここでは、「メッセージを送信する権利」というリソースを複数のタスクが取り合うという構図を実現しました。

まず、**Cortex-M4**側のあるタスクが、「メッセージを送信する権利」**セマフォ**を獲得します。すると、他のタスクはメッセージを送信できなくなります。

**セマフォ**を獲得したタスクがメッセージを送信したあと、通常であれば**セマフォ**を開放して「メッセージを送信する権利」を放棄します。しかしながら、今回のモデルでは獲得した**セマフォ**を放置します。

放置された**セマフォ**は、誰のものでもなくなりますが、メッセージを送信したことで「メッセージを受信した**Cortex-M0+**側に譲渡された」と解釈します。つまり、「メッセージを送信する権利」を受信側が獲得したとみなします。

メッセージを受信した**Cortex-M0+**側は、もちろん「メッセージを送信する権利」を行使するわけではありません。行使しないことで、後続メッセージが到着するのを防ぎます。

**Cortex-M0+**側でメッセージの処理が終わったら、「メッセージを送信する権利」を開放します。これで、他のタスクがメッセージを送信できるようになります。

##**Cortex-M0+**側のプログラム

まず、**セマフォ**番号を決めます。ここでは、8番を使っています。

```main_cm0p.c
#define SEMAPHORE_SENDER        (8) /* メッセージを送信する権利 */
```

**Cortex-M0+**側が「メッセージを送信する権利」を譲渡されるとき、**セマフォ**を放置することにより譲渡を実現しているので、何かをする必要があるわけではありません。

```main_cm0p.c
void pipeUartTxCallback(uint32_t *message) {
    CY_ASSERT(
        txCharsLeft == 0
    );
    
    /* 受信成功:急いでデータをバッファにコピー */
    strcpy(txBuffer, (char_t *)(&message[1]));
    txCharsLeft = strlen(txBuffer);
    txColumn = 0;
}
```

むしろ、**PIPE**を停止する処理がなくなったのですっきりしました。

一方、メッセージの処理が終わった時に**セマフォ**を開放する必要があります。

```main_cm0p.c
    for (;;) {
        /* UART制御ブロック */
        if (txCharsLeft > 0) {
            /* バッファのデータを一文字ずつちんたら送り出す。 */
            UART_Put(txBuffer[txColumn]);
            txColumn++;
            txCharsLeft--;
            
            if (txCharsLeft <= 0) {
                /* すべて送り出したらセマフォを開放する */
                while (
                    Cy_IPC_Sema_Clear(SEMAPHORE_SENDER, false) != CY_IPC_SEMA_SUCCESS
                ) ;
            }
        }
        /* 一文字当たり10msの低速処理 */
        CyDelay(10);
    }
```

メインループの中で、メッセージの受付を再開した部分で**セマフォ**を開放しています。

##**Cortex-M4**側のプログラム

**Cortex-M4**側でも同じ**セマフォ**番号を宣言します。

```main_cm4.c
#define SEMAPHORE_SENDER        (8) /* メッセージを送信する権利 */
```

メッセージの送信前に「メッセージを送信する権利」を獲得する処理が追加されました。

```main_cm4.c
        case ST_SEND:
            /* フラグが立っている時のみ実行 */
            if (! *(context->flag)) break;
            /* セマフォを獲得する */
            if (Cy_IPC_Sema_Set(SEMAPHORE_SENDER, false) == CY_IPC_SEMA_SUCCESS) {
                /* メッセージを送る */
                if (
                    Cy_IPC_Pipe_SendMessage(
                        CY_IPC_EP_CYPIPE_CM0_ADDR,
                        CY_IPC_EP_CYPIPE_CM4_ADDR,
                        (uint32_t *)(&context->message[context->side]),
                        0  
                    ) == CY_IPC_PIPE_SUCCESS
                ) {
                    /* バッファを切り替える */
                    context->side = (context->side)?(0):(1);
                    context->state = ST_CREATE;
                    /* 割り込みフラグを折る */
                    *(context->flag) = false;
                } else {
                   /* メッセージの送信に失敗したので、セマフォを開放する */
                    while (
                        Cy_IPC_Sema_Clear(SEMAPHORE_SENDER, false) != CY_IPC_SEMA_SUCCESS
                    ) ;
                }
            }
            break;
```

**セマフォ**が獲得出来たらメッセージを送ります。獲得した**セマフォ**
は、メッセージと共に**Cortex-M4**側に譲渡されたと解釈しますので、他の処理は必要ありません。

万が一メッセージの送信に失敗した場合には、**セマフォ**を開放します。

##関連文献
[AN215656 - PSoC 6 MCU Dual-Core CPU System Design][AN215656]
[AN217666 - PSoC 6 MCU Interrupts][AN217666]
[CE216795 - PSoC(R) 6 MCU Dual-Core Basics][CE216795]
[CE219339 - PSoC 6 MCU - MCWDT and RTC Interrupts (Dual Core)][CE219339]
[PSoC 6 MCU: PSoC 63 with BLE Architecture Technical Reference Manual][PSoC63BLE ATRM]

##関連記事
[PSoC 6 のデュアルコアでＬチカ (1)][LC(1)]
[PSoC 6 のデュアルコアでＬチカ (2)][LC(2)]
[PSoC 6 のデュアルコアでＬチカ (3)][LC(3)]
[PSoC 6 のデュアルコアでＬチカ (4)][LC(4)]
[PSoC 6 のデュアルコアでＬチカ (5)][LC(5)]
[PSoC 6 のデュアルコアでＬチカ (6)][LC(6)]
[PSoC 6 のデュアルコアでＬチカ (7)][LC(7)]
[PSoC 6 のデュアルコアでHello World (1)][(1)]
[PSoC 6 のデュアルコアでHello World (2)][(2)]
[PSoC 6 のデュアルコアでHello World (3)][(3)]
[PSoC 6 のデュアルコアでHello World (4)][(4)]

##リポジトリ
[github Repository][repository]

[PSoC Advent Calendar 2017]:https://qiita.com/advent-calendar/2017/psoc
[PSoC 6]:http://www.cypress.com/psoc6
[CY8CKIT-062-BLE]:http://www.cypress.com/cy8ckit-062-ble
[AN215656]:https://www.cypress.com/an215656
[CE216795]:https://www.cypress.com/ce216795
[CE219339]:https://www.cypress.com/ce219339
[AN217666]:https://www.cypress.com/an217666
[PSoC63BLE ATRM]:http://www.cypress.com/file/385621/download
[LC(1)]:https://qiita.com/noritan_org/items/d08f4578a91d63b93c06
[LC(2)]:https://qiita.com/noritan_org/items/8240f48f81b32b81a179
[LC(3)]:https://qiita.com/noritan_org/items/ea0ea4c933539409f2dc
[LC(4)]:https://qiita.com/noritan_org/items/03a360f00fd3f6988baf
[LC(5)]:https://qiita.com/noritan_org/items/96fb2d7cfb28620eb3a6
[LC(6)]:https://qiita.com/noritan_org/items/c20005207be98ac33200
[LC(7)]:https://qiita.com/noritan_org/items/23abc166c3b4e6719574
[(1)]:https://qiita.com/noritan_org/items/35651a747f0dec5b2cc8
[(2)]:https://qiita.com/noritan_org/items/c3878bc05a53247b641d
[(3)]:https://qiita.com/noritan_org/items/e03f958baeafeb2996e0
[(4)]:https://qiita.com/noritan_org/items/6f890f78e1ea524d7331
[repository]:https://github.com/noritan/Design339