フォト
2025年3月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
無料ブログはココログ

« 2018年5月 | トップページ | 2018年7月 »

2018年6月の6件の記事

2018年6月27日 (水)

次はSTM32ボードを積極的に使ていきたい(23) グラフィック液晶(4)

TFT表示制御とタッチスクリーン制御用SPIバスの共有利用

前回の続きです。前回はTFT液晶表示とタッチスクリーンでそれぞれにSPIバスを
割当ていましたが、SPIバスを共有利用する方式に変更しました。

機能としては前回と全く同じです。

結線図
01
結線表

02

ブレットボード上の実装

03


スケッチ

/***************************************************
  This is our touchscreen painting example for the Adafruit ILI9341 Shield
  ----> http://www.adafruit.com/products/1651

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/

// 2018/06/25,たま吉さん, XPT2046コントローラー対応
// 2018/06/27,たま吉さん, SPI1のみ利用に修正

#include <SPI.h>
#include <Adafruit_GFX_AS.h>    // Core graphics library
#include <Adafruit_ILI9341_STM.h>
#include <XPT2046_touch.h>

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 600
#define TS_MINY 440
#define TS_MAXX 3460
#define TS_MAXY 3460

// TFT制御用ピン
#define TFT_CS  PA0
#define TFT_RST PA1
#define TFT_DC  PA2

// タッチパネルCSピン
#define CS_PIN  PA3 

// TFT制御用
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST);
SPISettings TFT_SPISet(SAFE_FREQ, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT);

// タッチスクリーン制御用
SPIClass SPI_TS(1);
XPT2046_touch ts(CS_PIN, SPI_TS); // Chip Select pin, SPI port

// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;

void setup(void) {
  Serial.begin(115200);
  Serial.println(F("Touch Paint!"));

  tft.begin(SPI);
  tft.fillScreen(ILI9341_BLACK);

  ts.begin();
  Serial.println("Touchscreen started");

  // make the color selection boxes
  SPI.beginTransaction(TFT_SPISet);
  tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
  tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
  tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
  tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
  tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
  tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);

  // select the current color 'red'
  tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
  currentcolor = ILI9341_RED;
  SPI.endTransaction();
}

void loop() {
  // Retrieve a point
  TS_Point p = ts.getPoint();

  if ( (p.z <=800) || (p.z > 3000))
    return;
   
 int16_t tmp = p.x;
  p.x = p.y;
  p.y = tmp;
  
  Serial.print("Z = "); Serial.print(p.z);
  Serial.print(" X = "); Serial.print(p.x);
  Serial.print(" Y = "); Serial.print(p.y);

  SPI.beginTransaction(TFT_SPISet);

  // Scale from ~0 ~ TS_MAXX to tft.width using the calibration #'s
  p.x = tft.width() - map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());

  Serial.print("("); Serial.print(p.x);
  Serial.print(", "); Serial.print(p.y);
  Serial.println(")");

  if (p.y < BOXSIZE) {
    oldcolor = currentcolor;

    if (p.x < BOXSIZE) {
      currentcolor = ILI9341_RED;
      tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 2) {
      currentcolor = ILI9341_YELLOW;
      tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 3) {
      currentcolor = ILI9341_GREEN;
      tft.drawRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 4) {
      currentcolor = ILI9341_CYAN;
      tft.drawRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 5) {
      currentcolor = ILI9341_BLUE;
      tft.drawRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 6) {
      currentcolor = ILI9341_MAGENTA;
      tft.drawRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    }

    if (oldcolor != currentcolor) {
      if (oldcolor == ILI9341_RED)
        tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
      if (oldcolor == ILI9341_YELLOW)
        tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
      if (oldcolor == ILI9341_GREEN)
        tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
      if (oldcolor == ILI9341_CYAN)
        tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
      if (oldcolor == ILI9341_BLUE)
        tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
      if (oldcolor == ILI9341_MAGENTA)
        tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
    }
  }
  if (((p.y - PENRADIUS) > BOXSIZE) && ((p.y + PENRADIUS) < tft.height())) {
    tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
  }
  SPI.endTransaction();
}

タッチ・スクリーンライブラリ XPT2046_touch は、API利用の都度、SPIの通信条件の
再設定を行ってくれており、他のデバイス利用との共有が出来るのですが、
TFT制御用のライブラリ Adafruit_ILI9341_STM は行ってくれません。
他のデバイスでSPIを利用した後は、TFT制御のためのSPIの設定は正しくない状態に
なります。

そこでAdafruit_ILI9341_STM  のAPI利用の前に、SPIの通信条件の設定を
行うよう、修正しました。
具体的には、SPISettings型のSPI通信条件を定義しておき、
    SPISettings TFT_SPISet(SAFE_FREQ, MSBFIRST, SPI_MODE0, DATA_SIZE_16BIT);
この定義を使って、TFT制御の直前に
   SPI.beginTransaction(TFT_SPISet);
を実行して、通信条件を設定しています。
TFT制御終了後は
   SPI.endTransaction();
を実行します(ただし、この命令、内部的には何も行っていません。お飾りです)

次回はこの方式にて、SDカードスロットの併用も試してみたいと思います。

2018年6月25日 (月)

次はSTM32ボードを積極的に使ていきたい(22) グラフィック液晶(3)

グラフィック液晶搭載タッチスクリーン利用の調査

前回の続きです。

グラフィック液晶モジュールのタッチスクリーンの利用を調査しました。

Dscn8344

私が所有しているグラフィック液晶モジュールには、タッチスクリーンを
利用することが出来ます。

裏側のICを調べると、XPT2046というタッチスクリーン・コントローラが搭載されていました。

03

このコントローラーはTI社のTSC2046と同等のようで、探すと日本語のデータシートがあります。

幸いにして、Arduino STM32には標準でXPT2046用のライブラリが提供されています。
  ・Serasidis_XPT2046_touch - A simple XPT2046 Touch Screen library for STM32 micro-controllers
このライブラリを使い、
Adafruit_ILI9341_STMライブラリのサンプルスケッチ touchpaint.inoを修正して
簡単なお絵描きプログラムを作成してみました。

オリジナルのtouchpaint.inoはAdafruit製のグラフィック液晶モジュール用で
コントローラにSTMPE610を使っていることを前提としているので、そのままでは動きません。
コントローラー周りをXPT2046対応に修正しました。

XPT2046はSPIインタフェースで利用しますが、液晶パネルの制御にもSPIを利用してます。
そのため、2つあるSPIバスをそれぞれに割り当てました。
液晶パネルの表示にSPI1、XPT2046にSPI2を利用しました。

接続図
01

結線表

02

スケッチ
/***************************************************
  This is our touchscreen painting example for the Adafruit ILI9341 Shield
  ----> http://www.adafruit.com/products/1651

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/

// 2018/06/25,たま吉さん, XPT2046コントローラー対応

#include <SPI.h>
#include <Adafruit_GFX_AS.h>    // Core graphics library
#include <Adafruit_ILI9341_STM.h>
#include <XPT2046_touch.h>

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 600
#define TS_MINY 440
#define TS_MAXX 3460
#define TS_MAXY 3460

// TFT制御用ピン
#define TFT_CS  PA0
#define TFT_RST PA1
#define TFT_DC  PA2

// タッチパネルCSピン
#define CS_PIN  PA3 

SPIClass SPI_2(2);
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST);
XPT2046_touch ts(CS_PIN, SPI_2); // Chip Select pin, SPI port

// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;

void setup(void) {
  Serial.begin(115200);
  Serial.println(F("Touch Paint!"));

//  tft.begin(SPI_2);
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);

  ts.begin();
  Serial.println("Touchscreen started");

  // make the color selection boxes
  tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
  tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
  tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
  tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
  tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
  tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);

  // select the current color 'red'
  tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
  currentcolor = ILI9341_RED;
}

void loop() {
  // Retrieve a point
  TS_Point p = ts.getPoint();

  if ( (p.z <=800) || (p.z > 3000))
    return;
   
 int16_t tmp = p.x;
  p.x = p.y;
  p.y = tmp;
  
  Serial.print("Z = "); Serial.print(p.z);
  Serial.print(" X = "); Serial.print(p.x);
  Serial.print(" Y = "); Serial.print(p.y);

  // Scale from ~0 ~ TS_MAXX to tft.width using the calibration #'s
  p.x = tft.width() - map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());

  Serial.print("("); Serial.print(p.x);
  Serial.print(", "); Serial.print(p.y);
  Serial.println(")");

  if (p.y < BOXSIZE) {
    oldcolor = currentcolor;

    if (p.x < BOXSIZE) {
      currentcolor = ILI9341_RED;
      tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 2) {
      currentcolor = ILI9341_YELLOW;
      tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 3) {
      currentcolor = ILI9341_GREEN;
      tft.drawRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 4) {
      currentcolor = ILI9341_CYAN;
      tft.drawRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 5) {
      currentcolor = ILI9341_BLUE;
      tft.drawRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 6) {
      currentcolor = ILI9341_MAGENTA;
      tft.drawRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    }

    if (oldcolor != currentcolor) {
      if (oldcolor == ILI9341_RED)
        tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
      if (oldcolor == ILI9341_YELLOW)
        tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
      if (oldcolor == ILI9341_GREEN)
        tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
      if (oldcolor == ILI9341_CYAN)
        tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
      if (oldcolor == ILI9341_BLUE)
        tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
      if (oldcolor == ILI9341_MAGENTA)
        tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
    }
  }
  if (((p.y - PENRADIUS) > BOXSIZE) && ((p.y + PENRADIUS) < tft.height())) {
    tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
  }
}

スケッチを書き込んで実行すると、簡単なお絵描きが出来ます。
ただし、若干座標位置、描画可能範囲がずれいます。

下記の図は、実行中のシリアル出力です。

各行の後半の括弧内の数値がタッチして検知した座標x、yです。
xの値がマイナスの値になっちゃっています。

04

プログラム内の下記の箇所で、描画範囲部分のスクリーン位置を実測値にて設定しています。
#define TS_MINX 600
#define TS_MINY 440
#define TS_MAXX 3460
#define TS_MAXY 3460

タッチスクリーンでは、x、yの座標と圧力zを12ビットのアナログ値で測定しています。
12ビットなので0~4095の範囲のなります。
定義した上記の値は、描画領域の上下左右の境界部分の値です。

この値を実際の320x240ドットの範囲にスケール変換して座標を得ています。
測定した値が正しくないために、取得した座標にずれが生じてしまっているようです。
もう少し厳密に測定する必要がありそうです。

液晶パネル上に被膜抵抗(タッチスクリーン)が張り付いていて、その上を押すと
0~4095の値が 得られるわけですが、タッチスクリーンは液晶の描画範囲の外側も含んでいます。

個々のモジュールでは、タッチスクリーンを貼った具合(ずれ等)は微妙に異なります。
ですので、個々のモジュール毎に描画の上下限範囲の値を測定する
キャリブレーションが必要となります。

キャリブレーション設定支援のスケッチなんかも必要ですね。

2018年6月23日 (土)

次はSTM32ボードを積極的に使ていきたい(21) グラフィック液晶(2)

Arduino STM32 最新版 でのグラフィック液晶利用調査

以前、調査・検証した「次はSTM32ボードを積極的に使ていきたい(13) - グラフィック液晶」の再調査です。

マイコンボードとして、Blue Pillボード(STM32F103C8T6搭載)を使います。
グラフィック液晶モジュールは、コントローラーにILI9341(SPI接続版)をつかった製品を使います。
開発環境としては、Arduinoを利用します。

Dscn8316

ここ数ヶ月で利用しているArduino STM32モジュールにかなりの仕様変更がありまして、
コントローラーにILI9341を使った液晶モジュール利用環境にも影響がありました。
そのため、改めて動作確認を行いました。


影響する仕様変更点

Adafruit_GFX_ASライブラリの実装形態の変更

(概要)
  コントローラーILI9341用ライブラリAdafruit_ILI9341_STMは描画処理等に、
  Adafruit_GFX_ASライブラリを利用しています。

  Adafruit_GFX_ASは従来は、Adafruit_GFXライブラリをSTM32環境に修正したものが
  提供されていましたが、Adafruit_GFXからの派生クラスとして実装する形態に変更されました。

(影響)
  別途、Adafruit_GFXを各自でインストールする必要があります。

(メリット)
  従来は、Adafruit_GFXの古いバージョンがベースだったため、グラフィック液晶関連では
  Arduinoと同等の機能を利用することが出来ませんでしたが、この修正により利用出来る
  ようになりました。

それでは、最新版のArduino STM32モジュールを使った環境にて、
手持ちのグラフィック液晶モジュールの動作確認を行ってみることにします。

Adafruit_GFXライブラリのインストール
ライブラリマネージャにてAdafruit_GFXを検索し、最新版をインストールします。
Photo

この方法でインストールすると、ライブラリ\librariesに配置されるライブラリの
フォルダ名がarduino_981956となってしまいました。
これだと分かりにくいので、Arduino IDEを一旦終了し、Adafruit_GFXに変更して
Arduino IDEを再起動して利用しました。

サンプルスケッチ「stm32_graphicstest」を使った動作確認

Blue PillボードのSPIバスは2つありますが、ここではSPI1を使います。
SPI1は次のピンを利用します。
  PA4 : NSS
  PA5 : SCK
  PA6 : MISO
  PA7 : MOSI

液晶モジュールとの結線は次のような感じです。

・結線図

01

・結線表

02

スケッチの読み込みと修正

メニューのスケッチ例から
Adafruit_ILI9341_STMのサンプルスケッチ「stm32_graphicstest」を開きます。

#include "SPI.h"
#include "Adafruit_GFX_AS.h"
#include "Adafruit_ILI9341_STM.h"

#define TFT_CS  PA0                  
#define TFT_RST PA1
#define TFT_DC  PA2
            
//Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC);
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST);

void setup() {
  Serial.begin(115200);
  delay(3000);
  Serial.println("ILI9341 Test!"); 
 
  tft.begin();

RESETをBlue Pillのリセットと連動させる場合はBlue PillのRSTへの接続でもOkです。
その場合は、TFT_RSTを-1にするか、コメントアウトしているコンストラクタの方を
利用して初期化します。

スケッチを書き込むと、液晶モジュールにはトップ画像のデモ画面は表示されます。


・SPI2を利用したい場合


SPI2は次のピンを利用します。
  PB12 : NSS2
  PB13 : SCK2
  PB14 : MISO2
  PB15 : MOSI2

方法としては、
  ①SPI.setModule(2)にて、SPI2に切り替える
または、
  ②SPI2のインスタンスを生成し、Adafruit_ILI9341_STMクラスのメンバ関数
         void  begin(SPIClass & spi, uint32_t freq=48000000);
     を使う
でSPI2を利用することが出来ます。

①の方式は安定版(RR20170323)でのみ利用可能です。
最新版では①と②の方法が可能ですが、②の方法は何となくバグがあるようです。
SPI2を使っているのに、SPIオブジェクトの設定が変更されてしまうような気がします。
(SPIにSPI2の値がセットされてしまう。これについては調査中です)

結線図および結線表のピンは、
   A5 => B13
   A6 => B14
   A7 => B15
に変更となります。

ちなみに、SPI1とSPI2ではMAXの転送速度が異なります。
SPI1ではシステムクロックの1/2(36MHz)がまで出せますが、SPI2ではその半分となります。

SPI2を利用する際のスケッチの修正(SPI2のインスタンス生成による対応)
#include "SPI.h"
#include "Adafruit_GFX_AS.h"
#include "Adafruit_ILI9341_STM.h"

#define TFT_CS  PA0                  
#define TFT_RST PA1
#define TFT_DC  PA2
            
//Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC);
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST);

SPIClass SPI_2(2);
void setup() {
  Serial.begin(115200);
  delay(3000);
  Serial.println("ILI9341 Test!"); 
 
  tft.begin(SPI_2);


次に、従来は古いAdafruit_GFXがベースだったために使えなかった、
フォントFreeFontを試してみます。

スケッチ(SPI2を使っています)
#include "SPI.h"
#include "Adafruit_GFX_AS.h"
#include "Adafruit_ILI9341_STM.h"
#include <Fonts/FreeMonoBoldOblique12pt7b.h>
#include <Fonts/FreeSerifBold12pt7b.h>
#include <Fonts/FreeSansBoldOblique12pt7b.h>

#define TFT_CS  PA0                  
#define TFT_RST PA1
#define TFT_DC  PA2

Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST);
SPIClass SPI_2(2);

void setup() {
  Serial.begin(115200);
  tft.begin(SPI_2);  
  tft.fillScreen(ILI9341_BLACK);
  
  tft.setCursor(0, 8);
  tft.setTextColor(ILI9341_WHITE);  
  tft.setFont(&FreeMonoBoldOblique12pt7b); 
  tft.println("Hello World!");

  tft.setCursor(0, 38);
  tft.setTextColor(ILI9341_YELLOW);  
  tft.setFont(&FreeSerifBold12pt7b); 
  tft.println("Hello World!");

  tft.setCursor(0, 60);
  tft.setTextColor(ILI9341_RED);  
  tft.setFont(&FreeSansBoldOblique12pt7b); 
  tft.println("Hello World!");
}

void loop() {

}

実行結果

Dscn8341

公式サイトにも説明がありますが、
FreeFontは表示位置がカーソル指定とずれるためちょっと使いにくいです。
等幅、プロポーショナルフォント、ボールド、イタリック等使い分けることが出来ますが、
それほど使用頻度は無いと思われます。


さて、利用しているこのグラフィック液晶モジュール、

Dscn8324

タッチパネルとSDカードスロットも搭載しています。
ピンもTFTとは独立してそれぞれ、SPIインタフェース対応の接続ピンがあります。
これらの機能も使い切ってみたいと思います。


2018年6月18日 (月)

Arduino STM32のUSB HIDインタフェースの新しいブートローダー

現在、Arduino for STM32のフォーラムの下記の
USB HIDインタフェースの新しいブートローダーに注目しています。
Small USB HID bootloader for BluePill and other STM32F10X devices

簡単にまとめると次のような感じです。
・USB HIDインタフェースの4Kバイト弱のブートローダーを別途サポートを予定
・OSへのドライバーインストール不要でスケッチの書込みが可能となる。
・フラッシュメモリの領域が4kバイト増加する。
・USB HIDブートローダ実行のトリガーはBOOT1ピンの状態で判定(の予定)

最新のArduino STM32の環境にも徐々にUSB HIDインタフェース関連の機能が
組み込まれている状況です(ただし、メニュー設定での利用は出来ない)。

USB HIDブートローダも公開されています。
rogerclarkmelbourne/STM32_HID_Bootloader
Serasidis/STM32_HID_Bootloader(オリジナル版)

豊四季Tiny BASIC for Arduino STM32をUSB HIDインタフェースの新しいブートローダー
に切り替えようと思い、4月から提供待ち状態です。

メリットとしては
・Blue Pillを使うにおいて、環境によて、
  ドライバーのインストールやUSBポートの認識にかなり手こずる場合もあり、
  これが軽減されることが期待できます。
・4kバイトのプログラム領域が開くので、コマンドをいくつか追加出来る。
(現状は、領域に空きが無くて機能追加が出来ない状態です)

ただし、BOOT1ピンをプログラム自動起動モード設定に利用していたので、
別のピンに変更する必要があります。


2018/08/20 追記

最近のアップデートをインストールして確認したところ、
アップデート方法にHIDブートローダを使うメニューも追加されていました。

09

ブートローダを書き込んで試したところ、
スケッチの書き込みも出来ました。

13

詳細については、続編の
Arduino STM32のUSB HIDインタフェースの新しいブートローダー (2)
にまとめました。

2018年6月14日 (木)

Lenovo Miix 2 8 を久々に使ってみる

「ポメラが欲しい」という衝動をぐっとこらえて、

あまり活用していなかったLenovo Miix 2 8で何とかしようと模索中です。

Windows 10にアップデートし、良さげなキーボードを付けたりして
そこそこ活用できそうな感じになってきました。

Dscn8219

キーボードは、こんな感じで乗せるタイプです。

Dscn8228

折りたたんでノートPCみたいな感じで利用出来ます。
キーボードを付けても重さは575gなので持ち運びも苦にならないです。

Dscn8221

暫くこれを持ち歩いて、使ってみることにしよう。


2018年6月11日 (月)

CH340E搭載小型USB-シリアル変換モジュールの調査

AliexpressにてCH340Eを使った小型USB-シリアル変換モジュールを見つけ入手しました。

1PCS CH340E USB to TTL Serial Converter, 5V/3.3V Model:BTE17-06 Alternative CH340G Module
00

1個 $0.53ですが、送料が$1.32かかります。1個だけの注文だと割高になるので5個購入。
5個でも送料は$1.32でした。

このモジュールはaitendoでも販売されているようです。

到着したモジュール
Dscn8178

基板の実装状態は良好な製品です。

GND、5V、TXD、RXD、DTR、3.3Vの6端子があります。
DTRが使えるので、シリアル経由のプログラム書き込みにも利用出来ます。
ポリヒューズが乗っており過電流の対策も施されています。
3.3Vは内蔵レギュレーターで生成しています。

Dscn8188

早速、Arduino Pro mini (5V 16MHz)で書き込みテストを行ってみました。

Dscn8202

Lチカスケッチは問題なく書き込めました。

次に秋月で購入したATmega328P(内部RC 8MHz)への書込みを試してみます。

Dscn8205

書込みでエラー発生。

02

念のため、コマンドラインにて接続チェックをしましたがやはりエラー発生です。

01

ケーブルやリセット回りの実装等を見直すも、原因不明です。
様子的にはDTRによるリセットはちゃんの行われているようですが、
それ以降のデータ通信が上手く行っていないようです。

念のため利用実績のあるCP2102搭載のUSB-シリアル変換モジュールで
書込み確認してみました。

Dscn8209

問題無く書き込み出来ました。何回やってもエラーなしです。

04_2

当然、接続確認も問題なし。

03


CH340E搭載モジュール固有の問題のようです。
Arduino Pro mini (5V 16MHz)では問題なく書き込めていたので、
CH340EがRC発振8MHzの精度の悪さに敏感なためエラーになっているのかもしれません。

CH340E搭載モジュールとCP2102搭載を直結して57600bps設定で通信が出来ることを
確認したので、57600bps設定の通信も問題無く出来ています。

原因については、ロジックアナライザ等を使ってもう少し調べてみることにします。

2018/06/12 追記
ロジックアナライザにて正常書込みが出来るCP2102モジュールと上手くいかない
CH340Eの信号を調べてみました。

CP2012モジュール利用時
06

CH340Eモジュール利用時
05

どうも、CH340EモジュールのDTR信号に問題があるようです。
Atmega328Pは外部リセットピンのLOW→HIGHの立上りでMCU起動の遅延タイマが
スタートし始動しますが、これではブートローダが動く前にデータが送られて処理出来ません。

色々調べると、CH340搭載モジュールの一部にはこれと同様の問題があるようです。
   参考にしたサイト
   ・Arduino Forum Topic: CH340 programmer not auto-resetting (Read 2806 times)
   ・くつしたねこのTinkering,Tinkering and Obliquity - Arduino互換機を作りたい(3)
   ・Memoteki - Arduinoに書き込めない問題を修正する方法[not in sync]

上記のサイトに解決策があり、早速参考にしてみました。
次の回路を付加してCH340EモジュールのDTR出力から短いワンショットパルスを生成します。   

07
Dscn8210

これにより、DTR信号からRESET信号を生成できました。
一番下が生成したRESET信号です。

08

CP2012モジュールのDTRとほぼ同じ信号が生成出来ました。
ただし、これでも書込みがうまくいきません。
もう少し調べてみることにします。

« 2018年5月 | トップページ | 2018年7月 »