LoginSignup
6
5

More than 5 years have passed since last update.

STM32のFSMCにLCDを接続する

Last updated at Posted at 2016-10-21

STM32のFSMC(flexible static memory controller)にLCDを接続する方法を調べました。

FSMCというのはSTM32の外部にSRAMやFLASHを接続するための機能です。FSMCを使ってパラレル接続のLCDを接続することができます。

この件については過去にいろんな人がいろんな記事を書いていますが、自分の理解のためにまとめてみます。

ターゲットのMCUはSTM32F103VCT6です。

officialの情報

STM32F103VCT6 のFSMC

  • STM32F103VCT6はLQFP100のパッケージでピンが足りないのでFSMCの信号が部分的にしか外ピンに出ていません。
  • LQFP100で外ピンに出ているFSMCの信号
    • D0-D15, A16-A23, CLK, NOE, NWE, NWAIT, NE1, NADV, NBL0, NBL1
    • D0-D15はデータ、A16-A23はアドレス、NOEは負論理の出力イネーブル、NWEは負論理の書込みイネーブル、NE1はBANK1のチップセレクト
    • CLK, NADV, NBL0, NBL1 はLCD接続する場合は使わない。

FSMCの設定

  • AN2790 のサンプルコード STM32016 のソースコードで行っている設定

  • FSMCタイミング設定 (バンク1のFSMC_BTR1レジスタ)

