フォト
2017年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  
無料ブログはココログ

ARM

2017年3月23日 (木)

次はSTM32ボードを積極的に使ていきたい(11)

Blue PillでIchigoJamのような、BASICインタプリタを動かしたいと思い、
vintagechipsさんが公開している豊四季タイニーBASICを動かしてみました。

関連情報
   ・電脳伝説 Vintagechips - 豊四季タイニーBASIC確定版

シンプルなプログラムでいい感じです。
対話型 BASICインタプリタの売り、「トライ&RUN」を行うには編集機能がちょっと弱いです。
そこで、IchigoJamのような感じでプログラム入力が出来るよう、ちょっと機能追加しました。

動画はtinyBASIC 起動直後の表示メッセージに行番号とPRINT文付けて
プログラム化してしまう操作デモです。
フルスクリーン編集対応しているからこそ出来る操作です。


MCURSESを使って手を加えただけで、結構イケてる環境にビフォー&アフターしました。
MCURSESスバラシイ..

スクリーン制御が出来ると凝ったプログラムが作れますね。
次のコマンドを追加しました。

CLS,LOCATE,COLOR,ATTR,WAIT

02_2

こんな感じで指定した位置の文字を色を付けて表示出来ます。

修正版を下記にて公開します

・Tamakichi/ttbasic_arduino 豊四季タイニーBASIC for Arduino 修正版 V0.1
  https://github.com/Tamakichi/ttbasic_arduino
まだまだ、ガンガン修正していきます.

Blue Pillでは、USBでのシリアル接続での利用となります。
Arduino MEGAでも動作しました。Arduno UNOはメモリ不足で動きません。

01_2

2017年3月16日 (木)

次はSTM32ボードを積極的に使ていきたい(10)

Blue Pillボードのフラッシュメモリの容量の確認

Blue PillボードにはARMマイコン STM32F103C8が搭載されています。

STM32F103C8は、公式にはフラッシュメモリ容量は64kバイトなのですが、
実際には128kバイトのものが流通しているとのことです。

実際にどうなのか、ちょっと確かめてしました。
まずは、搭載マイコンの刻印のチェック



STM32F103C8T6」と明記されています。

データシートにより、このマイコンのフラッシュメモリサイズは64kバイトのはずです。

03

次に、実際にフラッシュメモリサイズを128kバイトと仮定して、
その領域の最終領域のアドレス 0x801FC00 に書き込みを行ってみました。
フラッシュメモリはページ単位(1kバイト)で消去、16ビット単位で書き込みが出来ます。

04

書き込み確認用スケッチ

特定の文字列をフラッシュメモリ上の指定アドレスに書き込んで、その内容を
確認するプログラムです。
64kバイト目のページと128kバイト目のページに異なる文字列を書きこんで、
シリアル接続にて内容を確認します。

//
// FILE stm31_testFlash
// フラッシュメモリ書き込みテスト for Arduino STM32
// 作成日 2017/03/16 by たま吉さん
//

#define FLASH_PAGE_SIZE        1024
#define FLASH_START_ADDRESS    ((uint32)(0x8000000))

#include <string.h>
#include "stm32_hexedit.h"
#include "TFlash.h"

uint8_t str1[] = "1234567890A";
uint8_t str2[] = "abcdefghij";

void Arduino_putchar(uint8_t c) {
  Serial.write(c);
}

char Arduino_getchar() {
  char c;
  while (!Serial.available());
  return Serial.read();
}

uint32_t adr0 = FLASH_START_ADDRESS + FLASH_PAGE_SIZE *  63;
uint32_t adr1 = FLASH_START_ADDRESS + FLASH_PAGE_SIZE *  127;

void setup() {
  Serial.begin(115200);
  while (!Serial.isConnected()) delay(100);
  setFunction_putchar(Arduino_putchar); 
  setFunction_getchar(Arduino_getchar); 
  initscr();

  // フラッシュメモリ書き込みテスト
  TFlash.unlock();
  TFlash.eracePage(adr0);
  TFlash.write((uint16_t*)adr0, str1, strlen((char*)str1));
  TFlash.eracePage(adr1);
  TFlash.write((uint16_t*)adr1, str2, strlen((char*)str2));
  TFlash.lock();
}

void loop() {
  // 64kバイトフラッシュメモリ最終ページの参照
  clear();
  hexedit2 (adr0, false);

  // 128kバイトフラッシュメモリ最終ページの参照
  clear();
  hexedit2 (adr1, false);  
}

