RTOS:ADC14 Functionalizing ADC

ADCの部分を関数化して複数チャンネルに拡張できるようにする。

またテスト動作で、取得した値を別のスレッドでシリアルに送る事をしてみる。 

結果を格納するグローバル変数を2チャンネル分にあわせて以下のように配列化する。

 /* ADC conversion result variables */
float adcValue0Volt[2];

ADCの値を返す関数として、以下を追記する。

float getADC14(int channel)
{

    /* ADC conversion result variables */
    uint16_t adcValue;
    float adcValueVolt;
    ADC_init();
       ADC_Handle   adc; //adc handle
       ADC_Params   params; //adc parameters

       ADC_Params_init(&params); //initialization of parameters

       switch(channel){
       case 0:
           adc = ADC_open(CONFIG_ADC_0, &params); //open adc
           break;
       case 1:
           adc = ADC_open(CONFIG_ADC_1, &params); //open adc
           break;
       default:
           adc = ADC_open(CONFIG_ADC_0, &params); //open adc
       }
       int_fast16_t res; //for checking adc converting
       res=ADC_convert(adc, &adcValue); //second argument should set address.
                if (res == ADC_STATUS_SUCCESS) {
                adcValueVolt = (float)ADC_convertRawToMicroVolts(adc, adcValue)/1000000.0;
                }
       ADC_close(adc);
       return adcValueVolt;


解説は以前と同じなので割愛。だが、returnする前にcloseしてあげないと、ここでもとに戻らなくなるので停止する。この点だけが関数として切り出した時の変更点にあたる。

/* declaration of original functions*/
void gpioButtonFxn0(uint_least8_t index);
float getADC14(int channel);
と上の方で、関数の定義を入れるのを忘れないようにする。
mainThread4を以下に編集する。
不要な部分を削除してあげて、adcValue0Volt[1]=getADC14(1);で作った関数を呼び出し
値を取得し、グローバル変数であるadcValue0Volt[]に格納している。
この例では、一定間隔でADCの値を読むようにした。

void *mainThread4(void *arg0)
{
    const char  echoPrompt[] = "Thread4:\n";
    while (1) {
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        adcValue0Volt[0]=getADC14(0);
        adcValue0Volt[1]=getADC14(1);
        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }
}

mainThread3の方も編集して、別のスレッドで読み取ったADCの値をシリアルでPCに送る。

void *mainThread3(void *arg0)
{
    const char  echoPrompt[] = "Thread3:";
    char  UART_TX_buffer[32];

    while (1) {

        UART_write(uart, echoPrompt, sizeof(echoPrompt));

        memset(UART_TX_buffer, 0x00, sizeof(UART_TX_buffer));
        sprintf(UART_TX_buffer,"V=%f\n",adcValue0Volt[1]);
        UART_write(uart, UART_TX_buffer, sizeof(UART_TX_buffer));
        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }//end while
}

ここまでできたらビルトしてみる。エラーが出ない事を確認して、書き込んでみる。

しかし、実行すると停止してしまう。
コード自体複雑ではないので間違いない。
試しに、mainThread3側の
sprintf(UART_TX_buffer,"V=%f\n",adcValue0Volt[1]);
の所を、
sprintf(UART_TX_buffer,"V=\n");
と変数を変換代入せず、V=という文字だけをUART_TX_bufferに入れるようにする。
するとちゃんと動いてくれる。が変数の表示はむろんできない。
この動作の確認から、sprintfの関数の所で、変数を形式指定して代入する所で問題がある事がわかる。
これを解決するのに右往左往した・・・
https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1002832/cc2640r2f-sprintf-causes-hang-at-simple-peripheral?tisearch=e2e-sitesearch&keymatch=sprintf#
に記載もあるのだが、TASKのスタックサイズを大きくしなさいという事。Sprintfはサイズを圧迫する命令だという事。
そこで、
sprintf(UART_TX_buffer,"V=%f\n",adcValue0Volt[1]);
にもとに戻し

Thread3のStack sizeを2048と大きく変更してみる。


ソースコードは先ほど停止してしまったものと同じであるが今度はちょんとスレッド4でADCで読み取った値を別スレッドの3でシリアルでPCに送る事ができた。

sprintfを使う時はスタックサイズを十分に大きくするべし

という教訓

/*
 * 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>/* to use memset and strcmp*/
#include <stdio.h> /* to use sprintf */
#include <stdlib.h>/* to use sprintf */


/* 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);
float getADC14(int channel);

/* ADC conversion result variables */
float adcValue0Volt[2];

/*
 *  ======== 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:";
    char  UART_TX_buffer[32];

    while (1) {

        UART_write(uart, echoPrompt, sizeof(echoPrompt));

        memset(UART_TX_buffer, 0x00, sizeof(UART_TX_buffer));
        sprintf(UART_TX_buffer,"V=%f\n",adcValue0Volt[1]);
        UART_write(uart, UART_TX_buffer, sizeof(UART_TX_buffer));
        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }//end while
}


void *mainThread4(void *arg0)
{

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

    while (1) {
        UART_write(uart, echoPrompt, sizeof(echoPrompt));

        adcValue0Volt[1]=getADC14(1);

        Task_sleep(500 * (1000 / Clock_tickPeriod));
    }
}

float getADC14(int channel)
{

    /* ADC conversion result variables */
    uint16_t adcValue;
    float adcValueVolt;
    ADC_init();
       ADC_Handle   adc; //adc handle
       ADC_Params   params; //adc parameters

       ADC_Params_init(&params); //initialization of parameters

       switch(channel){
       case 0:
           adc = ADC_open(CONFIG_ADC_0, &params); //open adc
           break;
       case 1:
           adc = ADC_open(CONFIG_ADC_1, &params); //open adc
           break;
       default:
           adc = ADC_open(CONFIG_ADC_0, &params); //open adc
       }
       int_fast16_t res; //for checking adc converting
       res=ADC_convert(adc, &adcValue); //second argument should set address.
                if (res == ADC_STATUS_SUCCESS) {
                adcValueVolt = (float)ADC_convertRawToMicroVolts(adc, adcValue)/1000000.0;
                }
       ADC_close(adc);
       return adcValueVolt;

}


コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

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