フィールド名 設定値 説明
ACCMOD 0x1 (アクセスモードB) アクセスモード
DATLAT 0x0 (非同期SRAMの場合 don't care) データ待ち時間 
CLKDIV 0x0 (非同期SRAMの場合 don't care) クロック分周比
BUSTURN 0x0 (1 × HCLK 周期) バスターンアラウンドフェーズ時間
DATAST 0x5 (6 × HCLK 周期) データフェーズ時間
ADDHLD 0x0 (1 × HCLK 周期) アドレスホールドフェーズ時間
ADDSET 0x1 (2 × HCLK 周期) アドレスセットアップフェーズ時間
  • SRAM/NOR 型フラッシュチップセレクト制御レジスタ設定 (バンク1のFSMC_BCR1レジスタ)
フィールド名 設定値 説明
CBURSTRW 0x0 (無効) 書き込みバーストイネーブル
ASYNCWAIT 0x0 (考慮しない) 非同期転送時のウェイト信号
EXTMOD 0x0 (無効) 拡張モードイネーブル
WAITEN 0x0 (無効) ウェイトイネーブルビット
WREN 0x1 (有効) 書き込みイネーブルビット
WAITCFG 0x0 (ウェイトステートの 1 データサイクル前にアクティブ) ウェイトタイミング設定
WRAPMOD 0x0 (無効) ラップドバーストモードサポート
WAITPOL 0x0 (アクティブlow) ウェイト信号極性ビット
BURSTEN 0x0 (無効) バーストイネーブルビット
FACCEN 0x0 (無効) フラッシュアクセスイネーブル
MWID 0x1 (16ビット) メモリデータバス幅
MTYP 0x0 (SRAM) メモリタイプ
MUXEN 0x0 (多重化しない) アドレス / データ多重化イネーブルビット 多重化しない
MBKEN 0x1 (有効) メモリバンクイネーブルビット 有効

LCDとの接続

LCD FSMC STM32F103VCT6
RESET - 60 PD12
RS A16 58 PD11
CS NE1 88 PD7
RD NOE 85 PD4
WR NWE 86 PD5
D0 D0 61 PD14
D1 D1 62 PD15
D2 D2 81 PD0
D3 D3 82 PD1
D4 D4 38 PE7
D5 D5 39 PE8
D6 D6 40 PE9
D7 D7 41 PE10
D8 D8 42 PE11
D9 D9 43 PE12
D10 D10 44 PE13
D11 D11 45 PE14
D12 D12 46 PE15
D13 D13 55 PD8
D14 D14 56 PD9
D15 D15 57 PD10

FSMCの初期設定例

  • STM32F103 で libopencm3 をライブラリとして使った場合のFSMC初期設定例
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/fsmc.h>

static void fsmc_setup(void)
{
  /* Enable PORTD and PORTE */
  rcc_periph_clock_enable(RCC_GPIOD);
  rcc_periph_clock_enable(RCC_GPIOE);

  /* Enable FSMC */
  rcc_periph_clock_enable(RCC_FSMC);

  /* config FSMC data lines */
  uint16_t portd_gpios = GPIO0 | GPIO1 | GPIO8 | GPIO9 |
                         GPIO10 | GPIO14 | GPIO15;
  gpio_set_mode(GPIOD, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, portd_gpios);

  uint16_t porte_gpios = GPIO7 | GPIO8 | GPIO9 | GPIO10 | 
                         GPIO11 | GPIO12 | GPIO13 | GPIO14 |
                         GPIO15;
  gpio_set_mode(GPIOE, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, porte_gpios);


  /* config FSMC NOE */
  gpio_set_mode(GPIOD, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);

  /* config FSMC NWE */
  gpio_set_mode(GPIOD, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO5);

  /* config FSMC NE1 */
  gpio_set_mode(GPIOD, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO7);

  /* config FSMC A16 for D/C (select Data / Command ) */
  gpio_set_mode(GPIOD, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO11);

  /* config FSMC register */
  FSMC_BTR(0) = FSMC_BTR_ACCMODx(FSMC_BTx_ACCMOD_B) |
                FSMC_BTR_DATLATx(0)  |
                FSMC_BTR_CLKDIVx(0)  |
                FSMC_BTR_BUSTURNx(0) |
                FSMC_BTR_DATASTx(5)  |
                FSMC_BTR_ADDHLDx(0)  |
                FSMC_BTR_ADDSETx(1);

  FSMC_BCR(0) = FSMC_BCR_WREN | FSMC_BCR_MWID | FSMC_BCR_MBKEN;
}

LCDコントローラへのアクセス

  • LCDアクセス用構造体
    • 上記の接続でRSピンの出力が0と1になるように構造体LCDを0x6001FFFEに配置する。
    • LCD->LCD_REG でアクセスするとA16が0になる。(アドレス 0x6001FFFE)
    • LCD->LCD_RAM でアクセスするとA16が1になる。(アドレス 0x60020000)
/* Private typedef -----------------------------------------------------------*/
typedef struct
{
  __IO uint16_t LCD_REG;
  __IO uint16_t LCD_RAM;
} LCD_TypeDef;

#define LCD_BASE    ((uint32_t)(0x60000000 | 0x00020000 -2 ) )
#define LCD         ((LCD_TypeDef *) LCD_BASE)
  • レジスタの読み出し
uint16_t LCD_ReadReg(uint8_t LCD_Reg)
{
  /* Write 16-bit Index (then Read Reg) */
  LCD->LCD_REG = LCD_Reg;
  /* Read 16-bit Reg */
  return (LCD->LCD_RAM);
}
  • レジスタへの書込み
void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
  /* Write 16-bit Index, then Write Reg */
  LCD->LCD_REG = LCD_Reg;
  /* Write 16-bit Reg */
  LCD->LCD_RAM = LCD_RegValue;
}
  • RAMの読み出し
    • RAMの読み出しは、コマンドが必要なので、使用するコントローラ毎に異なる。
uint16_t LCD_ReadRAM(void)
{
  /* Write 16-bit Index (then Read Reg) */
  LCD->LCD_REG = R34 /* Select GRAM Reg */
  /* Read 16-bit Reg */
  return LCD->LCD_RAM;
}
  • RAMへの書込み
void LCD_WriteRAM(uint16_t RGB_Code)
{
  /* Write 16-bit GRAM Reg */
  LCD->LCD_RAM = RGB_Code;
}

参考

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5