2020年5月28日木曜日

PSoC6向けI2C_CharLCDライブラリを作ってみた。

今回はPSoC6向けにI2CでつながるキャラクタLCD用ライブラリを作ってみました。
PSoC5LPとかでちゃちゃっと表示器が欲しい時にはキャラクタLCDのコンポーネントを使って表示させることが出来ます。PSoC5LPやPSoC4だとキャラクタLCDのコンポーネントはパラレル接続とI2C接続の2つから選ぶことが出来ます。PSoC6でもちゃちゃっと表示器が欲しい所なのですが、リソースがたくさんあるにもかかわらずキャラクタLCDのコンポーネントはありません。パラレルTFTのコンポーネントがあるにはあるのですが毎回持ち出すのはちょっと大げさですし、一部のPSoC6には対応できません。なので今回はPSoC6向けにI2Cで接続するキャラクタLCD用のライブラリを作ることにしました。

 まず、このライブラリについての説明をする前にPSoC6で使われるライブラリを知る必要があります。PSoC6のライブラリはPDLとHAL(以降はCYHALとします)の2つがあります。PDLはペリフェラルドライバーライブラリーの略で文字通りPSoC6のペリフェラルを使うためライブラリーです。CYHALはPDLを元に作られています。おそらく、PDLのバージョンを切り替えても動作することを目的にしているのだと思われます。PSoC6の開発環境はPSoC Creator と modus ToolBoxの2つがあるのですが、PDLはどちらの環境でも使われていますがCYHALライブラリはmodus ToolBoxにだけ使われています。CYHALベースでI2C_CharLCDライブラリを作ってしまうと、PSoC Creatorで使うことが出来ません。なのでI2C_CharLCDライブラリはPDLをベースに作ることにしました。また、PSoC6ではRTOSを多用することも多いのでRTOSを使っても問題が起きにくいようにしました。PDLの厄介な所は構造体やポインタを多用するのでちょっとメモリー周りに意識が向いていないと使いこなせない所ですね。きちんとC言語が分かっている、C言語向けのオブジェクト指向を知っている必要があります。

さて、I2C_CharLCDライブラリの説明に入ろうと思います。AQM0802Aで動作確認をしていますが、コントローラICがST7032であればI2C_CharLCDライブラリが適応できると考えられます。I2C_CharLCDライブラリはmodus ToolBox、PSoC Creatorの両方の環境で動作できます。I2C_CharLCDライブラリの関数は5つと構造体が1つあります。それぞれの関数と構造体は次の通りです。

void I2C_CharLCD_Init(I2C_CHAR_LCD_HANDLE *handle, CySCB_Type *base,cy_stc_scb_i2c_context_t *context)
I2C_CharLCD_InitはI2C_CharLCDで使うI2C_CHAR_LCD_HANDLE構造体の初期化、キャラクタLCDそのものを初期化をします。

void I2C_CharLCD_Clear(I2C_CHAR_LCD_HANDLE *handle)
I2C_CharLCD_Clear()はキャラクタLCDの表示を消します。

bool I2C_CharLCD_Set_Cursor(I2C_CHAR_LCD_HANDLE *handle, uint8_t col, uint8_t row)
I2C_CharLCD_Set_Cursor()は表示のどこから表示をするかを設定します。

bool I2C_CharLCD_PutString(I2C_CHAR_LCD_HANDLE *handle, uint8_t *string, uint16_t length)
I2C_CharLCD_PutString()は文字列を表示します。

void I2C_CharLCD_PutChar(I2C_CHAR_LCD_HANDLE *handle, uint8_t putstr)
I2C_CharLCD_PutChar()は文字を1字だけ表示します。

I2C_CHAR_LCD_HANDLE
I2C_CHAR_LCD_HANDLE構造体はI2C_CharLCDライブラリのすべてで使います。

RTOSを使わない場合はI2CCharLCDConfig.hの#define Free_RTOS_ONをコメントアウトします。RTOSを使う場合はI2CCharLCDConfig.hの#define Free_RTOS_ONと書きます。

サンプルプログラムは次の通りです。
サンプルプログラムmodusToolboxで書きました。

#include "cy_pdl.h"
#include "cyhal.h"
#include "cybsp.h"
#include "FreeRTOS.h"
#include "task.h"
#include "I2CCharLCD.h"
#include "stdio.h"

void ledTask(void* prameter);
TaskHandle_t ledtask_h;

void lcdTask(void* prameter);
TaskHandle_t lcdtask_h;

int uxTopUsedPriority;
cy_stc_i2s_context_t i2cContext;
void I2C_ISR(void);

const cy_stc_sysint_t i2cIntrConfig =
{
    .intrSrc      = I2C_0_IRQ,
    .intrPriority = 6
};

int main(void)
{
    cy_rslt_t result;

    /* Initialize the device and board peripherals */
    result = cybsp_init() ;
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    uxTopUsedPriority = configMAX_PRIORITIES - 1;
    xTaskCreate(ledTask, "LEDTASK", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &ledtask_h);
    xTaskCreate(lcdTask, "LCDTASK", 256, NULL, tskIDLE_PRIORITY + 2, &lcdtask_h);
    vTaskStartScheduler();

    __enable_irq();

    for (;;)
    {
    }
}

void ledTask(void* prameter)
{

for(;;)
{
Cy_GPIO_Set(LED0_PORT, LED0_PIN);
vTaskDelay(250);
Cy_GPIO_Clr(LED0_PORT, LED0_PIN);
vTaskDelay(250);
}
}


void lcdTask(void* prameter)
{
Cy_SCB_I2C_Init(I2C_0_HW,  &I2C_0_config, &i2cContext);
Cy_SCB_I2C_SetDataRate(I2C_0_HW, 100000, Cy_SysClk_PeriphGetFrequency(CY_SYSCLK_DIV_16_BIT, 0U));
/* Hook interrupt service routine and enable interrupt */
Cy_SysInt_Init(&i2cIntrConfig, &I2C_ISR);
NVIC_EnableIRQ(I2C_0_IRQ);
Cy_SCB_I2C_Enable(I2C_0_HW);

    I2C_CHAR_LCD_HANDLE aqm;

    I2C_CharLCD_Init(&aqm, I2C_0_HW, &i2cContext);
    I2C_CharLCD_PutString(&aqm, (uint8_t*) "count", 5);
    I2C_CharLCD_Set_Cursor(&aqm, 0, 1);

    uint8_t count = 0;
    uint8_t strCount[5] = {};
for(;;)
{
snprintf((char*) strCount, 5, "%d  ", count);
I2C_CharLCD_PutString(&aqm, strCount, 5);
count++;
if(count > 255)
{
count = 0;
}
vTaskDelay(250);
//I2C_CharLCD_Clear(&aqm);
}
}

void I2C_ISR(void)
{
    Cy_SCB_I2C_Interrupt(I2C_0_HW, &i2cContext);
}
/* [] END OF FILE */

サンプルプログラムが正しく動くと次のようになります。



一応ですが、I2C_CharLCDライブラリのソースファイルを置いておきます。

0 件のコメント:

コメントを投稿