LoginSignup
0
1

More than 3 years have passed since last update.

Zephyr + STM32F769 Discovery Kit > I2C > AQM0802に「Hello」と表示するまで > v0.1

Last updated at Posted at 2019-11-26
動作環境
ホストOS: Ubuntu 18.04 LTS
ボード: STM32F769 Discovery Kit (以下、STM32F769)
RTOS: Zephyr 2.1.0-rc1
キャラクタLCD: AQM0802

概要

  • Zephyr + STM32F769でのI2C送信の練習
  • AQM0802に文字を書く
    • AQM0802 @ 秋月電子
    • ESP8266で実装したコードを移植する
      • thanks to @exabugs さん (2016年にESP8266の実装時に参考にさせていただきました)

Zephyrの準備

i2c_scannerをsamples/drivers/wrk_AQM0802_191125にディレクトリコピーした。
その後、実装をAQM0802用に書き換えた。

  • proj.confの変更
  • libAQM0802.cの追加
  • libAQM0802.hの追加
  • main.cの書き換え
proj.conf
CONFIG_PRINTK=y
CONFIG_I2C=y
CONFIG_SERIAL=y

main.c, libAQM0802.c,.hについては後述する (ソースが長いため)。

回路

以下に実装した基板を使った。

以下のように接続した。

  • AQM0802 <-> STM32F769
    • VCC <-> CN11 ピン4 (3V3) : 赤
    • GND <-> CN9 ピン7 (GND) : 緑
    • SDA <-> CN9 ピン9 (SDA) : 青
    • SCL <-> CN9 ピン10 (SCL) : 黄

ブレッドボードで以下のように実装した。

IMG_1384.JPG

実行手順

  • 1. STM32F769をUSB接続しておく
    • ST-LinkのUSB接続
  • 2. プログラムをビルド
    • cd ~/Zephyr_191116/zephyrproject/
    • west build -p auto -b stm32f769i_disco samples/drivers/wrk_AQM0802_191125
  • 3. プログラム書き込み
    • west flash

に以下のように「Hello」が表示される。

IMG_1382.JPG

ソース

main.c

main.c
/*
 * Copyright (c) 2018 Tavish Naruka <tavishnaruka@gmail.com>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <errno.h>
#include <zephyr.h>
#include <sys/printk.h>
#include <device.h>
#include <drivers/i2c.h>

// below added by user (7of9)
#include <stdint.h>
#include "libAQM0802.h"

#ifdef ARDUINO_I2C_LABEL
#define I2C_DEV ARDUINO_I2C_LABEL
#else
//#define I2C_DEV "I2C_0"
#define I2C_DEV "I2C_1" // Nov. 25, 2019 for STM32F769I_disco
#endif

/*
Nov. 26, 2019
    - add [AQM0802] library from ESP8266 implementation
    - branched from [i2c_scanner]
*/

void main(void)
{
    struct device *i2c_dev;
    u8_t cnt = 0;

    uint8_t msgs[10] = "hello";
    int msgLen = strlen(msgs);

    AQM0802_Initialize(/* cursorOn=*/true, /* cursorPosOn=*/true, /* contrast=*/2);
    AQM0802_PutMessage(msgs, msgLen, 1, 1);
}

libAQM0802.h

libAQM0802.h
#ifndef LIBAQM0802_H
#define LIBAQM0802_H

#include <stdint.h>

void AQM0802_Initialize(bool cursorOn, bool cursorPosOn, uint8_t contrast);
void AQM0802_PutMessage(uint8_t *msgPtr, int msgLen, uint8_t x_st1, uint8_t y_st1);

#endif

libAQM0802.c

Hackaday用にESP8266実装したesp8266_160217_AQM0802.inoを移植した。

libAQM0802.c
#include <stdint.h>
#include <stdlib.h>
#include <zephyr.h>
#include <device.h>
#include <drivers/i2c.h>
#include <sys/printk.h>

