2023年7月5日 星期三

小試一下,FSMC之於LCD(NT35510),在F103的設定(by Stm32CubeMx)

  雖然用GPIO會比較快,也可以省卻「如果你的chip不支援FSMC...」的問題

不過多學會點會比較好些,也許哪天會用到也不一定,
本篇參考以下兩個URL:這個 & 這個
NT35510的規格書在此

先上圖吧


(別忘了Back Light要On起來,沒有back light,沒有顯示)
先用read ID & color fomat測看看,如果讀出是亂碼,請到上圖的NOR/PSRAME timing for wirte access那裡改一下,有時要多點clock才會正確 (參考上面兩個URL的內文介紹如個推算,因為我是用NT35510的,所以會以第二個link為主)

程式碼如下
---------------------------------------------------
//因為是用base1 第 4區,所以base address是0x6C000000
 (即0x60000000~0x6FFFFFFF分成區,第四區起始位址即為0x6C000000,參考「STM32F103 战舰开发指南V1.1.pdf」P365)
#define FMC_ADDR_CMD  ((uint32_t) 0x6C000000)
//而A10做為C/D(或曰register select),又要往左shfit一位,故為00800
#define FMC_ADDR_DATA  ((uint32_t) 0x6C000800)
//在 MX_FSMC_Init();後,這些對應建立起來後,就可以直接用位址的方式讀寫,不必再用8080介面操作了...
void lcd_wr_cmd(volatile uint16_t cmd)
{
    cmd = cmd;
    *(uint16_t *)(FMC_ADDR_CMD) = cmd;
}
void lcd_wr_data(volatile uint16_t data)
{
     data = data;
*(uint16_t *)(FMC_ADDR_DATA) = data;
}
uint16_t lcd_rd_data(void)
{
volatile uint16_t ram; 
ram = *(uint16_t *)(FMC_ADDR_DATA);
return ram;
}
...
...
main的內容
    HAL_Init();
   MX_FSMC_Init();
   MX_USART1_UART_Init();
 //神說,要有光,於是就有了光
 HAL_GPIO_WritePin(LCD_BL_GPIO_Port,LCD_BL_Pin,GPIO_PIN_SET);
  HAL_Delay(10);
  lcd_wr_cmd(0x1100);    //Sleep out & booster on 
  HAL_Delay(10);
  lcd_wr_cmd(0x2900);   //display memory  to frame.
  HAL_Delay(10);
  //第一步,先試著讀id,如果傳回值不是80h的話,就是錯了
  lcd_wr_cmd(0x0401);
  HAL_Delay(100);
  uint16_t chip_id=0xabcd;
  chip_id=lcd_rd_data();
  
  //試著讀寫 color format,原先是8x8x8 RBG格式,如今我們為了測試,用565格式
  //0x0C00是read color mode,而0x3A00是write color mode.
  uint16_t pix_fomrat_org=0;
  lcd_wr_cmd(0x0c00);pix_fomrat_org=lcd_rd_data();
  lcd_wr_cmd(0x3A00); lcd_wr_data(0x55);
  lcd_wr_cmd(0x0c00);
  uint16_t pix_fomrat=lcd_rd_data();
   //清除資料一下 (預設尺寸是480*800)
  lcd_wr_cmd(0x2c00);; //demo how to do "clear screen"
  for(uint32_t i=0;i<(0x01df-1)*(0x03ef-1);i++){
      lcd_wr_data(0x07E0);
  }
  
  //最後,把大頭照放上去 x,y : 200,200, width& height:140x140
  lcd_wr_cmd(0x2A00);lcd_wr_data(0);;
  lcd_wr_cmd(0x2A01);lcd_wr_data(200);
  lcd_wr_cmd(0x2A02);lcd_wr_data(339>>8);
  lcd_wr_cmd(0x2A03);lcd_wr_data(339&0xff);
  
  lcd_wr_cmd(0x2B00);lcd_wr_data(0);
  lcd_wr_cmd(0x2B01);lcd_wr_data(200);
  lcd_wr_cmd(0x2B02);lcd_wr_data(339>>8);
  lcd_wr_cmd(0x2B03);lcd_wr_data(339&0xff);  
  lcd_wr_cmd(0x2c00); //demo how to do "clear screen"
  for(uint32_t i=0;i<(140*140);i++){
      lcd_wr_data(g_pexl[i]);
  }
  
 //然後就是while(1)...

---------------------------------------------------
 耶~ 有看到圖片了(會不會太自戀了?)
------




------
這次的實作基本上只是個小插曲,還是建議用GPIO直接去操作,以清除螢幕這個函數來說好了
-----------
void fill_color(uint16_t color, uint32_t count)

   //當然以下的HAL_GPIO_WritePin都可以再直接操作BSRR暫存器來最佳化之,
  //只是為了實作驗證是否了解正確,直接用HAL程式庫了
    set_d0tod7_output();
    HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_RESET);//RS:0
    HAL_GPIO_WritePin(LCD_WRITE_GPIO_Port,LCD_WRITE_Pin,GPIO_PIN_SET);//write 1
    HAL_GPIO_WritePin(LCD_READ_GPIO_Port,LCD_READ_Pin,GPIO_PIN_SET);//RD 1
    HAL_GPIO_WritePin(LCD_CS_GPIO_Port,LCD_CS_Pin,GPIO_PIN_RESET);//CS 0
    
    write_byte_to_gpio(0x2c00);
    HAL_GPIO_WritePin(LCD_WRITE_GPIO_Port,LCD_WRITE_Pin,GPIO_PIN_RESET);//write 0
    HAL_GPIO_WritePin(LCD_WRITE_GPIO_Port,LCD_WRITE_Pin,GPIO_PIN_SET);//write 1
    
    //set to data mode
    HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_SET);//RS:1
    write_byte_to_gpio(color);
    uint32_t pin16u=(uint32_t)LCD_WRITE_Pin<< 16u;
    for(uint32_t i=0;i<count;i++)
    {
         LCD_WRITE_GPIO_Port->BSRR = pin16u; //RESET
         LCD_WRITE_GPIO_Port->BSRR = LCD_WRITE_Pin;//SET
     }
    //all done
    HAL_GPIO_WritePin(LCD_CS_GPIO_Port,LCD_CS_Pin,GPIO_PIN_SET);//CS 1
    HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_SET);//RS:1
    HAL_GPIO_WritePin(LCD_READ_GPIO_Port,LCD_READ_Pin,GPIO_PIN_SET);//read 1
    HAL_GPIO_WritePin(LCD_WRITE_GPIO_Port,LCD_WRITE_Pin,GPIO_PIN_SET);//write 1
}
-----------
這比填入FSMC再填入LCD快了點(直接高低電位切換,當然快啊,這樣比很不講武德捏)
而且會看技術規格文件,是這行必備的生存技能
當然FSMC會了也是很好的一件事,畢竟很多時候可以對應到別的設備的,大大節省開發難度
要學的東西真的太多了,一起加油吧.