├── README.md ├── examples └── MisakiFontOut │ └── MisakiFontOut.ino ├── image ├── 01.png ├── 02.jpg ├── 03.jpg ├── 04.png ├── 05.jpg ├── 06.jpg ├── 07.jpg ├── 08.jpg └── 09.jpg ├── keywords.txt ├── library.properties └── src ├── TNTSC.cpp └── TNTSC.h /README.md: -------------------------------------------------------------------------------- 1 | # Arduino STM32 NTSCビデオ出力ラブラリ 2 | ## 概要 3 | Arduino STM32環境にて利用可能なNTSCビデオ出力ドライバライブラリです. 4 | STM32F103x系マイコン搭載ボードにてNTSCビデオ出力を行うことが出来ます. 5 | 6 | **(注意)** 7 | 本ライブラリには描画処理を行うAPI関数は含まれていません。 8 | 描画処理を行うには別途上位のライブラリが必要となります。 9 | 10 | ![動作状況](./image/02.jpg) 11 | 12 | ## ライブラリ名称 13 | TNTSC (ヘッダーファイル TNTSC.h) 14 | 15 | ## 仕様 16 | 17 | - NTSCモノクロ2色(白・黒)表示 18 | - 表示解像度 14つのモード(システムクロック72MHz時・48MHz時合わせて) 19 | 横112×縦108ドット ~ 横512×縦216ドット)   20 | - ビデオ出力には下記リソースを利用します.   21 | - SRAM ビデオ表示用フレームバッファ 1,512~12,096バイト(解像度による)   22 | - タイマー Timer2 23 |  - SPI1 or SPI2 (begin()の第2引数spinoで指定可能、SPI1がデフォルト) 24 |  - DMA1 CH3   25 | 26 | ## 回路図 27 | ![回路図](./image/01.png) 28 | 接続端子 29 | PA1: 同期信号 30 | PA7: 映像信号(SPIにSPI1を利用した場合) 31 | ※SPIにSPI2を利用する場合、映像信号出力ピンはPB15となります. 32 | 33 | ## 必要部品 34 | - STM32F103xマイコンボード Blue Pill(STMF103C8T6搭載) 35 | - 560Ω 抵抗 36 | - 240Ω 抵抗 37 | - RCAジャック端子(NTSC対応モニターに接続) 38 | 39 | ## インストール 40 | TNTSCフォルダを各自のArduino STM32インストール先のライブラリ用フォルダに配置する. 41 | => インストールフォルダ\hardware\Arduino_STM32\STM32F1\libraries\ 42 | に配置. 43 | 44 | ## サンプルスケッチの実行 45 | ### サンプルスケッチ:MisakiFontOur 46 | 別途下記のライブラリのインストールが必要 47 | - Arduino-misakiUTF16 48 | (Arduino用 美咲フォントライブラリ 教育漢字・内部フラッシュメモリ乗せ版) 49 | https://github.com/Tamakichi/Arduino-misakiUTF16 50 | 51 | **実行結果**   52 | 画面解像度を5秒間隔で変更してデモメッセージを表示します. 53 | ![実行結果](./image/05.jpg) ![実行結果](./image/06.jpg) 54 | ![実行結果](./image/07.jpg) ![実行結果](./image/08.jpg) 55 | ![実行結果](./image/09.jpg) 56 | 57 | ## ライブラリリファレンス 58 | ライブラリはクラスライブラリとして実装しています. 59 | NTSCビデオ出力の操作はグローバルオブジェクト変数TNTSCを利用します。 60 | 61 | ### ヘッダーファイル 62 | `#include ` 63 | 64 | ### グローバルオブジェクト 65 | `TNTSC` 66 | 67 | ### 定数 68 | 画面解像度の指定   69 | ・システムクロック 72MHz設定時   70 | ``` 71 | #define SC_112x108 0 // 112x108 72 | #define SC_224x108 1 // 224x108 73 | #define SC_224x216 2 // 224x216 74 | #define SC_448x108 3 // 448x108 75 | #define SC_448x216 4 // 448x216 76 | #define SC_DEFAULT SC_224x216 77 | ``` 78 | ・システムクロック 48MHz設定時   79 | ``` 80 | #define SC_128x96 0 // 128x96 81 | #define SC_256x96 1 // 256x96 82 | #define SC_256x192 2 // 256x192 83 | #define SC_512x96 3 // 512x96 84 | #define SC_512x192 4 // 512x192 85 | #define SC_128x108 5 // 128x108 86 | #define SC_256x108 6 // 256x108 87 | #define SC_256x216 7 // 256x216 88 | #define SC_512x108 8 // 512x108 89 | #define SC_512x216 9 // 512x216 90 | #define SC_DEFAULT SC_256x192 91 | ``` 92 | 93 | ### パブリックメンバー関数 94 | 95 | #### NTSCビデオ映像補正 96 | 97 | - 書式 98 | `void adjust(int16_t cnt, int16_t hcnt=0, int16_t vcnt=0);` 99 | - 引数 100 | cnt :垂直同期信号補正値(指定した水平走査線数分、タイミングを調整する) 101 | hcnt:横画像表示開始位置補正(指定したクロック数分、開始位置を補正する) 102 | vcnt:縦画像表示開始位置補正(指定した走査線数分、開始位置を補正する) 103 | - 戻り値 104 | なし 105 | - 説明 106 | NTSCビデオ出力に関するタイミング等の補正を行います。 107 | 利用しているモニターディスプレイの映像がスクロールしたり、映像が欠けたりする場合、この関数により補正出来る場合があります。 108 | 垂直同期が取れない(スクロールする、映像の下部がにじむ)場合は、cntを調整、画像位置を補正する場合は、hcnt、vcntにて補正が出来ます。 109 | この関数は、begin()関数の前に呼び出して下さい。 110 | 111 | #### NTSCビデオ出力開始 112 | 113 | - 書式 114 | `void begin(uint8_t mode=SC_DEFAULT,uint8_t spino = 1, uint8_t* extram=NULL)` 115 | 116 | - 引数 117 | mode :画面モード 118 | spino:利用するSPIの指定 1:SPI2(デフォルト)、2:SPI2 119 | extram:外部獲得フレームバッファ用メモリアドレス、NUULの場合は指定なし 120 | 121 | - 戻り値 122 | なし 123 | 124 | - 説明 125 | NTSCビデオ出力を開始します. 126 | 引数modeにて画面が解像度の指定が可能です。下記の指定が可能です. 127 | 128 | システムクロック 72MHz時 129 | 130 | mode|横ドット数|縦ドット数|使用メモリサイズ(バイト) 131 | :---:|--------:|--------:|---------------------:| 132 | SC_112x108|112|108|1,512 133 | SC_224x108|224|108|3,024 134 | SC_224x216|224|216|6,048 135 | SC_448x108|448|108|6,048 136 | SC_448x216|448|216|12,096 137 | SC_DEFAULT|224|216|6,048 138 | 139 | システムクロック 48MHz時   140 | 141 | mode|横ドット数|縦ドット数|使用メモリサイズ(バイト) 142 | :---:|--------:|--------:|---------------------:| 143 | SC_128x96|128|96|1,536 144 | SC_256x96|256|96|3,072 145 | SC_256x192|256|192|6,144 146 | SC_512x96|512|96|6,144 147 | SC_512x192|512|192|12,288 148 | SC_128x108|128|108|1,728 149 | SC_256x108|256|108|3,456 150 | SC_256x216|256|216|6,912 151 | SC_512x108|512|108|6,912 152 | SC_512x216|512|216|13,824 153 | SC_DEFAULT|256|192|6,144 154 | 155 | 指定した解像度に応じた表示用フレームバッファが動的に確保されます. 156 | 157 | #### NTSCビデオ出力終了 158 | 159 | - 書式 160 | `void end()` 161 | 162 | - 引数 163 | なし 164 | 165 | - 戻り値 166 | なし 167 | 168 | - 説明 169 | NTSCビデオ出力を終了します. 170 | 表示用フレームバッファ、およびタイマー割り込み等の資源を開放します. 171 | 172 | #### NTSCビデオ出力用フレームバッファ先頭アドレス取得 173 | 174 | - 書式 175 | `uint8_t* VRAM()` 176 | 177 | - 引数 178 | なし 179 | 180 | - 戻り値 181 | フレームバッファ先頭アドレス 182 | 183 | - 説明 184 | NTSCビデオ出力用フレームバッファ先頭アドレスを取得します. 185 | フレームバッファのバイトデータ内の1ビットは画面上の1ドットに対応しています. 186 | 1バイト内のビット並びは上位が左、下位が右となります. 187 | 188 | 画面モードが224x216ドットの場合のフレームバッファ構成 189 | ![フレームバッファ](./image/04.png)   190 | 191 | 取得したフレームバッファアドレスを利用してフレームバッファに直接データを 192 | 書き込むことで任意の表示を行うことが出来ます. 193 | 194 | #### 画面クリア 195 | 196 | - 書式 197 | `void cls()` 198 | 199 | - 引数 200 | なし 201 | 202 | - 戻り値 203 | なし 204 | 205 | - 説明 206 | フレームバッファを初期化し、画面表示をクリアします. 207 | 208 | #### フレーム表示待ち 209 | 210 | - 書式 211 | `void delay_frame(uint16_t x)` 212 | 213 | - 引数 214 | uint16_t x : 表示待ち枚数 215 | 216 | - 戻り値 217 | なし 218 | 219 | - 説明 220 | 指定したフレーム数の画面が表示されるまで時間待ちを行います. 221 | 画面の表示内容を高速に更新する場合、最低1フレーム分の表示待ちを行うことで 222 | チラつきにない更新を行うことが出来ます.   223 | 1フレームは約1/60秒(16.7ミリ秒)に相当します. 224 | 225 | #### 画面横ドット数の取得 226 | 227 | - 書式   228 | `uint16_t width()` 229 | 230 | - 引数 231 | なし 232 | 233 | - 戻り値 234 | 画面 横ドット数 235 | 236 | - 説明 237 | 現在の画面解像度の横ドット数を返します. 238 | 239 | #### 画面縦ドット数の取得 240 | 241 | - 書式   242 | `uint16_t height()` 243 | 244 | - 引数 245 | なし 246 | 247 | - 戻り値 248 | 画面 縦ドット数 249 | 250 | - 説明 251 | 現在の画面解像度の縦ドット数を返します. 252 | 253 | #### 表示用フレームバッファ利用サイズの取得 254 | 255 | - 書式   256 | `uint16_t vram_size()` 257 | 258 | - 引数 259 | なし 260 | 261 | - 戻り値 262 | 表示用フレームバッファ利用サイズ(バイト) 263 | 264 | - 説明 265 | 現在の画面解像度の表示用フレームバッファ利用サイズを返します. 266 | 267 | #### 画面モードの取得 268 | 269 | - 書式   270 | `uint16_t () screen()` 271 | 272 | - 引数 273 | なし 274 | 275 | - 戻り値 276 | 画面モード(0~4) 277 | 278 | - 説明 279 | 現在の画面モードを返します. 280 | 281 | 282 | #### サンプルスケッチ 283 | 284 | ``` 285 | #include 286 | #include // 美咲フォントライブラリ 287 | 288 | // フォント描画 289 | void drawFont(int x, int y, uint8_t* font) { 290 | uint8_t* ptr = &TNTSC.VRAM()[y*(TNTSC.width()/8)*8+x]; 291 | for (int i=0; i<8; i++) { 292 | *ptr = *font; 293 | ptr+=(TNTSC.width()/8); 294 | font++; 295 | } 296 | } 297 | 298 | // 文字列描画 299 | void drawText(int x, int y, char* str) { 300 | uint8_t fnt[8]; 301 | while(*str) { 302 | if (x>=(TNTSC.width()/8)) 303 | break; 304 | if (! (str = getFontData(fnt, str, true)) ) { 305 | Serial.println("Error"); 306 | break; 307 | } 308 | drawFont(x,y ,fnt); 309 | x++; 310 | } 311 | } 312 | 313 | void setup(){ 314 | 315 | } 316 | 317 | void loop(){ 318 | char str[32]; 319 | for (uint8_t i = 0; i <=4; i++) { 320 | TNTSC.begin(i); 321 | 322 | // 画面表示 323 | TNTSC.cls(); 324 | drawText(0, 0,"左上");drawText((TNTSC.width()/8)-2, 0,"右上"); 325 | drawText(0,(TNTSC.height()/8)-1,"左下");drawText((TNTSC.width()/8)-2,(TNTSC.height()/8)-1,"右下"); 326 | drawText(0,2,"  ■■NTSC出力■■  "); 327 | drawText(0,4," ねこにコ・ン・バ・ン・ワ "); 328 | 329 | sprintf(str, "解像度:%dx%dドット", TNTSC.width(), TNTSC.height()); 330 | drawText(0,6, str); 331 | drawText(0,9," まだまだ色々と調整中です "); 332 | 333 | delay(5000); 334 | TNTSC.end(); 335 | } 336 | } 337 | ``` 338 | -------------------------------------------------------------------------------- /examples/MisakiFontOut/MisakiFontOut.ino: -------------------------------------------------------------------------------- 1 | // 2 | // Arduino STM32 NTSCビデオ出力 サンプル V2.2 3 | // 最終更新日 2017/02/17 たま吉さん 4 | // Blue Pillボード(STM32F103C8)にて動作確認 5 | // 6 | // 修正履歴 7 | // 2017/02/17 水平・垂直同期信号をPWM出力で行うように変更,解像度を224x216に変更 8 | // 2017/02/20 NTSCビデオ表示部をライブラリ化 9 | // 2017/03/03 解像度モード追加 10 | // 2017/06/25 オブジェクトを動的に生成する仕様変更対応 11 | // 2017/11/18 NTSCオブジェクトのグローバル化対応 12 | // 13 | 14 | #include 15 | 16 | #include // 美咲フォントライブラリ 17 | 18 | // フォント描画 19 | void drawFont(int x, int y, uint8_t* font) { 20 | uint8_t* ptr = &TNTSC.VRAM()[y*(TNTSC.width()/8)*8+x]; 21 | for (int i=0; i<8; i++) { 22 | *ptr = *font; 23 | ptr+=(TNTSC.width()/8); 24 | font++; 25 | } 26 | } 27 | 28 | // 文字列描画 29 | void drawText(int x, int y, char* str) { 30 | uint8_t fnt[8]; 31 | while(*str) { 32 | if (x>=(TNTSC.width()/8)) 33 | break; 34 | if (! (str = getFontData(fnt, str, true)) ) { 35 | Serial.println("Error"); 36 | break; 37 | } 38 | drawFont(x,y ,fnt); 39 | x++; 40 | } 41 | } 42 | 43 | void setup(){ 44 | 45 | } 46 | 47 | void loop(){ 48 | char str[32]; 49 | for (uint8_t i = 0; i <=4; i++) { 50 | TNTSC.begin(i,2); // 第2引数でSPI 1,2を指定(デフォルト 1)) 51 | TNTSC.adjust(0); // 垂直同期信号補正(デフォルト 0) 52 | 53 | // 画面表示 54 | TNTSC.cls(); 55 | drawText(0, 0,"左上");drawText((TNTSC.width()/8)-2, 0,"右上"); 56 | drawText(0,(TNTSC.height()/8)-1,"左下");drawText((TNTSC.width()/8)-2,(TNTSC.height()/8)-1,"右下"); 57 | drawText(0,2,"  ■■NTSC出力■■  "); 58 | drawText(0,4," ねこにコ・ン・バ・ン・ワ "); 59 | 60 | sprintf(str, "解像度:%dx%dドット", TNTSC.width(), TNTSC.height()); 61 | drawText(0,6, str); 62 | drawText(0,9," まだまだ色々と調整中です "); 63 | 64 | delay(5000); 65 | TNTSC.end(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /image/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/01.png -------------------------------------------------------------------------------- /image/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/02.jpg -------------------------------------------------------------------------------- /image/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/03.jpg -------------------------------------------------------------------------------- /image/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/04.png -------------------------------------------------------------------------------- /image/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/05.jpg -------------------------------------------------------------------------------- /image/06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/06.jpg -------------------------------------------------------------------------------- /image/07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/07.jpg -------------------------------------------------------------------------------- /image/08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/08.jpg -------------------------------------------------------------------------------- /image/09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tamakichi/ArduinoSTM32_TNTSC/dce262c8b6e2817f41aa36ec8bf77975b60b1417/image/09.jpg -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map TNTSC 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | TNTSC KEYWORD1 9 | 10 | begin KEYWORD2 11 | end KEYWORD2 12 | VRAM KEYWORD2 13 | cls KEYWORD2 14 | width KEYWORD2 15 | height KEYWORD2 16 | vram_size KEYWORD2 17 | delay_frame KEYWORD2 18 | screen KEYWORD2 19 | setBktmStartHook KEYWORD2 20 | setBktmEndHook KEYWORD2 21 | adjust KEYWORD2 22 | ####################################### 23 | # Constants (LITERAL1) 24 | ####################################### 25 | SC_112x108 LITERAL1 26 | SC_224x108 LITERAL1 27 | SC_224x216 LITERAL1 28 | SC_448x108 LITERAL1 29 | SC_448x216 LITERAL1 30 | SC_DEFAULT LITERAL1 31 | SC_128x96 LITERAL1 32 | SC_256x96 LITERAL1 33 | SC_256x192 LITERAL1 34 | SC_512x96 LITERAL1 35 | SC_512x192 LITERAL1 36 | SC_128x108 LITERAL1 37 | SC_256x108 LITERAL1 38 | SC_256x216 LITERAL1 39 | SC_512x108 LITERAL1 40 | SC_512x216 LITERAL1 41 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=TNTSC 2 | version=1.1 3 | author=Tamakichi 4 | email=tamacat2014@gmail.com 5 | sentence=NTSC video out driver 6 | paragraph=NTSC video out for STM32F1 7 | url=https://github.com/Tamakichi/ArduinoSTM32_NTSC 8 | architectures=STM32F1 9 | maintainer=Tamakichi 10 | category=Device Control 11 | includes=NTSC.h 12 | -------------------------------------------------------------------------------- /src/TNTSC.cpp: -------------------------------------------------------------------------------- 1 | // FILE: TNTSC.cpp 2 | // Arduino STM32 用 NTSCビデオ出力ライブラリ by たま吉さん 3 | // 作成日 2017/02/20, Blue Pillボード(STM32F103C8)にて動作確認 4 | // 更新日 2017/02/27, delay_frame()の追加 5 | // 更新日 2017/02/27, フック登録関数追加 6 | // 更新日 2017/03/03, 解像度モード追加 7 | // 更新日 2017/04/05, クロック48MHz対応 8 | // 更新日 2017/04/18, SPI割り込みの廃止(動作確認中) 9 | // 更新日 2017/04/27, NTSC走査線数補正関数追加 10 | // 更新日 2017/04/30, SPI1,SPI2の選択指定を可能に修正 11 | // 更新日 2017/06/25, 外部確保VRAMの指定を可能に修正 12 | 13 | #include 14 | #include 15 | 16 | #define gpio_write(pin,val) gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val) 17 | 18 | #define PWM_CLK PA1 // 同期信号出力ピン(PWM) 19 | #define DAT PA7 // 映像信号出力ピン 20 | #define NTSC_S_TOP 3 // 垂直同期開始ライン 21 | #define NTSC_S_END 5 // 垂直同期終了ライン 22 | #define NTSC_VTOP 30 // 映像表示開始ライン 23 | #define IRQ_PRIORITY 2 // タイマー割り込み優先度 24 | #define MYSPI1_DMA_CH DMA_CH3 // SPI1用DMAチャンネル 25 | #define MYSPI2_DMA_CH DMA_CH5 // SPI2用DMAチャンネル 26 | #define MYSPI_DMA DMA1 // SPI用DMA 27 | 28 | // 画面解像度別パラメタ設定 29 | typedef struct { 30 | uint16_t width; // 画面横ドット数 31 | uint16_t height; // 画面縦ドット数 32 | uint16_t ntscH; // NTSC画面縦ドット数 33 | uint16_t hsize; // 横バイト数 34 | uint8_t flgHalf; // 縦走査線数 (0:通常 1:半分) 35 | uint32_t spiDiv; // SPIクロック分周 36 | } SCREEN_SETUP; 37 | 38 | #if F_CPU == 72000000L 39 | #define NTSC_TIMER_DIV 3 // システムクロック分周 1/3 40 | const SCREEN_SETUP screen_type[] __FLASH__ { 41 | { 112, 108, 216, 14, 1, SPI_CLOCK_DIV32 }, // 112x108 42 | { 224, 108, 216, 28, 1, SPI_CLOCK_DIV16 }, // 224x108 43 | { 224, 216, 216, 28, 0, SPI_CLOCK_DIV16 }, // 224x216 44 | { 448, 108, 216, 56, 1, SPI_CLOCK_DIV8 }, // 448x108 45 | { 448, 216, 216, 56, 0, SPI_CLOCK_DIV8 }, // 448x216 46 | }; 47 | #elif F_CPU == 48000000L 48 | #define NTSC_TIMER_DIV 2 // システムクロック分周 1/2 49 | const SCREEN_SETUP screen_type[] __FLASH__ { 50 | { 128, 96, 192, 16, 1, SPI_CLOCK_DIV16 }, // 128x96 51 | { 256, 96, 192, 32, 1, SPI_CLOCK_DIV8 }, // 256x96 52 | { 256, 192, 192, 32, 0, SPI_CLOCK_DIV8 }, // 256x192 53 | { 512, 96, 192, 64, 1, SPI_CLOCK_DIV4 }, // 512x96 54 | { 512, 192, 192, 64, 0, SPI_CLOCK_DIV4 }, // 512x192 55 | { 128, 108, 216, 16, 1, SPI_CLOCK_DIV16 }, // 128x108 56 | { 256, 108, 216, 32, 1, SPI_CLOCK_DIV8 }, // 256x108 57 | { 256, 216, 216, 32, 0, SPI_CLOCK_DIV8 }, // 256x216 58 | { 512, 108, 216, 64, 1, SPI_CLOCK_DIV4 }, // 512x108 59 | { 512, 216, 216, 64, 0, SPI_CLOCK_DIV4 }, // 512x216 60 | }; 61 | #endif 62 | 63 | #define NTSC_LINE (262+0) // 画面構成走査線数(一部のモニタ対応用に2本に追加) 64 | #define SYNC(V) gpio_write(PWM_CLK,V) // 同期信号出力(PWM) 65 | static uint8_t* vram; // ビデオ表示フレームバッファ 66 | static volatile uint8_t* ptr; // ビデオ表示フレームバッファ参照用ポインタ 67 | static volatile int count=1; // 走査線を数える変数 68 | 69 | static void (*_bktmStartHook)() = NULL; // ブランキング期間開始フック 70 | static void (*_bktmEndHook)() = NULL; // ブランキング期間終了フック 71 | 72 | static uint8_t _screen; 73 | static uint16_t _width; 74 | static uint16_t _height; 75 | static uint16_t _ntscHeight; 76 | static uint16_t _vram_size; 77 | static uint16_t _ntsc_line = NTSC_LINE; 78 | static uint16_t _ntsc_adjust = 0; 79 | static uint16_t _hAdjust = 0; // 横表示位置補正 80 | static uint16_t _vAdjust = 0; // 縦表示位置補正 81 | static uint8_t _spino = 1; 82 | static dma_channel _spi_dma_ch = MYSPI1_DMA_CH; 83 | static dma_dev* _spi_dma = MYSPI_DMA; 84 | static SPIClass* pSPI; 85 | 86 | uint16_t TNTSC_class::width() {return _width;;} ; 87 | uint16_t TNTSC_class::height() {return _height;} ; 88 | uint16_t TNTSC_class::vram_size() { return _vram_size;}; 89 | uint16_t TNTSC_class::screen() { return _screen;}; 90 | 91 | 92 | // ブランキング期間開始フック設定 93 | void TNTSC_class::setBktmStartHook(void (*func)()) { 94 | _bktmStartHook = func; 95 | } 96 | 97 | // ブランキング期間終了フック設定 98 | void TNTSC_class::setBktmEndHook(void (*func)()) { 99 | _bktmEndHook = func; 100 | } 101 | 102 | // DMA用割り込みハンドラ(データ出力をクリア) 103 | void TNTSC_class::DMA1_CH3_handle() { 104 | while(pSPI->dev()->regs->SR & SPI_SR_BSY); 105 | pSPI->dev()->regs->DR = 0; 106 | } 107 | 108 | // DMAを使ったデータ出力 109 | void TNTSC_class::SPI_dmaSend(uint8_t *transmitBuf, uint16_t length) { 110 | dma_setup_transfer( 111 | _spi_dma, _spi_dma_ch, // SPI1用DMAチャンネル指定 112 | &pSPI->dev()->regs->DR, // 転送先アドレス :SPIデータレジスタを指定 113 | DMA_SIZE_8BITS, // 転送先データサイズ : 1バイト 114 | transmitBuf, // 転送元アドレス : SRAMアドレス 115 | DMA_SIZE_8BITS, // 転送先データサイズ : 1バイト 116 | DMA_MINC_MODE| // フラグ: サイクリック 117 | DMA_FROM_MEM | // メモリから周辺機器、転送完了割り込み呼び出しあり 118 | DMA_TRNS_CMPLT // 転送完了割り込み呼び出しあり */ 119 | ); 120 | dma_set_num_transfers(_spi_dma, _spi_dma_ch, length); // 転送サイズ指定 121 | dma_enable(_spi_dma, _spi_dma_ch); // DMA有効化 122 | } 123 | 124 | // ビデオ用データ表示(ラスタ出力) 125 | void TNTSC_class::handle_vout() { 126 | if (count >=NTSC_VTOP+_vAdjust && count <=_ntscHeight+NTSC_VTOP+_vAdjust-1) { 127 | 128 | SPI_dmaSend((uint8_t *)ptr, screen_type[_screen].hsize); 129 | //pSPI->dmaSend((uint8_t *)ptr, screen_type[_screen].hsize,1); 130 | if (screen_type[_screen].flgHalf) { 131 | if ((count-NTSC_VTOP) & 1) 132 | ptr+= screen_type[_screen].hsize; 133 | } else { 134 | ptr+=screen_type[_screen].hsize; 135 | } 136 | } 137 | 138 | // 次の走査線用同期パルス幅設定 139 | if(count >= NTSC_S_TOP-1 && count <= NTSC_S_END-1){ 140 | // 垂直同期パルス(PWMパルス幅変更) 141 | TIMER2->regs.adv->CCR2 = 1412; 142 | } else { 143 | // 水平同期パルス(PWMパルス幅変更) 144 | TIMER2->regs.adv->CCR2 = 112; 145 | } 146 | 147 | count++; 148 | if( count > _ntsc_line ){ 149 | count=1; 150 | ptr = vram; 151 | } 152 | 153 | } 154 | 155 | void TNTSC_class::adjust(int16_t cnt, int16_t hcnt, int16_t vcnt) { 156 | _ntsc_adjust = cnt; 157 | _ntsc_line = NTSC_LINE+cnt; 158 | _hAdjust = hcnt; 159 | _vAdjust = vcnt; 160 | } 161 | 162 | // NTSCビデオ表示開始 163 | void TNTSC_class::begin(uint8_t mode, uint8_t spino, uint8_t* extram) { 164 | // スクリーン設定 165 | _screen = mode <=4 ? mode: SC_DEFAULT; 166 | _width = screen_type[_screen].width; 167 | _height = screen_type[_screen].height; 168 | _vram_size = screen_type[_screen].hsize * _height; 169 | _ntscHeight = screen_type[_screen].ntscH; 170 | _spino = spino; 171 | flgExtVram = false; 172 | 173 | if (extram) { 174 | vram = extram; 175 | flgExtVram = true; 176 | } else { 177 | vram = (uint8_t*)malloc(_vram_size); // ビデオ表示フレームバッファ 178 | } 179 | cls(); 180 | ptr = vram; // ビデオ表示用フレームバッファ参照ポインタ 181 | count = 1; 182 | 183 | // SPIの初期化・設定 184 | if (spino == 2) { 185 | pSPI = new SPIClass(2); 186 | _spi_dma = MYSPI_DMA; 187 | _spi_dma_ch = MYSPI2_DMA_CH; 188 | } else { 189 | pSPI = &SPI; 190 | _spi_dma = MYSPI_DMA; 191 | _spi_dma_ch = MYSPI1_DMA_CH; 192 | }; 193 | pSPI->begin(); 194 | pSPI->setBitOrder(MSBFIRST); // データ並びは上位ビットが先頭 195 | pSPI->setDataMode(SPI_MODE3); // MODE3(MODE1でも可) 196 | if (_spino == 2) { 197 | pSPI->setClockDivider(screen_type[_screen].spiDiv-1); // クロックをシステムクロック36MHzの1/8に設定 198 | } else { 199 | pSPI->setClockDivider(screen_type[_screen].spiDiv); // クロックをシステムクロック72MHzの1/16に設定 200 | } 201 | pSPI->dev()->regs->CR1 |=SPI_CR1_BIDIMODE_1_LINE|SPI_CR1_BIDIOE; // 送信のみ利用の設定 202 | 203 | // SPIデータ転送用DMA設定 204 | dma_init(_spi_dma); 205 | dma_attach_interrupt(_spi_dma, _spi_dma_ch, &DMA1_CH3_handle); 206 | spi_tx_dma_enable(pSPI->dev()); 207 | 208 | /// タイマ2の初期設定 209 | nvic_irq_set_priority(NVIC_TIMER2, IRQ_PRIORITY); // 割り込み優先レベル設定 210 | Timer2.pause(); // タイマー停止 211 | Timer2.setPrescaleFactor(NTSC_TIMER_DIV); // システムクロック 72MHzを24MHzに分周 212 | Timer2.setOverflow(1524); // カウンタ値1524でオーバーフロー発生 63.5us周期 213 | 214 | // +4.7us 水平同期信号出力設定 215 | pinMode(PWM_CLK,PWM); // 同期信号出力ピン(PWM) 216 | timer_cc_set_pol(TIMER2,2,1); // 出力をアクティブLOWに設定 217 | pwmWrite(PWM_CLK, 112); // パルス幅を4.7usに設定(仮設定) 218 | 219 | // +9.4us 映像出力用 割り込みハンドラ登録 220 | Timer2.setCompare(1, 225-60+_hAdjust); // オーバーヘッド分等の差し引き 221 | Timer2.setMode(1,TIMER_OUTPUTCOMPARE); 222 | Timer2.attachInterrupt(1, handle_vout); 223 | 224 | Timer2.setCount(0); 225 | Timer2.refresh(); // タイマーの更新 226 | Timer2.resume(); // タイマースタート 227 | } 228 | 229 | // NTSCビデオ表示終了 230 | void TNTSC_class::end() { 231 | Timer2.pause(); 232 | Timer2.detachInterrupt(1); 233 | spi_tx_dma_disable(pSPI->dev()); 234 | dma_detach_interrupt(_spi_dma, _spi_dma_ch); 235 | pSPI->end(); 236 | if (!flgExtVram) 237 | free(vram); 238 | if (_spino == 2) { 239 | delete pSPI; 240 | //pSPI->~SPIClass(); 241 | } 242 | } 243 | 244 | // VRAMアドレス取得 245 | uint8_t* TNTSC_class::VRAM() { 246 | return vram; 247 | } 248 | 249 | // 画面クリア 250 | void TNTSC_class::cls() { 251 | memset(vram, 0, _vram_size); 252 | } 253 | 254 | // フレーム間待ち 255 | void TNTSC_class::delay_frame(uint16_t x) { 256 | while (x) { 257 | while (count != _ntscHeight + NTSC_VTOP); 258 | while (count == _ntscHeight + NTSC_VTOP); 259 | x--; 260 | } 261 | } 262 | 263 | 264 | TNTSC_class TNTSC; 265 | 266 | -------------------------------------------------------------------------------- /src/TNTSC.h: -------------------------------------------------------------------------------- 1 | // FILE: TNTSC.h 2 | // Arduino STM32 用 NTSCビデオ出力ライブラリ by たま吉さん 3 | // 作成日 2017/02/20, Blue Pillボード(STM32F103C8)にて動作確認 4 | // 更新日 2017/02/27, delay_frame()の追加、 5 | // 更新日 2017/02/27, フック登録関数追加 6 | // 更新日 2017/03/03, 解像度モード追加 7 | // 更新日 2017/04/05, クロック48MHz対応 8 | // 更新日 2017/04/27, NTSC走査線数補正関数adjust()追加 9 | // 更新日 2017/04/30, SPI1,SPI2の選択指定を可能に修正 10 | // 更新日 2017/06/25, 外部確保VRAMの指定を可能に修正 11 | // 更新日 2018/08/05, 水平・垂直表示位置補正の追加 12 | // 13 | 14 | #ifndef __TNTSC_H__ 15 | #define __TNTSC_H__ 16 | 17 | #include 18 | 19 | #if F_CPU == 72000000L 20 | #define SC_112x108 0 // 112x108 21 | #define SC_224x108 1 // 224x108 22 | #define SC_224x216 2 // 224x216 23 | #define SC_448x108 3 // 448x108 24 | #define SC_448x216 4 // 448x216 25 | #define SC_DEFAULT SC_224x216 26 | #elif F_CPU == 48000000L 27 | #define SC_128x96 0 // 128x96 28 | #define SC_256x96 1 // 256x96 29 | #define SC_256x192 2 // 256x192 30 | #define SC_512x96 3 // 512x96 31 | #define SC_512x192 4 // 512x192 32 | #define SC_128x108 5 // 128x108 33 | #define SC_256x108 6 // 256x108 34 | #define SC_256x216 7 // 256x216 35 | #define SC_512x108 8 // 512x108 36 | #define SC_512x216 9 // 512x216 37 | #define SC_DEFAULT SC_256x192 38 | #endif 39 | 40 | // ntscビデオ表示クラス定義 41 | class TNTSC_class { 42 | private: 43 | uint8_t flgExtVram; // 外部確保メモリ利用(0:利用なり 1:利用あり) 44 | 45 | public: 46 | void begin(uint8_t mode=SC_DEFAULT,uint8_t spino = 1, uint8_t* extram=NULL); // NTSCビデオ表示開始 47 | void end(); // NTSCビデオ表示終了 48 | uint8_t* VRAM(); // VRAMアドレス取得 49 | void cls(); // 画面クリア 50 | void delay_frame(uint16_t x); // フレーム換算時間待ち 51 | void setBktmStartHook(void (*func)()); // ブランキング期間開始フック設定 52 | void setBktmEndHook(void (*func)()); // ブランキング期間終了フック設定 53 | 54 | uint16_t width() ; 55 | uint16_t height() ; 56 | uint16_t vram_size(); 57 | uint16_t screen(); 58 | void adjust(int16_t cnt, int16_t hcnt=0, int16_t vcnt=0); 59 | 60 | private: 61 | static void handle_vout(); 62 | static void SPI_dmaSend(uint8_t *transmitBuf, uint16_t length) ; 63 | static void DMA1_CH3_handle(); 64 | }; 65 | 66 | extern TNTSC_class TNTSC; // グローバルオブジェクト利用宣言 67 | 68 | #endif 69 | --------------------------------------------------------------------------------