PSoC 6 듀얼 코어로 Hello World (2)

이것은 PSoC Advent Calendar 2017의 16 일째에 밀린 기사입니다.

마지막 회의



마지막 기사 에서는, 메세지 기능을 사용해 Cortex-M4로부터 Cortex-M0+에 캐릭터 라인을 보내, UART로부터 출력을 얻고 있었습니다.
이번에는 Cortex-M4 측에 복수의 태스크를 갖게 해, 태스크간에 UART의 사용권을 서로 빼앗는, 멀티 태스크와 같은 구조를 도입해 보았습니다.

멀티태스킹이란?



하나의 CPU에 복수의 일을 시키는 것은, 하나의 CPU를 실행할 수 있는 것은 하나의 프로그램 뿐이므로, 보통은 불가능한 과제입니다. 그러나 여러 작업을 세분화하여 하나의 CPU로 문지르면서 실행할 수 있으면 밖에서 CPU의 동작을 보았을 때 여러 작업이 동시에 실행되고 있는 것처럼 보입니다. 이것이 단일 CPU를 통한 멀티 태스킹 아이디어입니다.

이 프로젝트에서 목표로하는 목표



이 프로젝트에서는 Cortex-M4 측에 멀티 태스킹과 같은 메커니즘을 도입하여 각 태스크에서 Cortex-M0 + 측에 메시지를 보내 UART의 출력을 요청합니다.

Cortex-M0+ 측 프로그램



Cortex-M0+ 측의 프로그램은 마지막 기사 의 것이 그대로 사용할 수 있습니다. 변경 부분은 0입니다. 송신측의 태스크의 수가 아무리 증가해도, 수신측은 도착한 데이터를 딱딱함과 UART로부터 흘릴 뿐입니다.

Cortex-M4 측 프로그램



Cortex-M4 측의 프로그램에서는 먼저 문자열을 전송하는 작업을 상태 머신으로 분해하여 초기화 루틴과 디스패치 루틴으로 분리했습니다.

main_cm4.c
#include <stdio.h>
#include "project.h"

#define IPC_CHANNEL_UARTTX  (8)  /* メッセージ送受信用の IPC チャネル番号 */

/* IPC チャネルのハンドル */
IPC_STRUCT_Type *ipcHandle;

/* Task1の定義 */
enum Task1State {
    ST_CREATE,
    ST_SEND
};

struct Task1Context {
    enum Task1State state;  /* ステートマシンの状態 */
    uint32_t count;  /* メッセージ番号 */
    uint32_t side;  /* 使用中バッファ面 */
    const char_t *name;  /* タスクの名前 */
    char_t buffer[2][128]; /* ダブルバッファ */
};

void task1_init(struct Task1Context *context, const char_t *name) {
    /* タスクの初期化 */
    context->name = name;
    context->count = 0;
    context->side = 0;
    context->state = ST_CREATE;
}

void task1_dispatch(struct Task1Context *context) {
    switch (context->state) {
        case ST_CREATE:
            /* 送信するメッセージを作成する */
            (void)sprintf(
                context->buffer[context->side],
                "%s: HELLO WORLD %lu\r\n",
                context->name, context->count++
            );
            context->state = ST_SEND;
            break;
        case ST_SEND:        
            /* メッセージを送る */
            if (
                Cy_IPC_Drv_SendMsgPtr(
                    ipcHandle,
                    CY_IPC_NO_NOTIFICATION,
                    context->buffer[context->side]
                ) == CY_IPC_DRV_SUCCESS
            ) {
                /* バッファを切り替える */
                context->side = (context->side)?(0):(1);
                context->state = ST_CREATE;
            }
            break;
        default:
            CY_ASSERT(false);
    }
}

Task1은 자신의 이름과 일련 번호가 포함된 문자열을 Cortex-M0+ 쪽으로 보냅니다. 상태 머신에는 두 가지 상태가 있습니다. ST_CREATE 상태에서는 다음에 전송할 문자열을 준비하고 ST_SEND 상태로 전환합니다. ST_SEND 상태에서는 Cortex-M0+에 메시지를 보내지만 성공한 경우에만 ST_CREATE 상태로 돌아갑니다. 이렇게 하면 작성한 문자열이 전송될 때까지 ST_SEND 상태에 머무르므로 모든 문자열을 빠짐없이 전달할 수 있습니다.

Task1에서 사용되는 태스크에 고유한 저장 영역은 struct Task1Context 라는 구조체에 있습니다. 이 구조체에 대한 포인터를 task1_init() 함수 또는 task1_dispatch() 함수의 첫 번째 인수로 전달하여 독립적인 작업을 처리할 수 있습니다.

main_cm4.c
int main(void) {
    struct Task1Context context1_0;
    struct Task1Context context1_1;
    struct Task1Context context1_2;

    __enable_irq(); /* 全体の割り込みを許可する */

    /* メッセージ交換のためのハンドルを獲得する */
    ipcHandle = Cy_IPC_Drv_GetIpcBaseAddress(IPC_CHANNEL_UARTTX);

    /* タスクの初期化 */
    task1_init(&context1_0, "M4-1-0");
    task1_init(&context1_1, "M4-1-1");
    task1_init(&context1_2, "M4-1-2");

    for (;;) {
        /* Task1 のディスパッチャ */
        task1_dispatch(&context1_0);
        task1_dispatch(&context1_1);        
        task1_dispatch(&context1_2);        
    }
}

Task1을 벗어난 main() 함수에는 초기화와 디스패처 호출 만 남았습니다. 여기에서는 세 가지 작업을 정의하고 무한 루프 내에서 단순히 순서대로 디스패처를 호출합니다.

실행해보면



실행을 시작하면 세 가지 작업이 처리되는 방식을 알 수 있습니다.



실행 순서와 실행 빈도는 작업에 따라 다릅니다. 이것은, 태스크의 스케줄은 커녕 메시지의 큐등도 받아들이고 있지 않기 때문입니다. 이 때문에 잠시 움직이면



이와 같이 타이밍에 따라서는, 하나의 태스크만이 연장되어 실행되어 가는 모습도 관측되었습니다. 가장 큰 원인은 Cortex-M4가 부담없이 요청을 연발하고 있다는 것입니다. 요구측의 타이밍을 만들어야 합니다.

관련 문헌



AN215656 – PSoC 6 MCU Dual-Core CPU System Design
AN217666 - PSoC 6 MCU 인터럽트
CE216795 - PSoC(R) 6 MCU Dual-Core Basics
PSoC 6 MCU: PSoC 63 with BLE Architecture Technical Reference Manual

관련 기사



PSoC 6 듀얼 코어 L 치카 (1)
PSoC 6 듀얼 코어 L 치카 (2)
PSoC 6 듀얼 코어 L 치카 (3)
PSoC 6 듀얼 코어 L 치카 (4)
PSoC 6 듀얼 코어 L 치카 (5)
PSoC 6 듀얼 코어 L 치카 (6)
PSoC 6 듀얼 코어 L 치카 (7)
PSoC 6 듀얼 코어로 Hello World (1)

좋은 웹페이지 즐겨찾기