256色モードでDMAを使用して10x10のキャラクタを画面に表示するサンプルプログラムです。
96*64バイトの画面の大きさと同じscreen_bufferを2つ作成して交互にDMA転送している。
TinyScreen::writeBufferDMAは画面を転送する前に戻って来るのでTinyScreen::getReadyStatusDMA()で
DMA転送が終わったかどうか毎回チェックしている。
TinyScreen::writeBufferでは画面描画には256色で約4550マイクロ秒,65536色で約9100マイクロ秒かかるが
TinyScreen::writeBufferDMAではその時間を省く事ができる。
その代わり画面に表示されている画像は1フレーム前の画像になる。
また、このサンプルでは60FPSで描画している。
#include <TinyScreen.h> #define COLOR8(r,g,b) ((b>>5)<<5|(g>>5)<<2|(r>>6)) static const unsigned int SCREEN_WIDTH = 96; static const unsigned int SCREEN_HEIGHT = 64; static const unsigned int BUFFER_SIZE = (SCREEN_WIDTH * SCREEN_HEIGHT); static const unsigned int BUFFER_COUNT = 2; static const unsigned long FPS = 60; static const unsigned long INTERVAL_TIME = 1000000 / FPS; TinyScreen tiny_screen = TinyScreen(TinyScreenPlus); unsigned char screen_buffer[BUFFER_COUNT][BUFFER_SIZE]; unsigned long micros_time; int current_buffer; int x; int anime_count; // Character image const unsigned char Hiyoko_1[10 * 10] = { 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x40, 0x40, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0xFF, 0x40, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x40, 0x40, 0x1B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x0F, 0x0F, 0x0F, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x5B, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00 }; const unsigned char Hiyoko_2[10 * 10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x40, 0x40, 0x1B, 0x1B, 0x1B, 0x5B, 0x5B, 0x5B, 0x00, 0x1B, 0xFF, 0x40, 0x1B, 0x1B, 0x5B, 0x1B, 0x1B, 0x5B, 0x00, 0x1B, 0x40, 0x40, 0x1B, 0x5B, 0x1B, 0x1B, 0x1B, 0x5B, 0x0F, 0x0F, 0x0F, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00 }; void setup() { tiny_screen.begin(); tiny_screen.setBitDepth(TSBitDepth8); tiny_screen.setBrightness(7); tiny_screen.setFont(liberationSansNarrow_12ptFontInfo); tiny_screen.fontColor(TS_8b_White, TS_8b_Black); tiny_screen.initDMA(); current_buffer = 0; x = 86; anime_count = 0; } // Draw sprite no clip void DrawSprite(const unsigned char* buffer, int x, int y, int width, int height, int color_key) { int scan_x; int scan_y; int source_address = 0; int destination_address = SCREEN_WIDTH * y + x; for(scan_y = 0; scan_y < height; ++ scan_y) { for(scan_x = 0; scan_x < width; ++ scan_x) { unsigned char color = buffer[source_address + scan_x]; if(static_cast<int>(color) != color_key) { screen_buffer[current_buffer][destination_address + scan_x] = color; } } source_address += width; destination_address += SCREEN_WIDTH; } } void loop() { unsigned long interval_time = micros() - micros_time; if(interval_time > INTERVAL_TIME) { // Clear buffer memset(screen_buffer[current_buffer], COLOR8(30, 30, 100), BUFFER_SIZE); // Move & draw sprite -- x; if(x < 0) { x = 86; } ++ anime_count; if(anime_count >= 16) { anime_count = 0; } if(anime_count < 8) { DrawSprite(Hiyoko_1, x, 27, 10, 10, 0); } else { DrawSprite(Hiyoko_2, x, 27, 10, 10, 0); } // Wait DMA transfer while(!tiny_screen.getReadyStatusDMA()); // End transfer tiny_screen.endTransfer(); // Start DMA transfer current_buffer = 1 - current_buffer; tiny_screen.goTo(0, 0); tiny_screen.setX(0, SCREEN_WIDTH - 1); tiny_screen.setY(0, SCREEN_HEIGHT - 1); tiny_screen.startData(); tiny_screen.writeBufferDMA(screen_buffer[current_buffer], BUFFER_SIZE); micros_time = micros(); } }