RTOS:UART write from MULTI THREAD

 前回のUARTでPCとシリアルでWrite&Readを実施した。ただUARTは一つのthreadで読み書きすべてを実施する書き方を行った。

今回は、二つのスレッドからPCに出力をしてみる。前回の途中までは同じ。

void *mainThread3(void *arg0)
{
    char        input;
    const char  echoPrompt[] = "Thread3\n";
    UART_Handle uart;
    UART_Params uartParams;

      UART_init();

      /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode =UART_RETURN_NEWLINE; //UART_RETURN_NEWLINE;//UART_RETURN_FULL;
    uartParams.baudRate = 115200;

    /* OPEN UART */
    uart = UART_open(CONFIG_UART_0, &uartParams);
    UART_write(uart, echoPrompt, sizeof(echoPrompt));

    /* Loop forever echoing */
    while (1) {
       UART_write(uart, echoPrompt, sizeof(echoPrompt));
     Task_sleep(500 * (1000 / Clock_tickPeriod));
    }//end while
}
違いは、文字列が単純にどのスレッドからの書き込みかわかるように”Thread3"として、whileの中で、UARTにwriteし、Task_sleepで0.5秒に一度出力するようにしている。
まず、これを実行してみる。

ここまでは、理解しているとそう難しくはない。
さて、これにvoid *mainThread3をコピーしてvoid *mainThread4(void *arg0)を作ってみる。
const char  echoPrompt[] = "Thread4\n";
どちらのスレッドから吐き出されたかわかるように、文字列をThread4にしておく。
新しスレッドをタスクに足す。cfgファイルを開いて、taskの4つ目を足し、Fuctionに新たに付け足す関数を配置する。
このの状態でビルドしてみる。エラーは出ないが、フラッシュしてみると・・・
あら?何も表示されない。また、LEDを他のスレッドで点滅させているが、それも止まっている。

複数からのスレッドからUARTで書き込みができない??
https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/942205/tm4c129encpdt-certificate-date-issue/3486481#3486481
ではセマフォやMutexを使ってWriteする間は割り込みを止めないと・・・とかいろいろ書いてある。
しかし実はそんな事しなくてもよい。

ポイントは、UART_openを一度だけ呼び出し、返されたハンドルを2つのスレッドで共有させる。そうする事で、複数のタスクに同時に書き込ませることができる。
上の例だとハンドルを共有せず、それぞれOPENする事になる。

具体的に手直しをする。UART_openを一度だけ呼び出し、返されたハンドルを2つのスレッドで共有させると書いたがどうするのかは、スレッドの親側、この場合メインでUARTをオープンし、ハンドルを共有し、戻る先が同じになるようにしておく必要がある。

まずこれまであまり触る事の無かった、main_tirtos.c側を編集する。
UARTを使うためヘッダーファイルを読み込み、ハンドル、パラメーターの変数を定義する。
既にある、#include <ti/drivers/Board.h>の下にでも

#include <ti/drivers/Board.h>
#include <ti/drivers/UART.h>
    UART_Handle uart;
    UART_Params uartParams;
とする。続いてそのしたにでも、
    /* Driver configuration */
    #include "ti_drivers_config.h"
を配置する。これは、例えばCONFIG_UART_0と、syscfgで名前を定義して、ピンをアサインしているを読み込むため。
メインで、
int main(void)
{

    Board_init();

    UART_init();
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode =UART_RETURN_NEWLINE; //UART_RETURN_NEWLINE;//UART_RETURN_FULL;
    uartParams.baudRate = 115200;
    uartParams.writeMode=UART_MODE_BLOCKING;

    /* OPEN UART */
    uart = UART_open(CONFIG_UART_0, &uartParams);

    BIOS_start();

    return (0);
}
とUARTを開く所まで処理をする記述をする。uartParams.writeMode=UART_MODE_BLOCKING;を指定しているがデフォルトでBLOCKINGされるようで記述がなくても動作は同じだった。

次は、スレッドを記述している方のcファイルを編集する。
#include <ti/drivers/UART.h>
 extern   UART_Handle uart;
 extern   UART_Params uartParams;