/*
v0.1 2019 Nov. 28
    - add libAQM0802.h
    - change i2c write function to those for Zephyr+I2C

===== migrated from [esp8266_160217_AQM0802.ino] to [libAQM0802.c] =====

 * v0.4 2016 Feb. 20
 *  - add [kOffset_addr2ndline]
 *  - update AQM0802_PutMessage() for auto wrapping (more than 8 characters)
 * v0.3 2016 Feb. 18
 *  - add message display function
 *    + add Test_AQM0802_showDateTime()
 *    + add AQM0802_PutMessage()
 * v0.2 2016 Feb. 17
 *  - add test functions()
 *    + add Test_AQM0802_cursorOn_posOn_contrastHigh()
 *    + add Test_AQM0802_cursorOn_posOn_contrastLow()
 *    + add Test_AQM0802_cursorOn_posOff_contrastLow()
 * v0.1 2016 Feb. 17
 *  - add AQM0802_Initialize()
 *  - add AQM0802_Clear()
 *  - add AQM0802_WriteData()
 *  - add AQM0802_WriteInstruction()
 *  - add writeToDevice()
 *
 * -------
 * Special thanks to exabugs for ( http://qiita.com/exabugs/items/9d1b66aa1d22805afbc8 )
 */

#ifdef ARDUINO_I2C_LABEL
#define I2C_DEV ARDUINO_I2C_LABEL
#else
//#define I2C_DEV "I2C_0"
#define I2C_DEV "I2C_1" // Nov. 25, 2019 for STM32F769I_disco
#endif

static const uint8_t kDeviceAddr = 0x3e;

static const int kMaxXsize = 8;
static const int kMaxYsize = 2;

static const int kOffset_addr2ndline = 0x40;

static uint8_t ControlByteList[] = {
  0x00, // Instruction write operation. ( Co=0, Rs=0 )
  0x40, // Data write operation. ( Co=0, Rs=1 )
};

enum {
  TYPE_INSTRUCITON = 0,
  TYPE_DATA,
};

// private functions ---------------------------
void writeToDevice(int type, uint8_t *dataByte, size_t len) 
{
    struct device *i2c_dev;
    struct i2c_msg msgs[1];
    u8_t dst[10];

    i2c_dev = device_get_binding(I2C_DEV);

    /* Send the address to read from */

    for (int idx = 0; idx < len; idx++) {
        // [ESP8266 + I2C]
        // Wire.beginTransmission(kDeviceAddr);
        // Wire.write(ControlByteList[type]);
        // Wire.write(dataByte[idx]);
        // Wire.endTransmission();
        // delayMicroseconds(27); // 26.3us
        //
        // [Zephyr + STM32F769I_Discovery]
        dst[0] = ControlByteList[type];
        dst[1] = dataByte[idx];
        msgs[0].buf = &dst[0];
        msgs[0].len = 2U;
        msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
        i2c_transfer(i2c_dev, &msgs[0], 1, kDeviceAddr);
        k_usleep(27); // 26.3us
    }
}

// public functions ---------------------------
void AQM0802_WriteSingleInstruction(uint8_t data) 
{ 
  size_t len = 1;
  uint8_t list[] = {data};
  writeToDevice(TYPE_INSTRUCITON, list, len); 
}

void AQM0802_WriteInstructions(uint8_t *data, int len) 
{ 
  writeToDevice(TYPE_INSTRUCITON, data, len); 
}

void AQM0802_WriteData(uint8_t *data, size_t len) 
{ 
  writeToDevice(TYPE_DATA, data, len); 
}

void AQM0802_Clear()
{
    AQM0802_WriteSingleInstruction(0x01);
}

void AQM0802_Initialize(bool cursorOn, bool cursorPosOn, uint8_t contrast)
{ 
  // 
  k_sleep(40); // delay(40); // Wait time > 40ms after VDD stable

  // Function set
  AQM0802_WriteSingleInstruction(0x38);

  // Function set
  AQM0802_WriteSingleInstruction(0x39);

  // Internal OSC frequency
  AQM0802_WriteSingleInstruction(0x14);

  // { Contrast set -----------------------------
  uint8_t ctrst = contrast;
  if (ctrst > 0b1111) {
    ctrst = 0b1111;
  }
  AQM0802_WriteSingleInstruction(0x70 | ctrst);
  // } Contrast set -----------------------------

  // Power/ICON/Contrast control
  AQM0802_WriteSingleInstruction(0x56);

  // Follower control
  AQM0802_WriteSingleInstruction(0x6C);

  // Wait time > 200mS (for power stable)
  k_sleep(200); // delay(200);

  // Function set
  AQM0802_WriteSingleInstruction(0x38);

  // { Display ON/OFF control -----------------------
  uint8_t extra = 0x0;
  if (cursorOn) {
    extra = extra | 0b10;
  }
  if (cursorPosOn) {
    extra = extra | 0b11;    
  }
  AQM0802_WriteSingleInstruction(0x0C | extra);
  // } Display ON/OFF control -----------------------

  // Clear Display
  AQM0802_WriteSingleInstruction(0x01);

  // Wait time > 1.08ms
  k_sleep(2); // delay(2);
}