スケッチを実行して確認すると、64kバイト目のページ、128kバイト目のページに
それぞれちゃんと書き込めていました。

ページ63、64kバイト目のページへの書込みの確認

06

ページ127、128kバイト目のページへの書込みの確認

05

ということで、STM32F103C8T6 ですが128kバイト利用出来ます。
ただし、生産ロット・時期により64kバイトの可能性もあります。

動作確認で利用した、フラッシュメモリ書き込みは色々と使えそうなので
ライブラリ化しました。

   ・Arduino STM32用 内部フラッシュメモリ書き込みライブラリ
     https://github.com/Tamakichi/ArduinoSTM32_TFlash

     まだ、ドキュメント等は未作成です。

     動作確認したスケッチはそのまま、ライブラリのサンプルとして入れています。
     別途、mcursesライブラリ(https://github.com/ChrisMicro/mcurses)が必要です。

 

2017年3月14日 (火)

次はSTM32ボードを積極的に使ていきたい(9)

TVoutライブラリと互換性の高いライブラリ

「次はSTM32ボードを積極的に使ていきたい(7)」で作成した、
「Arduino STM32用 NTSCビデオ出力ラブラリ」の上位層のライブラリを作成しました。

Arduino用のTVoutライブラリと互換性の高いAPIを実装しました。
TVoutのソースの一部を利用しています。

02

GitHubの方に登録&公開しました。
  ・Arduino STM32 TVoutライブラリ - TTVout
   https://github.com/Tamakichi/ArduinoSTM32_TVout


サンプルスケッチの動作の様子です
(だだし、古いバージョンのものです)




回路図(接続図)は次のような感じとなります。

01
使い方等については、公開ページの説明を参照願います。


ライブラリの実装において、ARM cortex-M3のビットバンド機能を使ってみました。
メモリ上のデータをビット単位で効率よく操作する仕組みです。

具体的には、1ビット毎にワードアドレス(32ビット)を割り付け、
そのアドレスへの読み書きでビット単位の読み書きが出来る仕組みです。

ビット操作を行うドット描画部分関数sp()に適用しました。
このsp()は、直線や円等の描画にも利用しています。
以下がその関数の実装部分です。

//
// ドット描画
// 引数
//  x:横座標
//  y:縦座標
//  c:色 0:黒 1:白 それ以外:反転
//
static void inline sp(uint16_t x, uint16_t y, uint8_t c) {
#if BITBAND==1
  if (c==1)
    _adr[_width*y+ (x&0xf8) +7 -(x&7)] = 1;
  else if (c==0)
    _adr[_width*y+ (x&0xf8) +7 -(x&7)] = 0;
  else 
    _adr[_width*y+ (x&0xf8) +7 -(x&7)] ^= 1;
#else
  if (c==1)
    _screen[(x/8) + (y*_hres)] |= 0x80 >> (x&7);
  else if (c==0)
    _screen[(x/8) + (y*_hres)] &= ~0x80 >> (x&7);
  else
    _screen[(x/8) + (y*_hres)] ^= 0x80 >> (x&7);
#endif
}

BITBANDが1の場合、ビットバンドを利用してフレームバッファのビットを操作します。
BITBANDが1でない場合は、ビットバンドを利用しません。かわりにビットシフト等にて
ビット操作を行います。

上記ソースでビットバンドを利用している場合と利用していない場合で
フレームバッファのアドレスが_adr、_screenといった具合に異なるのは、ビットバンドでの
アドレス操作が32バイト単位のため、型変換とアドレス変換を行っているためです。
    _adr = (volatile uint32_t*)(BB_SRAM_BASE + ((uint32_t)_screen - BB_SRAM_REF) * 32);

画面224x216ドットを1点ずつ点を描画して全面白色処理を行った場合、
ビットバンド機能を利用すると、全体で10%くらいパフォーマンスが向上しました。
10%は大きいです。

このビットバンド機能、ARMでもCortex-M3、Cortex-M4しかないようです。

2017年3月12日 (日)

次はSTM32ボードを積極的に使ていきたい(8)

Arduino STM32環境 Blue PillボードでPWMを使った単音演奏

01

Blue Pillボード(STM32F103C8)でPWMを使った「こいのぼり」の単音演奏をやってみました。
音の出力には圧電スピーカー(圧電サウンダ)を使いました。
ゲームなんかの効果音には使えますね。

演奏の様子
(ちょっと音が小さいです)


回路図

02

スケッチ

「こいのぼり」の演奏部分はスイッチサイエンスさんのサンプルスケッチを流用させていただきました。
SWICHI SCIENCE MAGAZINE - Arduinoで童謡「鯉のぼり」を流してみよう

/*
 *  Arduino STN32
 *  Stm32ボード(STM32F103C8T6)で PWMで任意の周波数を生成する
 *  作成日 2017/01/17 by たま吉さん

 *  説明
 *  ・PB9端子の圧電スピーカーを接続することで任意の周波数を音を出す
 *  ・Timer4 チャンネル 4 を利用しているため、PWM出力ピンはPB9固定

 *  参考にした情報
 *  ・Topic: DUE PWM Frequency (Read 51962 times) 
 *    https://forum.arduino.cc/index.php?topic=131323.15
 *    
 *  サンプル作成に参考にしたサイト
 *  ・Arduinoで童謡「鯉のぼり」を流してみよう
 *    http://mag.switch-science.com/2015/04/29/gwprojact_koinobori/
 */

//
// 音出し
// 引数
//  pin     : PWM出力ピン (現状はPB9固定)
//  freq    : 出力周波数 (Hz) 15~ 50000
//  duration: 出力時間(msec)
//
const int pwmOutPin = PB9;  // PWM出力ピン
void _tone(uint8_t pin, uint16_t freq, uint16_t duration = 0) {
  if (freq < 15 || freq > 50000 ) {
     _notone(pin);
  } else {
    uint32_t f =1000000/(uint16_t)freq;
    Timer4.setPrescaleFactor(72); // システムクロックを1/72に分周
    Timer4.setOverflow(f);
    Timer4.refresh();
    Timer4.resume(); 
    pwmWrite(pin, f/2);  
    if (duration) {
      delay(duration);
      Timer4.pause(); 
    }
  }
}

//
// 音の停止
// 引数
// pin     : PWM出力ピン (現状はPB9固定)
//
void _notone(uint8_t pin) {
    Timer4.pause();  
}

//HardwareTimer pwmtimer(2);
#define PIN pwmOutPin
void setup() {  
  pinMode(pwmOutPin, PWM);
  _tone(pwmOutPin,440, 100);
  _tone(pwmOutPin,880,100);  
  delay(500);

  _tone(PIN, 330, 150);
  delay(150);
  _tone(PIN, 294, 150);
  delay(150);
  _tone(PIN, 262, 300);
  delay(300);
  _tone(PIN, 294, 300);
  delay(300);
  _tone(PIN, 330, 300);
  delay(300);
  _tone(PIN, 440, 300);
  delay(300);
  _tone(PIN, 392, 150);
  delay(300);
  _tone(PIN, 330, 150);
  delay(150);
  _tone(PIN, 330, 150);
  delay(150);
  _tone(PIN, 330, 300);
  delay(300);
  _tone(PIN, 294, 150);
  delay(150);
  _tone(PIN, 262, 150);
  delay(150);
  _tone(PIN, 294, 300);
}

void loop() {
  
}


Arduino STM32では音を出すためのAPIとしてtone()関数があります。
  参考:  ・Arduino for STM32 - tone() and notone() have been added to the libmaple core

使ってみると音がちょっと汚いです。濁ったような音です。
原因はタイマー割り込みを使って、出力をオン・オフしているためです。
他の様々な割り込みの影響により、タイミングがずれたりして濁った音になっています。
(USBシリアル、SysTicの時間処理等)

また、このやり方だとCPU負荷もそれなりにかかります。
今後のビデオ出力を使ったゲーム作成なんかに使うにはちょと問題ありです。

そこで、PWM出力に置き換えて綺麗な音が出るようにしました。
音が出ている間はCPU負荷がかかりません。

問題点としては、利用するピンが固定となることです。標準のtone()では任意のピン
を使って音が出せます。

2017年2月28日 (火)

次はSTM32ボードを積極的に使ていきたい(7)

「次はSTM32ボードを積極的に使ていきたい(5)」でやったNTSCビデオ出力を改良しました。
水平同期パルス、垂直同期パルスをPWM出力を使って実装しました。
これで、利用する割り込み処理を少し減らせました。

02

画面は縦を192ドットから216ドットに広げました。 

03

同期信号はPWM出力に変更したため、利用ピンをA1に変更しました。

01

このNTSCビデオ出力はライブラリ化して、GitHubの方に登録&公開しました。
  ・Arduino STM32用 NTSCビデオ出力ラブラリ
   https://github.com/Tamakichi/ArduinoSTM32_TNTSC

ただし、このライブラリはフレームバッファ内のデータをただ表示するだけの機能しかありません。
別途描画処理を行う上位のライブラリが必要となります。 


2017/03/03 追記

画面解像度を5パターン対応しました。

https://github.com/Tamakichi/ArduinoSTM32_TNTSC の公開版は
V2.2にバージョンアップしました。

02

添付のサンプルスケッチも差し換えました。
画面解像度を動的に変更します。

05

04

2017年2月16日 (木)

次はSTM32ボードを積極的に使ていきたい(5)

やっと落ち着いてきました。 ブログを再開します^^
(NAVERとは徹底的に戦うつもりでしたが、時間の経過とともにどうでもよくなってきました)

安価なSTM32ボードでNTSCビデオ出力に挑戦、取りあえず表示出来ました。
プログラムの作成は、Arduino STM32環境を利用しました。

Dscn6446

解像度は取りあえず、モノクロ 224x192ドットです。
文字を表示するだけのデモプログラムです。

Dscn6444


回路図

01

端子A7: 映像信号出力
端子B1: 同期信号出力
GND : GND

抵抗値の計算は面倒なので、スマホのHandyCalcで計算しました。
連立方程式を入力すれば、解いてくれるので非常に便利です。

02

式のr1が端子A7: 映像信号出力に接続する抵抗、
式のr2が端子B1: 同期信号出力に接続する抵抗です。
r3は接続先モニターの内部抵抗で、75Ω(固定値)としています。

抵抗を使って3.3Vを分圧します。
3.3Vが白レベルが1V、同期信号レベルが0.3Vとなる様に抵抗を決定します。
求められた値に近い抵抗を使っています。

ビデオ信号生成方法及び抵抗の計算方法等については、次の情報を参考にいたしました。
大変参考になりました(感謝!)。
  ・nekosanさんのHP: 「PIC AVR 工作室  - ビデオ表示のツボ」
     http://picavr.uunyan.com/making_p_ntsc.html
  ・ChaNさんのHP: 「S-170A NTSCビデオ信号タイミング規格の概要」
     http://elm-chan.org/docs/rs170a/spec_j.html
  ・KOUSAKUさんのHP 建築発明工作ゼミ2008
    「Arduino ビデオ信号/テレビ画面に出力」
    「Arduino ビデオ信号/バウンドするドット」



スケッチ(プログラム)
GitHubGist: Tamakichi/stm32_video.ino

Arduino IDE 1.8.1+ArduinoSTM32環境を利用しています。
別途美咲フォントライブラリ Arduino-misakiUTF16 が必要です。

//
// Arduino STM32 NTSCビデオ出力 サンプル V2.0
// Blue Pillボード(STM32F103C8)にて動作確認
// 最終更新日 2017/02/17 たま吉さん
//

#include <SPI.h>
#include <misakiUTF16.h>  // 美咲フォントライブラリ

#define gpio_write(pin,val) gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val)

#define CLK PB1           // 同期信号出力ピン
#define DAT PA7           // 映像信号出力ピン
#define SC_WIDTH 224      // 横解像度
#define SC_HIGHT 192      // 縦解像度

#define SYNC(V)  gpio_write(CLK,V)  // 同期信号出力
#define VRAMSIZE (224*192/8) // ビデオ表示フレームバッファサイズ

int count=1;                 // 走査線を数える変数
uint8_t vram[VRAMSIZE];      // ビデオ表示フレームバッファ
uint8_t* ptr;                // ビデオ表示フレームバッファ参照用ポインタ
uint8_t flgHsync = 0;        // 水平同期信号出力フラグ
uint8_t flgVideo = 0;        // 映像信号出力フラグ

//垂直同期信号
inline void vsync(){
  SYNC(0);
  delay_us(27);
  SYNC(1);
  delay_us(5);
}

// フォント描画
void drawFont(int x, int y, uint8_t* font) {
  uint8_t* ptr = &vram[y*28*8+x];
  for (int i=0; i<8; i++) {
    *ptr = *font;
    ptr+=28;
    font++;
  }
}

// 文字列描画
void drawText(int x, int y, char* str) {
  uint8_t  fnt[8];
  while(*str) {
    if (x>=28)
      break;
    if (! (str = getFontData(fnt, str)) )  {
         Serial.println("Error"); 
         break;
    }
    drawFont(x,y ,fnt);
    x++;
  }  
}

// 画面クリア
void cls() {
  memset(vram, 0, VRAMSIZE);
}

// DMA用割り込みハンドラ(データ出力をクリア)
void DMA1_CH3_handle() {
  while(SPI.dev()->regs->SR & SPI_SR_BSY);
    SPI.dev()->regs->DR = 0;  
}

// DMAを使ったデータ出力
void SPI_dmaSend(uint8_t *transmitBuf, uint16_t length) {
  dma_setup_transfer( 
    DMA1,DMA_CH3,         // SPI1用DMAチャンネル3を指定
    &SPI.dev()->regs->DR, // 転送先アドレス    :SPIデータレジスタを指定
    DMA_SIZE_8BITS,       // 転送先データサイズ : 1バイト
    transmitBuf,          // 転送元アドレス     : SRAMアドレス
    DMA_SIZE_8BITS,       // 転送元データサイズ : 1バイト
    DMA_MINC_MODE|        // フラグ: サイクリック
    DMA_FROM_MEM|         //         メモリから周辺機器、転送完了割り込み呼び出しあり 
    DMA_TRNS_CMPLT        //         転送完了割り込み呼び出しあり 
  );
  dma_set_num_transfers(DMA1, DMA_CH3, length); // 転送サイズ指定
  dma_enable(DMA1, DMA_CH3);  // DMA有効化
}

// タイマー割り込みハンドラ(走査線の処理)
void handle_video() {
  SYNC(0); 
  flgHsync = 0;
  flgVideo = 0;
  if(count>=3 && count<=5){
    //垂直同期信
    vsync();
    vsync();    
  } else if (count >35 && count <227) { 
    flgHsync = 1; //水平同期信号出力有効
    flgVideo = 1; //映像信号出力有効
  } else {
    flgHsync = 1; //水平同期信号出力有効
  }
  count++; 
  if(count>262) {
    count=1;
    ptr = vram;    
  }
}

// 水平同期信号出力
void handle_hsync() {
  if (flgHsync)
    SYNC(1);    
}

// ビデオ用データ表示(ラスタ出力)
void handle_vout() {
  if (flgVideo) {
    SPI_dmaSend((uint8_t *)ptr, 28);
    ptr+=28;    
  }  
}

void setup(){

  // ジッター防止のためタイマー割り込み優先度を上げる
   nvic_irq_set_priority(NVIC_TIMER2, 0); // 割り込み優先レベル設定
  
  pinMode(CLK,OUTPUT); // 同期信号出力ピン

  // SPIの初期化・設定
  SPI.begin(); 
  SPI.setBitOrder(MSBFIRST); 
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  SPI.dev()->regs->CR1 |=SPI_CR1_BIDIMODE_1_LINE|SPI_CR1_BIDIOE; // 送信のみ利用の設定

  // SPIデータ転送用DMA設定
  dma_init(DMA1);
  dma_attach_interrupt(DMA1, DMA_CH3, &DMA1_CH3_handle);
  spi_tx_dma_enable(SPI.dev());  
 
  ptr = vram;
 
  /// タイマ2の初期設定
  Timer2.pause();                    // タイマー停止
  Timer2.setPrescaleFactor(3);       // システムクロック 72MHzを24MHzに分周 
  Timer2.setOverflow(1524);          // カウンタ値1524でオーバーフロー発生 63.5us周期

  // +0.0us 更新時呼び出し 割込みハンドラの登録
  Timer2.attachInterrupt(TIMER_UPDATE_INTERRUPT, handle_video); 

  // +4.7us 水平同期信号出力用 割り込みハンドラ登録
  Timer2.setCompare(1, 112);
  Timer2.setMode(1,TIMER_OUTPUTCOMPARE);
  Timer2.attachInterrupt(1, handle_hsync);     

  // +9.4us 映像出力用 割り込みハンドラ登録
  Timer2.setCompare(2, 225);
  Timer2.setMode(2,TIMER_OUTPUTCOMPARE);
  Timer2.attachInterrupt(2, handle_vout);   

  Timer2.refresh();  // タイマーの更新
  Timer2.resume();   // タイマースタート

  // 画面表示
  cls();
  drawText(3,3,"■■STM32ボードでNTSC出力テスト■■");
  drawText(7,6,"ねこにコ・ン・バ・ン・ワ");
  drawText(5,8,"解像度は224x192ドットです");
  drawText(6,12,"まだまだ色々と調整中です^^");
}

void loop(){
}

スケッチ(プログラム)の解説 (2017/02/18 追記・更新)

取りあえず、映像は表示出来たのですがかなり簡略化しています。
NTSCの仕様には完全には準拠していません。

NTSCビデオ信号の処理について
1画面は水平走査線262本で構成されています。
その走査線を先頭から番号を付けて1番から262番とすると

プログラムでは
  走査線   3番 ~   5番 で垂直同期信号の出力
  走査線 35番 ~227番 で映像信号出力
  上記以外は何も表示しない映像信号出力
を行っています。

垂直同期信号の出力
本来なら前置等価パルス3本、垂直同期パルス3本、後置等価パルス3本の
合計9本の走査線構成となりますが、前置・後置等価パルスは省略しています。

下記の垂直同期パルスを三回、走査線3本分のみを出力して同期を行っています。
(実際はdelay_us()を使った手抜きを行い、実際はちゃんと出ていません)
同期信号は0v or 0.3vのパルスで生成しています。

04

映像信号出力
前半に水平同期パルスを入れて、9.4usから映像出力を行っています。
水平同期パルスは0V or 0.3Vのパルス、映像信号は0.3V (黒) or 1.0V(白)です。
3.3Vを抵抗で分圧した後、合成して出力しています。

05

映像信号の出力はSPIを使っています。出力は72MHzのシステムクロックを1/16分周し
4.5MHzの速度で1ライン分28バイトを出力しています。
この場合、1クロック幅は0.22usとなり、映像出力期間としてさ有効な52.6us(実際は
この幅はとれない)は236ドット分となります。
実際は、224ドットしかとれませんでした。

システムクロック 72MHzは、NTSCビデオ出力に使うには相性が悪いです。
分周クロックが6~8MHZくらいを作れれば理想の256ドットくらいに出来るのですが..
SPIのクロック分周は2,4,6,8,16,32..としか出来ません。
1/8分周で1ライン448ドットは可能ですが、微妙に解像度が高くて使いにくいです。

SPIの送信バッファへのデータ補充はDMA転送を使ってします。
DMAは大変便利です。CPUの処理と切り離して勝手にやってくれます。

Arduino STM32にはSPI.dmaSend()というSPI出力をDMA経由で行うAPIがあるのですが、
このAPI、関数内で転送完了待ちのポーリング(ループ)を行っており折角のDMAの利点
が半減してしまうので、自作しました。
転送完了の割り込み通知にて映像信号をOFFにしています。
(これをしないと最後の出力データがHIGHの場合、画面が崩れます)

映像出力用のクロックは、Timer2を利用しています。
システムクロック72MHzを1/3分周して24MHzのクロックとして利用しています。
24MHzですと、走査線幅63.5usは1524クロック分となります。
主要タイミングのクロックは次のようになります。

走査線 63.5us                    1524
水平同期パルス幅 4.7us       112
映像出力開始       9.4us       225

各種同期信号、映像信号出力は上記のタイミングで処理を行い、
3つのタイミングで割り込み関数を呼び出しています。
  ・走査線・垂直同期用 : handle_video()
  ・水平同期用             : handle_hsync()
  ・映像信号出力用      : handle_vout()

タイマー機能は流石にARMだけあって高機能です。
タイマーの使い方については下記のサイトを参考にしました。
  LeafLabs Documentation
    ・Timers
    ・HardwareTimer
    ・libmaple APIs timer.h

NTSCビデオ出力については、もうちょっと機能強化してArduinoのTVoutのような
ライブラリにしようと思います。

2017/02/17 更新
ジッター防止及びUSB経由書き込み不全は、タイマー割り込みの優先度を上げることで
対応出来ました。スケッチを修正しました。

(注意)
スケッチは、ジッター防止のためUSBシリアル通信を停止しています。
=> Serial.end();

これを実行すると、Arduino IDEからUSB経由での直後のスケッチ書き込みが自動では
行えなくなります。


次にスケッチ書込みを行う場合は、「マイコンボードに書き込んでいます」の表示が
されたタイミングで、リセットボタンを押すと書き込みが出来ます。

03

2016年12月 7日 (水)

次はSTM32ボードを積極的に使ていきたい(4)

ここ数日、STM32ボードをArduino環境にて使うことにこだわって調べています。
その状況をこのタイトルのシリーズにてしばらく続けていきます。

Blue Pillボードの設計ミス (= USB経由のスケッチ書き込みの原因)

私が使っているSTM32F103C8T6搭載ボード、Arduino STM32のサポートフォーラムでは
Blue Pillと呼ばれています。

01

このボードには何種類かあるようですが、設計ミスがあるようです。
この件に関しては、フォーラムの 「Red Pill or Blue Pill?」にて議論されています。

具体的にはUSBのD+のプルアップ抵抗が本来は1.5kΩであるべきところを、
10kΩの抵抗が実装されています。
これが原因でUSB経由では、うまく書きこめない場合があるようです。

私の所有するBlue Pillボードも、調べてみると該当するD+のプルアップ抵抗が
10KΩになっていました。

03

私のパソコンではUSB書込みが出来ますが、パソコンの相性でたまたま書き込みが
出来ていた可能性があります。
(利用しているパソコン、Aliexpressで買ったので相性いいのかも^^)

注意:Blue PillボードでUSB経由で書き込みを可能にするには、ブートローダーを
        自分で書き込む必要があります。 フォーラムの次の記事に目を通すことをお勧めします。

          ・FAQ's and links - Please read if you are new
           http://www.stm32duino.com/viewtopic.php?f=2&t=873

ブートローダーを書き込んでもUSB経由でスケッチの書込みが出来ない場合は、
このR10抵抗を1.5kΩに付け替えるか、この抵抗に並列に1.8KΩの抵抗を接続
具体的にはPA12端子 - 3.3V間に1.8KΩの抵抗を接続すると良いようです。
(情報はフォーラムのこのあたり)


使えるライブラリ

STM32_arduinoのダウンロードサイトのWikiの情報はちょっと古いようです。
実際に使えそうなライブラリはフォーラムのWorking / ported librariesを見た方が良いです。

2016年12月 4日 (日)

次はSTM32ボードを積極的に使ていきたい(3)

STM32F103C8T6搭載ボード、
Arduino IDE環境で利用する場合のアナログ入力について調べてみました。

アナログジョイスティックのアナログ2入力をボード上のPB0、PB1に接続して実験しました。

Dscn6202

スケッチ

#define LED_PIN   PC13
#define SNS_X_PIN PB0
#define SNS_Y_PIN PB1

void setup() {
  pinMode(LED_PIN, OUTPUT);

  // アナログ入力利用設定
  pinMode(SNS_X_PIN, INPUT_ANALOG);
  pinMode(SNS_Y_PIN, INPUT_ANALOG);

  Serial.begin();
  while (!Serial.isConnected()) delay(100);

}

void loop() {

  // アナログジョイスティックによる入力
  uint16_t x,y;
  x = analogRead(SNS_X_PIN);
  y = analogRead(SNS_Y_PIN);
  Serial.print("(x,y) = (");
  Serial.print(x);
  Serial.print(",");
  Serial.print(y);
  Serial.println(")");
  delay(500);
}

実行結果

Photo_3

Arduinoと非互換なところ

analogread()で読み取れる値は12ビットの分解能となり0~4095の範囲の値となります。
Arduinoでは10ビット(0~1023)ですので、非互換となります。

また、Arduinoではアナログ入力の場合はpinMode()によるモード設定は不要でしたが、
stm32_arduino環境ではpinMode(SNS_X_PIN, INPUT_ANALOG) といった具合に必須となります。

この当たりの情報はstm32_arduinoのベースとなっている"LeafLabs Maple"のドキュメント
を参考にするよ良いようです。
・ LeafLabs Documentation  http://docs.leaflabs.com/docs.leaflabs.com/index.html
     - ADC http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/latest/adc.html
     - pinMode() http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/latest/lang/api/pinmode.html
     - analogRead() http://docs.leaflabs.com/static.leaflabs.com/pub/leaflabs/maple-docs/latest/lang/api/analogread.html

Arduinoのスケッチを移植して利用する際は、ちょっと注意が必要です。
対応としては、map関数を使ってスケール変換すると良いでしょう。
   例 x = map( analogRead(SNS_X_PIN), 0, 4095, 0, 1023) )


