1.8 インチ TFT LCD シールド (3)
STmicroelectronics の STM32Cube では、MCU のファミリ別に HAL ライブラリが構成されています。
その中で F0 / F1 / F3 / F4 シリーズのライブラリしかダウンロードしていないのですが、いずれのライブラリにも Adafruit 1.8 インチ TFT LCD シールド用の BSP (Board Support Package) が含まれています。
各 HAL ライブラリは、STM32CubeMX アプリケーションの
Help / Updater Settings... / Repository Folder
で指定する「リポジトリ」のフォルダの下に格納されます。
STM32CubeF4 の V1.16.0 の場合を例に取ると、リポジトリ・フォルダの下に「STM32Cube_FW_F4_V1.16.0」というフォルダが作成され、その中に F4 用の HAL ライブラリが収められます。
その中から LCD に関係するソース・ファイルを抜き出すと下のようになります。
\Drivers\BSP\Adafruit_Shield\stm32_adafruit_lcd.c \Drivers\BSP\Adafruit_Shield\stm32_adafruit_lcd.h \Drivers\BSP\Components\Common\lcd.h \Drivers\BSP\Components\st7735\st7735.c \Drivers\BSP\Components\st7735\st7735.h \Drivers\BSP\STM32F4xx-Nucleo\stm32f4xx_nucleo.h \Drivers\BSP\STM32F4xx-Nucleo\stm32f4xx_nucleo.c
この中で、「stm32_adafruit_lcd.c / .h」が最も上位、つまりアプリケーションに最も近いレベルのレイヤーで、2D グラフィクスの「プリミティブ」として、下に示すような「BSP_LCD_」というプリフィクスで始まる関数が用意されています。
uint8_t BSP_LCD_Init(void); uint32_t BSP_LCD_GetXSize(void); uint32_t BSP_LCD_GetYSize(void); uint16_t BSP_LCD_GetTextColor(void); uint16_t BSP_LCD_GetBackColor(void); void BSP_LCD_SetTextColor(__IO uint16_t Color); void BSP_LCD_SetBackColor(__IO uint16_t Color); void BSP_LCD_SetFont(sFONT *fonts); sFONT *BSP_LCD_GetFont(void); void BSP_LCD_Clear(uint16_t Color); void BSP_LCD_ClearStringLine(uint16_t Line); void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode); void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code); void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pBmp); void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); void BSP_LCD_DisplayOff(void); void BSP_LCD_DisplayOn(void);
フレーム・バッファからの読み出しを必須とはしていないので、多角形の輪郭線を描いて「内部」の点を指定し「塗りつぶす」ような使い方はできません。
「FillPolygon」関数は用意されていますが、描画の段階で多角形を 3 角形に分割し、塗りつぶされた 3 角形を描くことにより塗りつぶされた多角形を実現しています。
「stm32_adafruit_lcd.c」の中では、「グラフィクス・コントローラ・ドライバ」との結合は、下のような「関数へのポインタ」をメンバとする構造体を利用して行なっています。
typedef struct { void (*Init)(void); uint16_t (*ReadID)(void); void (*DisplayOn)(void); void (*DisplayOff)(void); void (*SetCursor)(uint16_t, uint16_t); void (*WritePixel)(uint16_t, uint16_t, uint16_t); uint16_t (*ReadPixel)(uint16_t, uint16_t); /* Optimized operation */ void (*SetDisplayWindow)(uint16_t, uint16_t, uint16_t, uint16_t); void (*DrawHLine)(uint16_t, uint16_t, uint16_t, uint16_t); void (*DrawVLine)(uint16_t, uint16_t, uint16_t, uint16_t); uint16_t (*GetLcdPixelWidth)(void); uint16_t (*GetLcdPixelHeight)(void); void (*DrawBitmap)(uint16_t, uint16_t, uint8_t*); void (*DrawRGBImage)(uint16_t, uint16_t, uint16_t, uint16_t, uint8_t*); } LCD_DrvTypeDef;
「stm32_adafruit_lcd.c」(および「st7735.h」) の中では、下に示すように外部シンボルとして「st7735_drv」を定義しており、「stm32_adafruit_lcd.c」のコンパイル時点では「st7735_drv」は「未定義」のまま処理されます。
「st7735_drv」は ST7735 ドライバである「st7735.c」の中で定義されており、最終的なリンクの時点で未定義参照が解決されます。
/* in "st7735.h" */ extern LCD_DrvTypeDef st7735_drv; /* in "stm32_adafruit_lcd.c" */ static LCD_DrvTypeDef *lcd_drv; uint8_t BSP_LCD_Init(void) { . . . . . <中略> . . . . . lcd_drv = &st7735_drv; /* LCD Init */ lcd_drv->Init(); /* Clear the LCD screen */ BSP_LCD_Clear(LCD_COLOR_WHITE); /* Initialize the font */ BSP_LCD_SetFont(&LCD_DEFAULT_FONT); . . . . . <中略> . . . . . }
LCD コントローラ・ドライバである「st7735.c」では、実際に LCD コントローラ・チップの st7735 へのコマンド/データ書き込みが必要ですが、「st7735.h」では下のように「LCD_IO_」プリフィクスから始まる関数を外部参照しており、「st7735.c」の内部では定義していません。
/* LCD IO functions */ void LCD_IO_Init(void); void LCD_IO_WriteMultipleData(uint8_t *pData, uint32_t Size); void LCD_IO_WriteReg(uint8_t Reg);
この「LCD_IO_」プリフィクスを持つ関数は、各ボード固有の BSP 内で記述されており、Nucleo-F411RE の場合は、「stm32f4xx_nucleo.c」の中にあります。
したがって、ST7735 と MCU インターフェース仕様やコントローラ・コマンド体系が異なる LCD コントローラを利用するには、少なくとも
が必要になります。
「stm32_adafruit_lcd.c」は上位のレイヤーなので、本来は変更の必要がないはずですが、下に示す 1 ヵ所だけ ST7735 依存の箇所があるので、そこだけは修正する必要があります。
/* Remap Ypos, st7735 works with inverted X in case of bitmap */ /* X = 0, cursor is on Top corner */ if(lcd_drv == &st7735_drv) { Ypos = BSP_LCD_GetYSize() - Ypos - height; }