jpfont_2_lcd.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #include <stdio.h>
  2. #include <malloc.h>
  3. #include <memory.h>
  4. #include "pico/stdlib.h"
  5. #include "hardware/spi.h"
  6. #include "hardware/dma.h"
  7. #include "hardware/timer.h"
  8. #include "pfnfont.h"
  9. #define SPI_PORT spi0
  10. #define PIN_MISO 16
  11. #define PIN_CS 17
  12. #define PIN_SCK 18
  13. #define PIN_MOSI 19
  14. #define TFT_DC 20 // LOW:Command | HIGH:Data
  15. #define TFT_RES 21
  16. #define TFT_COMMAND false
  17. #define TFT_DATA true
  18. #define TFT_WIDTH 240 // LCD縦ピクセル数
  19. #define TFT_HEIGHT 240 // LCD横ピクセル数
  20. #define TFT_BYTES_PER_PIXEL 2
  21. #define TFT_COLOR_BLACK 0x0000
  22. #define TFT_COLOR_BLUE 0x001F
  23. #define TFT_COLOR_RED 0xF800
  24. #define TFT_COLOR_GREEN 0x07E0
  25. #define TFT_COLOR_CYAN 0x07FF
  26. #define TFT_COLOR_MAGENTA 0xF81F
  27. #define TFT_COLOR_YELLOW 0xFFE0
  28. #define TFT_COLOR_WHITE 0xFFFF
  29. #define SSTCMD_SWRESET 0x01
  30. #define SSTCMD_SLPOUT 0x11
  31. #define SSTCMD_NORON 0x13
  32. #define SSTCMD_INVOFF 0x20
  33. #define SSTCMD_INVON 0x21
  34. #define SSTCMD_DISPOFF 0x28
  35. #define SSTCMD_DISPON 0x29
  36. #define SSTCMD_MADCTL 0x36
  37. #define SSTCMD_COLMOD 0x3A
  38. #define SSTCMD_INVCTR 0xB4
  39. #define SSTCMD_CASET 0x2A
  40. #define SSTCMD_RASET 0x2B
  41. #define SSTCMD_RAMWR 0x2C
  42. typedef struct {
  43. uint8_t start_x;
  44. uint8_t start_y;
  45. uint8_t end_x;
  46. uint8_t end_y;
  47. } sst7735_rect;
  48. inline int sst7735_rect_len(sst7735_rect *r)
  49. {
  50. return (r->end_x-r->start_x) * (r->end_y - r->start_y);
  51. }
  52. static inline void sst7735_send_cmd(uint8_t cmd)
  53. {
  54. gpio_put(TFT_DC, TFT_COMMAND);
  55. spi_set_format (SPI_PORT, 8, SPI_CPOL_1 , SPI_CPHA_1,SPI_MSB_FIRST );
  56. spi_write_blocking(SPI_PORT, &cmd, sizeof(uint8_t));
  57. gpio_put(TFT_DC, TFT_DATA);
  58. }
  59. static inline void sst7735_send_data8(uint8_t *data, size_t len)
  60. {
  61. gpio_put(TFT_DC, TFT_DATA);
  62. spi_set_format (SPI_PORT, 8, SPI_CPOL_1 , SPI_CPHA_1,SPI_MSB_FIRST );
  63. spi_write_blocking(SPI_PORT, data, len);
  64. // gpio_put(TFT_DC, TFT_DATA);
  65. }
  66. static inline void sst7735_send_data16(uint16_t *data, size_t len)
  67. {
  68. gpio_put(TFT_DC, TFT_DATA);
  69. spi_set_format (SPI_PORT, 16, SPI_CPOL_1 , SPI_CPHA_1,SPI_MSB_FIRST );
  70. spi_write16_blocking(SPI_PORT, data, len);
  71. // gpio_put(TFT_DC, TFT_DATA);
  72. }
  73. static inline void sst7735_reset()
  74. {
  75. gpio_put(TFT_RES, true);
  76. sleep_ms(500); // 500ms
  77. gpio_put(TFT_RES, false);
  78. sleep_ms(100); // RESET pulse 100ms
  79. gpio_put(TFT_RES, true);
  80. sleep_ms(500); // 500ms
  81. sst7735_send_cmd(SSTCMD_SWRESET); // Software Reset
  82. sleep_ms(100); // delay 100ms
  83. }
  84. static inline void sst7735_init(void)
  85. {
  86. uint8_t cmd_param[4];
  87. sst7735_send_cmd(SSTCMD_DISPOFF); // Display Off
  88. sleep_ms(500);
  89. sst7735_send_cmd(SSTCMD_SLPOUT); // Sleep Out
  90. sleep_ms(500);
  91. sst7735_send_cmd(SSTCMD_DISPON); // Display on
  92. sleep_ms(100);
  93. sst7735_send_cmd(SSTCMD_COLMOD); // Color mode
  94. cmd_param[0] = 0x55; // 16bit mode
  95. sst7735_send_data8(cmd_param, 1);
  96. sleep_ms(100);
  97. sst7735_send_cmd(SSTCMD_MADCTL);
  98. cmd_param[0] = 0x00;
  99. sst7735_send_data8(cmd_param, 1); // RGB 16bit mode
  100. sleep_ms(100);
  101. // sst7735_send_cmd(SSTCMD_NORON);
  102. sst7735_send_cmd(SSTCMD_INVON);
  103. }
  104. void sst7735_draw_image(uint16_t *image, sst7735_rect *rect)
  105. {
  106. uint8_t cmd_param[4] = {0,0,0,0};
  107. cmd_param[1] = rect->start_x;
  108. cmd_param[3] = rect->end_x;
  109. sst7735_send_cmd(SSTCMD_CASET); // Column Address Set
  110. sst7735_send_data8(cmd_param, 4);
  111. cmd_param[1] = rect->start_y;
  112. cmd_param[3] = rect->end_y;
  113. sst7735_send_cmd(SSTCMD_RASET); // Row Address Set
  114. sst7735_send_data8(cmd_param, 4);
  115. sst7735_send_cmd(SSTCMD_RAMWR); // RAM RW mode
  116. sleep_us(100);
  117. sst7735_send_data16((uint16_t *)image, sst7735_rect_len(rect));
  118. }
  119. void sst7735_clear(void)
  120. {
  121. uint16_t *temp_buf;
  122. sst7735_rect r = {start_x:0, start_y:0, end_x:TFT_WIDTH, end_y:TFT_HEIGHT};
  123. temp_buf = (uint16_t *)calloc(TFT_HEIGHT * TFT_WIDTH, sizeof(uint16_t));
  124. sst7735_draw_image(temp_buf, &r);
  125. free(temp_buf);
  126. }
  127. int dma_ch = -1; // DMAチャンネル
  128. dma_channel_config dma_conf; // DMA設定
  129. volatile bool dma_in_prgress = false; // DMA転送中フラグ
  130. // ワンショットタイマー遅延呼び出し用
  131. int64_t schedule_deferred_call(alarm_id_t id, void *user_data)
  132. {
  133. // DMA転送中フラグを落とす
  134. dma_in_prgress = false;
  135. return 0;
  136. }
  137. // DMA割り込み
  138. void dma_irq_handler()
  139. {
  140. dma_channel_acknowledge_irq0(dma_ch);
  141. // 遅延を入れないと死ぬ
  142. // ワンショットタイマーで20マイクロ秒後にフラグを落とす
  143. add_alarm_in_us(20, schedule_deferred_call, NULL, true);
  144. }
  145. uint8_t *string_line_buffer[2]; // 1行バッファ
  146. int buffer_selector = 0; // バッファセレクタ
  147. uint16_t back_color = TFT_COLOR_BLACK; // 背景色
  148. uint16_t font_color = TFT_COLOR_WHITE; // 文字色
  149. PFNFont *pfn; // PFNフォントオブジェクト
  150. // 1行バッファ内にフォントグリフを描くコールバック関数
  151. void draw_font_in_buffer(font_gryph_t *gryph, int x, int y)
  152. {
  153. // uint16_tポインタとしてバッファを扱う
  154. uint16_t *line_buf = (uint16_t*)string_line_buffer[buffer_selector];
  155. for(int r = 0; r < gryph->height; r++) {
  156. for(int c = 0; c < gryph->width; c++) {
  157. // 画面外描画をクリップ
  158. if ((x + c) >= TFT_WIDTH) continue;
  159. int bit_index = r * gryph->width + c;
  160. int byte_index = bit_index / 8;
  161. int bit_offset = bit_index % 8;
  162. if ((gryph->bitmap[byte_index] >> (7 - bit_offset)) & 1) {
  163. line_buf[r * TFT_WIDTH + (x + c)] = font_color;
  164. } else {
  165. // 背景塗りつぶし済み
  166. }
  167. }
  168. }
  169. }
  170. // 文字列描画用DMA設定関数
  171. void configure_dma_channel(void)
  172. {
  173. dma_ch = dma_claim_unused_channel(true);
  174. dma_conf = dma_channel_get_default_config(dma_ch);
  175. channel_config_set_transfer_data_size(&dma_conf, DMA_SIZE_16);
  176. channel_config_set_read_increment(&dma_conf, true);
  177. channel_config_set_write_increment(&dma_conf, false);
  178. uint dreq = spi_get_dreq(SPI_PORT, true);
  179. channel_config_set_dreq(&dma_conf, dreq);
  180. // DMA割り込み設定
  181. dma_channel_set_irq0_enabled(dma_ch, true);
  182. irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler);
  183. irq_set_enabled(DMA_IRQ_0, true);
  184. dma_channel_configure(
  185. dma_ch,
  186. &dma_conf,
  187. &spi_get_hw(SPI_PORT)->dr, // DATAレジスタ(SSPDR)
  188. string_line_buffer[buffer_selector],// Dummy(後で設定)
  189. 2, // Dummy
  190. false
  191. );
  192. }
  193. // 文字をLCDにレンダリングする
  194. void render_string(const char *str, int x, int y)
  195. {
  196. int render_width = 0;
  197. // DMAが設定されていなければ何もしない
  198. if(dma_ch < 0)
  199. return;
  200. // 1行バッファのサイズ
  201. size_t line_buffer_size = TFT_WIDTH * pfn->get_max_font_height() * TFT_BYTES_PER_PIXEL;
  202. // バッファを背景色で塗りつぶし
  203. uint16_t* current_buffer = (uint16_t*)string_line_buffer[buffer_selector];
  204. for (int i = 0; i < line_buffer_size / TFT_BYTES_PER_PIXEL; ++i) {
  205. current_buffer[i] = back_color;
  206. }
  207. // 文字をバッファに描画
  208. render_width = pfn->draw_string(str, x, 0);
  209. if(render_width == 0 )
  210. return;
  211. // 前のDMAを待つ
  212. while(dma_in_prgress);
  213. // SST77xxコマンド発行
  214. uint8_t cmd_param[4] = {0,0,0,0};
  215. cmd_param[1] = 0;
  216. cmd_param[3] = TFT_WIDTH;
  217. sst7735_send_cmd(SSTCMD_CASET); // Column Address Set
  218. sst7735_send_data8(cmd_param, 4);
  219. cmd_param[1] = y;
  220. cmd_param[3] = y + pfn->get_max_font_height();
  221. sst7735_send_cmd(SSTCMD_RASET); // Row Address Set
  222. sst7735_send_data8(cmd_param, 4);
  223. sst7735_send_cmd(SSTCMD_RAMWR); // RAM RW mode
  224. sleep_us(50);
  225. gpio_put(TFT_DC, TFT_DATA);
  226. spi_set_format (SPI_PORT, 16, SPI_CPOL_1 , SPI_CPHA_1,SPI_MSB_FIRST );
  227. dma_channel_set_read_addr(dma_ch, string_line_buffer[buffer_selector], false);
  228. dma_channel_set_trans_count(dma_ch, TFT_WIDTH * pfn->get_max_font_height(), true);
  229. dma_in_prgress = true;
  230. // バッファ反転
  231. buffer_selector = !buffer_selector;
  232. }
  233. // フォントデータ
  234. __asm(\
  235. ".section \".rodata\" \n"
  236. ".balign 4\n"
  237. ".global _pfnfont_data\n"
  238. ".global _pfnfont_data_len\n"
  239. "_pfnfont_data:\n"
  240. ".incbin \"shnmk16u.pfn\"\n"
  241. ".set _pfnfont_data_len, . - _pfnfont_data\n"
  242. ".section \".text\"\n"
  243. );
  244. extern const uint8_t _pfnfont_data[];
  245. extern uint32_t _pfnfont_data_len;
  246. int main()
  247. {
  248. stdio_init_all();
  249. // SPI
  250. spi_init(SPI_PORT, 20*1000*1000);
  251. gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
  252. gpio_set_function(PIN_CS, GPIO_FUNC_SPI);
  253. gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
  254. gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
  255. spi_set_format (SPI_PORT, 8, SPI_CPOL_1 , SPI_CPHA_1,SPI_MSB_FIRST );
  256. // TFT Pin Init
  257. gpio_init(TFT_DC);
  258. gpio_set_dir(TFT_DC, GPIO_OUT);
  259. gpio_init(TFT_RES);
  260. gpio_set_dir(TFT_RES, GPIO_OUT);
  261. // TFT INIT
  262. sst7735_reset();
  263. sst7735_init();
  264. sst7735_clear();
  265. // 描画コールバック関数を渡してPFNFontオブジェクトを生成
  266. pfn = new PFNFont((uint8_t *)_pfnfont_data, (size_t)&_pfnfont_data_len, draw_font_in_buffer);
  267. // フォントが正しく読み込めたかチェック
  268. if (pfn->isValid()) {
  269. printf("Font loaded successfully.\n");
  270. size_t line_buffer_size = TFT_WIDTH * pfn->get_max_font_height() * TFT_BYTES_PER_PIXEL;
  271. string_line_buffer[0] = (uint8_t *)malloc(line_buffer_size);
  272. string_line_buffer[1] = (uint8_t *)malloc(line_buffer_size);
  273. // render_string()を使用する前にかならずconfigure_dma_channel()を呼ぶこと
  274. configure_dma_channel();
  275. int x = 0, y = 0;
  276. while (true) {
  277. back_color = TFT_COLOR_BLACK;
  278. font_color = TFT_COLOR_WHITE;
  279. render_string("Picoで日本語表示!", x, y);
  280. font_color = TFT_COLOR_BLUE;
  281. y += pfn->get_max_font_height();
  282. render_string("Picoで日本語表示!", x, y);
  283. font_color = TFT_COLOR_RED;
  284. y += pfn->get_max_font_height();
  285. render_string("Picoで日本語表示!", x, y);
  286. font_color = TFT_COLOR_YELLOW;
  287. y += pfn->get_max_font_height();
  288. render_string("Picoで日本語表示!", x, y);
  289. sleep_ms(500);
  290. sst7735_clear();
  291. y = 0;
  292. }
  293. }
  294. else {
  295. printf("Font loading failed.\n");
  296. delete pfn;
  297. while(true) tight_loop_contents();
  298. }
  299. return 0;
  300. }