と先ほどのハンドルを外部参照しておく。
その上で、Thread3、4は、すでにオープンしているので、UART_writeする所だけを記述する。
void *mainThread3(void *arg0)
{
    const char  echoPrompt[] = "Thread3\n";
    while (1) {
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        //GateMutex_leave(gateUARTWait, key);    }//end while
}
void *mainThread4(void *arg0)
{
    const char  echoPrompt[] = "Thread4\n";
    while (1) {
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }//end while
}
で無事に狙い通りの動作をさせる事ができる。
ポイントは、すでに述べたが、

uartParams.writeMode=UART_MODE_BLOCKING
はおそらくだが、ちゃんとブロックして書き込み中に他のタスクからの割り込みが入らないようにしていると思われる。

*******
/*
 * Copyright (c) 2015-2019, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== empty.c ========
 */

#include <unistd.h> /* For usleep() */
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>



/* Driver Header files */
#include <ti/drivers/GPIO.h>
// #include <ti/drivers/I2C.h>
// #include <ti/drivers/SPI.h>
#include <ti/drivers/UART.h>
 extern   UART_Handle uart;
 extern   UART_Params uartParams;
#include <ti/drivers/ADC.h>
// #include <ti/drivers/Watchdog.h>

/* Driver configuration */
#include "ti_drivers_config.h"

#include <ti/sysbios/knl/Task.h> //to use task sleep Task.h is needed.
#include <ti/sysbios/knl/Clock.h> //of caurase, clock.h also.

#include <ti/sysbios/BIOS.h>

/* declaration of original functions*/
void gpioButtonFxn0(uint_least8_t index);

/*
 *  ======== mainThread ========
 */
void *mainThread0(uint16_t arg0, UArg arg1)
{
    /* 1 second delay */
   // uint32_t time = 1000;

    /* Call driver init functions */
    GPIO_init();

    /* Configure the LED pin */
    GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);

    /* Turn on user LED */
    GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);

    while (1) {
        GPIO_toggle(CONFIG_GPIO_LED_0);
        Task_sleep(((uint16_t)arg0)  * (1000 / Clock_tickPeriod));
    }
}

void *mainThread1(UArg arg0, UArg arg1)
{
    /* 1 second delay */
   // uint32_t time = 100; //msec

    /* Call driver init functions */
    GPIO_init();

    /* Configure the LED pin */
    GPIO_setConfig(CONFIG_GPIO_LED_1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);

    /* Turn on user LED */
    GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_ON);

    while (1) {

        GPIO_toggle(CONFIG_GPIO_LED_1);
        Task_sleep(((UInt)arg0) * (1000 / Clock_tickPeriod));
    }
}

void *mainThread2(UArg arg0, UArg arg1)
{

    GPIO_init();

    /* Configure the LED pin */
    GPIO_setConfig(CONFIG_GPIO_LED_2, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);

    /* Turn on user LED */
    GPIO_write(CONFIG_GPIO_LED_2, CONFIG_GPIO_LED_ON);

 //   GPIO_setCallback(CONFIG_GPIO_BTN_0, gpioButtonFxn0);
    GPIO_enableInt(CONFIG_GPIO_BTN_0);
    return 0;

}


void gpioButtonFxn0(uint_least8_t index)
{
    // Toggle the LED
    GPIO_toggle(CONFIG_GPIO_LED_2);
}

void *mainThread3(void *arg0)
{

    const char  echoPrompt[] = "Thread3\n";

    while (1) {
        //key = GateMutex_enter(gateUARTWait);
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        //GateMutex_leave(gateUARTWait, key);
        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }//end while
}


void *mainThread4(void *arg0)
{

    const char  echoPrompt[] = "Thread4\n";

    while (1) {
        //key = GateMutex_enter(gateUARTWait);
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        //GateMutex_leave(gateUARTWait, key);
        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }//end while
}
*********************************
/*
 * Copyright (c) 2016-2020, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,

 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== main_tirtos.c ========
 */
#include <stdint.h>

/* POSIX Header files */
#include <pthread.h>

/* RTOS header files */
#include <ti/sysbios/BIOS.h>

#include <ti/drivers/Board.h>
#include <ti/drivers/UART.h>
    UART_Handle uart;
    UART_Params uartParams;

    /* Driver configuration */
    #include "ti_drivers_config.h"

extern void *mainThread0(uint16_t arg0, UArg arg1);
extern void *mainThread1(UArg arg0, UArg arg1);

/* Stack size in bytes */
#define THREADSTACKSIZE    1024

/*
 * The following (weak) function definition is needed in applications
 * that do *not* use the NDK TCP/IP stack:
 */
void __attribute__((weak)) NDK_hookInit(int32_t id) {}

/*
 *  ======== main ========
 */
int main(void)
{

    Board_init();

    UART_init();
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode =UART_RETURN_NEWLINE; //UART_RETURN_NEWLINE;//UART_RETURN_FULL;
    uartParams.baudRate = 115200;
    //uartParams.writeMode=UART_MODE_BLOCKING;

    /* OPEN UART */
    uart = UART_open(CONFIG_UART_0, &uartParams);

    gateUARTWait = GateMutex_create(NULL, 0);

    BIOS_start();

    return (0);
}













コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

CH9329で日本語キーボード109で正しく表示する方法