アナログ入力ピン指定
下図のADCラベルがあるピンが利用可能です。スケッチ内でのピン指定は
PA0、PA1、・・・ 、PB0、PB1
0、1、 ・・・、16、17
D0、D1、・・・、D16、D17


といった記述で指定出来ます。A0、A1やADC1、ADC2ではダメみたいです。



次はPWMを調べます(どうも、かなり違うっぽい)。

 


2016年12月 3日 (土)

次はSTM32ボードを積極的に使ていきたい(2)

STM32F103C8T6搭載ボードをArduino STM32環境下にて利用する場合に
利用出来るシリアルポートを調べてみました。

事前調査の通り、USB経由のシリアルを含め、4本使えました。
(UART1のピン割り付けは間違っていたので修正しました)。
これは大変便利です。シリアル通信を利用するプログラムを作る時、
もう一本使えるとデバッグが楽になります。

Dscn6201


動作確認に利用したスケッチ

#define LED_PIN D32 // PC13 or 32 or D32
void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin();
  while (!Serial.isConnected()) delay(100);
  Serial.println("Serial USBport");  
  Serial1.begin(115200);
  Serial1.println("Serial port1");
  Serial2.begin(115200);
  Serial2.println("Serial port2");
  Serial3.begin(115200);
  Serial3.println("Serial port3");
}