#if 1 // 2019/11/26
void AQM0802_PutMessage(uint8_t *msgPtr, int msgLen, uint8_t x_st1, uint8_t y_st1)
{
  // _st1 : index starting from 1
  if ((x_st1 > kMaxXsize) || (y_st1 > kMaxYsize)) {
    return; // error
  }

  uint8_t pos;

  if (msgLen <= kMaxXsize) {
    pos = 0x80 | ((y_st1 - 1) * kOffset_addr2ndline);
    pos = pos | (x_st1 - 1);
    AQM0802_WriteSingleInstruction(pos);
    AQM0802_WriteData( (uint8_t *)msgPtr, msgLen);
    return;
  }

}
#else // work in progress 
void AQM0802_PutMessage(String msg, uint8_t x_st1, uint8_t y_st1)
{
  // _st1 : index starting from 1
  if ((x_st1 > kMaxXsize) || (y_st1 > kMaxYsize)) {
    return; // error
  }

  uint8_t pos;

  if (msg.length() <= kMaxXsize) {
    pos = 0x80 | ((y_st1 - 1) * kOffset_addr2ndline);
    pos = pos | (x_st1 - 1);
    AQM0802_WriteSingleInstruction(pos);
    AQM0802_WriteData( (uint8_t *)msg.c_str(), msg.length() );
    return;
  }

  char szbuf[10] = { 0 };
  // 1st line
  strncpy(szbuf, msg.c_str(), kMaxXsize);
  pos = 0x80 | ((y_st1 - 1) * kOffset_addr2ndline);
  pos = pos | (x_st1 - 1);
  AQM0802_WriteSingleInstruction(pos);
  AQM0802_WriteData( (uint8_t *)szbuf, strlen(szbuf) );

  // 2nd line
  msg = msg.substring(kMaxXsize); // remove string for 1st line
  memset(szbuf, 0, sizeof(szbuf));
  strncpy( szbuf, msg.c_str(), msg.length() );
  pos = 0x80 | ((y_st1 - 1) * kOffset_addr2ndline);
  pos += kOffset_addr2ndline; // for 2nd line, 1st column
//  pos = pos | (x_st1 - 1);  
  AQM0802_WriteSingleInstruction(pos);
  AQM0802_WriteData( (uint8_t *)szbuf, strlen(szbuf) );
}
#endif


//---------------------------------------------------------------------------------

// test functions ---------------------------

#if 1 // 2019/11/26

#else // work in progress
void Test_AQM0802_cursorOn_posOff_contrastLow()
{
  AQM0802_Initialize(/* cursorOn=*/true, /* cursorPosOn=*/false, /* contrast=*/1);
}

void Test_AQM0802_cursorOn_posOn_contrastLow()
{
  AQM0802_Initialize(/* cursorOn=*/true, /* cursorPosOn=*/true, /* contrast=*/1);
}

void Test_AQM0802_cursorOn_posOn_contrastHigh()
{
  AQM0802_Initialize(/* cursorOn=*/true, /* cursorPosOn=*/true, /* contrast=*/15);
}

void Test_AQM0802_showDateTime(String datstr, String timstr)
{
  AQM0802_PutMessage(datstr, /* x_st1=*/1, /* y_st1=*/1);
  AQM0802_PutMessage(timstr, /* x_st1=*/3, /* y_st1=*/2);
}
#endif

備考

  • libAQM0802.c, .hはI2C実装の確認用に最低限の実装しかしていない
  • 今後AQM0802をZephyrで本格利用する時には整備するだろう
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1