void loop() {
  digitalWrite(LED_PIN, HIGH); 
  delay(200);  
  digitalWrite(LED_PIN, LOW); 
  delay(200);
}

USB経由のシリアル通信はSerialオブジェクト、UART1、UART2、UART3が
Serial1、Serial2、Serail3オブジェクト使って利用出来ます。

Uplpad methodの指定の指定によっては、使えないポートがあるようです。
私は"STM32duino boot loader"指定していますが、"Serail"を指定すると
コンパイル時にSerial、Serail3を指定でエラーとなります。

02

USB経由のシリアル通信はちょと特殊な利用となります。
通信速度の指定をする必要がありません。指定してもエラーになりませんが、
指定値は無視されます。

最初は接続時に転送速度を自動調整しているのかと思ったのですが、
どうも違うようです。

対応していないような、通信速度でも正しく表示されます。

03

04

05

別の大量の出力を行うアスキーコード表示を行うスケッチを試すと
TeraTermの通信速度を極端に変えても常に同じ速度で出力されているようです。
ちょっと謎です。

また、USB経由でプログラムの書込みを行うため、
書込み中や直後ではUSB経由のシリアル通信は切断されます。
そのため、下記の1行を入れて、接続の確立をチェックと待ちが必要があります。
   while (!Serial.isConnected()) delay(100);

次は、PWM、analogReadが8ビット扱いなのか等を調べてみます。

2016年12月 1日 (木)

次はSTM32ボードを積極的に使ていきたい

Aliexpressで安売りしているSTM32F103C8T6搭載ボードを3個ポチりました。$1.52は安い!

01

Arduino IDEでの利用を可能とする「Arduino_STM32」がかなりよい感じに仕上がてきており、
販売者も商品名に「For Arduino」をうたうようになってきました。

$2程度と安い割には、
ARM Cortex-M3 72MHz CPU、フラッシュメモリ64kバイト、SRAM 20kバイトとArduino UNOと
比べると大容量で高速です。

今後は出来ることを調査し、積極的に使っていこうと思います。
まずは、Arduinoにて作成したスケッチの動作確認をやっていきます。

DMAを使ったグラフィック液晶なんかの高速描画あたりをちょっとやりたいです。

Arduino_STM32のソースを読んで、ピン割り付けを調べてみました。
実際にどういう感じで利用するかは、今後調べていきます。
ボード画像は、ネットで拾いました。ピン割りは自作です。

02

上図割り付け表のピンPAn、PBn、PCnとその横の朱色数字はプログラムソースに内で
直接指定することが出来ます。また数字にDを付けて指定も出来ます。

下記のソースのLチカスケッチはボード右上のLEDを点滅させるプログラムです。
#defineで定義したLED_PINのD32はPC13、32に置き換えることも可能です。

#define LED_PIN D32 // PC13 or 32 or D32
void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH); 
  delay(200);  
  digitalWrite(LED_PIN, LOW); 
  delay(200);
}


2016/12/03 追記

私が使っているSTM32F103C8T6搭載ボード、Arduino STM32のサポートフォーラムでは
Blue Pillと呼ばれているようです。

フォーラムの 「Red Pill or Blue Pill?」の記事に本ボードの説明がありました。
ボードのピン割り付けの情報もここにありました。
(自作のピン割り付けはは2つ目にI2Cが足りないようです)

このあたりの記事を読むと、Blue Pillボードにはいくつか異なる製品が流通している模様。
また、回路上、USB周りに問題がるボードがありUSB経由での書き込みが上手くいないケースもあるようです。
(USB用のPA12ピン接続のR10の抵抗に問題あり?)

Problem

「Red Pill or Blue Pill?」にはその議論や対策方法が紹介されています。

私のボードは取りあえず、USB経由で書き込み出来ます。
(たまに、書き込み後にエラーが出てる場合もありますが..)