boot 使用的是 https://gitee.com/LicheePiNano/lv7_rtthread_f1c100s 的spl
借鉴了一个keil 工程 和 https://whycan.com/t_1457.html 的 framebuffer
其中dede 初始化的时候 设置dede->mode 就崩溃了,很奇怪 可以读寄存器,但是不能写,写完程序就奔溃了,
如果屏蔽掉了就可以运行通过,但是可以显示,屏幕分辨率可以设置,但是显示的颜色不是设置buff的颜色,而是随机的 几个颜色重复出现,感觉buff的数据没设置进去
想咨询一下 移植过framebuffer的高手,处理按步骤初始化,还需要做什么额外处理吗 例如在启动文件添加某些东西?
/*debe配置*/
void Debe_Init(struct fb_f1c100s_pdata_t * pdat){
struct f1c100s_debe_reg_t * debe = (struct f1c100s_debe_reg_t *)pdat->virtdebe;
//时钟与复位
S_BIT(CCU_BUS_CLK_GATING_REG1,12);
S_BIT(CCU_BUS_SOFT_RST_REG1,12);
//delay_ms(1);
//使能DEBE
//S_BIT((virtual_addr_t)&debe->mode,0); // 用这个方式也不能用 设置程序就挂掉
uint32_t val = read32((virtual_addr_t)&debe->mode);
val |= (1 << 0);
logout("debe->mode %d",val);
write32((virtual_addr_t)&debe->mode, val); // 用这个方式也不能用 设置程序就挂掉
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "drv_fb.h"
#include "drv_gpio.h"
#include "drv_clock.h"
#include "reg-ccu.h"
#include "reg-debe.h"
#include "reg-defe.h"
#include "reg-tcon.h"
#include "io.h"
//全局结构体
struct fb_f1c100s_pdata_t __lcd_pdat;
struct fb_f1c100s_pdata_t * lcd_pdat;
//LCD时序
struct __lcd_timing lcd_timing = {
/*模式 ----水平时序------, -----垂直时序------, -极性控制--, 串并行 CPU_MODE PCKL=(24MHz*N)/M/F [5<F<96]*/
/*MODE WIDTH,HFP,HBP,HSPW, HEIGHT,VFP,VBP,VSPW, HA,VA,DA,CA, s, 0, N, M, F, */
#ifdef LCD_TYPE_RGB43_480_272
2, 480, 8, 43, 1, 272, 4, 12, 10, 0, 0, 1, 0, 1, 0, 65, 4,40 //PCLK=9.75MHZ
#endif
#ifdef LCD_TYPE_RGB43_800_480
2, 800, 40, 87, 1, 480, 13, 31, 1, 0, 0, 1, 0, 1, 0, 65, 4,13 //PCLK=30MHZ
#endif
#ifdef LCD_TYPE_RGB80_800_600
2, 800, 40, 87, 1, 600, 13, 31, 1, 0, 0, 1, 0, 1, 0, 65, 4,13 //PCLK=30MHZ
#endif
#ifdef LCD_TYPE_RGB70_1024_600
2, 1024,160,160, 1, 600, 2, 23, 12, 0, 0, 1, 0, 1, 0, 65, 4, 13 //PCLK=48.75MHZ
#endif
};
/**
* @brief 获取视频时钟频率
* @return uint32_t
*/
inline static uint32_t get_video_pll_clk(void){
uint32_t reg;
int n, m;
reg = CCU->pll_video_ctrl;
if (!(reg & (0x01 << 31)))
return 0;
if (reg & PLL_VIDEO_MODE_SEL){
//(24MHz*n)/m
n = PLL_VIDEO_FACTOR_N(reg) + 1;
m = PLL_VIDEO_PREDIV_M(reg) + 1;
return (_24MHZ_ * n) / m;
}
if (reg & PLL_VIDEO_FRAC_CLK_OUT)
return 270000000;
else
return 297000000;
return 0;
}
/**
* @brief 等待PLL时钟开启
* @param base
* @return rt_err_t
*/
static long f1c100s_clk_wait_pll_stable(uint32_t base){
uint32_t rval = 0;
volatile int time = 0xfff;
do {
rval = read32(base);
time--;
} while (time && !(rval & (1 << 28)));
return !time;
}
/**
* @brief 启用视频时钟
* @param dev
* @param enable
*/
inline static void f1c100s_clk_pll_video_set_enable(bool enable){
rt_uint32_t val = read32(CCU->pll_video_ctrl);
if(enable) {
val |= (1 << 31);
} else {
val &= ~(1 << 31);
}
write32(CCU->pll_video_ctrl, val);
if (enable) {
f1c100s_clk_wait_pll_stable(CCU->pll_video_ctrl);
}
}
/*debe配置*/
void Debe_Init(struct fb_f1c100s_pdata_t * pdat){
struct f1c100s_debe_reg_t * debe = (struct f1c100s_debe_reg_t *)pdat->virtdebe;
//时钟与复位
S_BIT(CCU_BUS_CLK_GATING_REG1,12);
S_BIT(CCU_BUS_SOFT_RST_REG1,12);
//delay_ms(1);
//使能DEBE
//S_BIT((virtual_addr_t)&debe->mode,0); // 用这个方式也不能用 设置程序就挂掉
uint32_t val = read32((virtual_addr_t)&debe->mode);
val |= (1 << 0);
logout("debe->mode %d",val);
write32((virtual_addr_t)&debe->mode, val); // 用这个方式也不能用 设置程序就挂掉
// 背景颜色 //
write32((virtual_addr_t)&debe->backcolor, (0xef0017) );
write32((virtual_addr_t)&debe->disp_size, (((pdat->height) - 1) << 16) | (((pdat->width) - 1) << 0));
//设置层0参数
write32((virtual_addr_t)&debe->layer0_size, (((pdat->height) - 1) << 16) | (((pdat->width) - 1) << 0));
write32((virtual_addr_t)&debe->layer0_stride, ((pdat->width) << 4));//[RGB565=4][ARGB8888=5]
write32((virtual_addr_t)&debe->layer0_addr_low32b, (int32_t)(pdat->vram[0]) << 3);
write32((virtual_addr_t)&debe->layer0_addr_high4b, (int32_t)(pdat->vram[0]) >> 29);
write32((virtual_addr_t)&debe->layer0_attr1_ctrl, 0x5 << 8);//[RGB565=0x5][ARGB8888=0xA]
S_BIT((virtual_addr_t)&debe->mode,8);//层0使能
if((pdat->vram[1]!=0)&&(pdat->vram[0]!=pdat->vram[1])){
//设置层1参数
write32((virtual_addr_t)&debe->disp_size, (((pdat->height) - 1) << 16) | (((pdat->width) - 1) << 0));
write32((virtual_addr_t)&debe->layer1_size, (((pdat->height) - 1) << 16) | (((pdat->width) - 1) << 0));
write32((virtual_addr_t)&debe->layer1_stride, ((pdat->width) <<5));//[RGB565=4][ARGB8888=5]
write32((virtual_addr_t)&debe->layer1_addr_low32b, (int32_t)(pdat->vram[1]) << 3);
write32((virtual_addr_t)&debe->layer1_addr_high4b, (int32_t)(pdat->vram[1]) >> 29);
write32((virtual_addr_t)&debe->layer1_attr1_ctrl, 0x0A << 8);//[RGB565=0x5][ARGB8888=0xA]
S_BIT((virtual_addr_t)&debe->layer1_attr0_ctrl,10);//优先级
S_BIT((virtual_addr_t)&debe->layer1_attr0_ctrl,15);//1: select Pipe 1 需要透明叠加时需要输入不同管道
S_BIT((virtual_addr_t)&debe->mode,9);//层1使能
}
//加载
S_BIT((virtual_addr_t)&debe->reg_ctrl,0);
//DEBE 开始
S_BIT((virtual_addr_t)&debe->mode,1);
}
/*TCON初始化*/
void Tcon_Init(struct fb_f1c100s_pdata_t * pdat){
struct f1c100s_tcon_reg_t *tcon=((struct f1c100s_tcon_reg_t *)pdat->virttcon);
int val;
int bp, total;
/*设置VIDEO PLL时钟*/
C_BIT(CCU_Base_Address+0x010,31);
write32(CCU_Base_Address+0x010,((lcd_timing.n-1)<<8)|((lcd_timing.m-1)<<0)|(3<<24));
S_BIT(CCU_Base_Address+0x010,31);
//delay_ms(1);
/*设置TCON时钟与复位*/
S_BIT(CCU_BUS_CLK_GATING_REG1,4);
S_BIT(CCU_TCON_CLK_REG,31);
S_BIT(CCU_BUS_SOFT_RST_REG1,4);
//delay_ms(1);
/*TCON配置*/
C_BIT(TCON_Base_Address+0x40,0);
val = (lcd_timing.v_front_porch + lcd_timing.v_back_porch + lcd_timing.v_sync_len);
write32(TCON_Base_Address+0x40,(0x1 << 31) |(val & 0x1f) << 4);
//val = lcd_timing.f; // 5< DCLKDIV <96 时钟除数
val = get_video_pll_clk() / 32000000;
write32(TCON_Base_Address+0x44, (0xf << 28) | (val << 0));
/*设置宽高*/
write32((virtual_addr_t)&tcon->tcon0_timing_active, ((lcd_timing.width - 1) << 16) | ((lcd_timing.height - 1) << 0));
/*设置HT+HBP*/
bp = lcd_timing.h_sync_len + lcd_timing.h_back_porch;
total = (lcd_timing.width*lcd_timing.serial) + lcd_timing.h_front_porch + bp;
write32((virtual_addr_t)&tcon->tcon0_timing_h, ((total - 1) << 16) | ((bp - 1) << 0));
/*设置VT+VBP*/
bp = lcd_timing.v_sync_len + lcd_timing.v_back_porch;
total = lcd_timing.height + lcd_timing.v_front_porch + bp;
write32((virtual_addr_t)&tcon->tcon0_timing_v, ((total * 2) << 16) | ((bp - 1) << 0));
/*设置时钟宽度*/
write32((virtual_addr_t)&tcon->tcon0_timing_sync, ((lcd_timing.h_sync_len - 1) << 16) | ((lcd_timing.v_sync_len - 1) << 0));
/*设置RB交换-方便布线*/
#if 0
S_BIT(TCON_Base_Address+0x40,23);
#endif
/*设置模式*/
write32((virtual_addr_t)&tcon->tcon0_hv_intf, 0);
write32((virtual_addr_t)&tcon->tcon0_cpu_intf, 0);
//FRM
if(pdat->bits_per_pixel == 18 || pdat->bits_per_pixel == 16){
write32((virtual_addr_t)&tcon->tcon0_frm_seed[0], 0x11111111);
write32((virtual_addr_t)&tcon->tcon0_frm_seed[1], 0x11111111);
write32((virtual_addr_t)&tcon->tcon0_frm_seed[2], 0x11111111);
write32((virtual_addr_t)&tcon->tcon0_frm_seed[3], 0x11111111);
write32((virtual_addr_t)&tcon->tcon0_frm_seed[4], 0x11111111);
write32((virtual_addr_t)&tcon->tcon0_frm_seed[5], 0x11111111);
write32((virtual_addr_t)&tcon->tcon0_frm_table[0], 0x01010000);
write32((virtual_addr_t)&tcon->tcon0_frm_table[1], 0x15151111);
write32((virtual_addr_t)&tcon->tcon0_frm_table[2], 0x57575555);
write32((virtual_addr_t)&tcon->tcon0_frm_table[3], 0x7f7f7777);
write32((virtual_addr_t)&tcon->tcon0_frm_ctrl, (pdat->bits_per_pixel == 18) ? ((1 << 31) | (0 << 4)) : ((1 << 31) | (5 << 4)));
}
//极性控制
val = (1 << 28);
if(!lcd_timing.h_sync_active) val |= (1 << 25);
if(!lcd_timing.v_sync_active) val |= (1 << 24);
if(!lcd_timing.den_active) val |= (1 << 27);
if(!lcd_timing.clk_active) val |= (1 << 26);
write32((virtual_addr_t)&tcon->tcon0_io_polarity, val);
//触发控制关
write32((virtual_addr_t)&tcon->tcon0_io_tristate, 0);
}
/*关TCON时钟*/
void Tcon_Clk_Close(void){
C_BIT(CCU_BUS_CLK_GATING_REG1,4);
C_BIT(CCU_TCON_CLK_REG,31);
C_BIT(CCU_BUS_SOFT_RST_REG1,4);
}
/*关Debe时钟*/
void Debe_Clk_Close(void){
C_BIT(CCU_BUS_CLK_GATING_REG1,12);
C_BIT(CCU_BUS_SOFT_RST_REG1,12);
}
#define gate_clk_enable(virt, shift, invert) write32(virt, (read32(virt) & ~(0x1 << shift)) | ((invert ? 0x0 : 0x1) << shift))
#define gate_clk_disable(virt, shift, invert) write32(virt, (read32(virt) & ~(0x1 << shift)) | ((invert ? 0x1 : 0x0) << shift))
static void clk_divider_set_rate(virtual_addr_t virt, uint32_t width, uint32_t shift, bool onebased, uint64_t prate, uint64_t rate){
uint32_t mask = ((1 << (width)) - 1);
uint32_t div;
uint32_t val;
if(rate == 0)
rate = prate;
div = prate / rate;
if(onebased)
div--;
if(div > mask)
div = mask;
val = read32(virt);
val &= ~(mask << shift);
val |= div << shift;
write32(virt, val);
}
static void clk_mux_set_parent(virtual_addr_t virt, uint32_t width, uint32_t shift, uint32_t parent_val){
uint32_t val;
val = read32(virt);
val &= ~(((1 << width) - 1) << shift);
val |= parent_val << shift;
write32(virt, val);
}
/**
* @brief 开启DEFE时钟
* @param dev 设备指针
*/
inline static void f1c100s_clk_defe_enable(){
gate_clk_enable(F1C100S_CCU_BASE + CCU_DEFE_CLK, 31, false);
gate_clk_enable(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE1, 14, false);
}
/**
* @brief 开启TCON时钟
*
* @param dev 设备指针
*/
inline static void f1c100s_clk_tcon_enable(){
gate_clk_enable(F1C100S_CCU_BASE + CCU_LCD_CLK, 31, false);
gate_clk_enable(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE1, 4, false);
}
/**
* @brief 开启DEBE时钟
*
* @param dev 设备指针
*/
inline static void f1c100s_clk_debe_enable(){
gate_clk_enable(F1C100S_CCU_BASE + CCU_DEBE_CLK, 31, false);
gate_clk_enable(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE1, 12, false);
}
/**
* @brief 初始化DEBE时钟
* @param dev
*/
static void f1c100s_clk_debe_init(){
clk_mux_set_parent(F1C100S_CCU_BASE + CCU_DEBE_CLK, 3, 24, 0);
// clk_divider_set_rate(F1C100S_CCU_BASE + CCU_DEBE_CLK, 4, 0, true, 24000000, 198000000);
clk_divider_set_rate(F1C100S_CCU_BASE + CCU_DEBE_CLK, 4, 0, true, 198000000, 198000000);
}
/**
* @brief 初始化DEF时钟
* @param dev 设备指针
*/
static void f1c100s_clk_defe_init(){
// 选择时钟源为 0b011
clk_mux_set_parent(F1C100S_CCU_BASE + CCU_DEFE_CLK, 3, 24, 0);
//clk_divider_set_rate(F1C100S_CCU_BASE + CCU_DEFE_CLK, 4, 0, true, 24000000, 198000000);
clk_divider_set_rate(F1C100S_CCU_BASE + CCU_DEFE_CLK, 4, 0, true, 198000000, 198000000);
}
/*tcon使能*/
void f1c100s_tcon_enable(struct fb_f1c100s_pdata_t * pdat){
struct f1c100s_tcon_reg_t * tcon = (struct f1c100s_tcon_reg_t *)pdat->virttcon;
uint32_t val;
val = read32((virtual_addr_t)&tcon->ctrl);
val |= (1 << 31);
write32((virtual_addr_t)&tcon->ctrl, val);
}
/*tcon失能*/
void f1c100s_tcon_disable(struct fb_f1c100s_pdata_t * pdat){
struct f1c100s_tcon_reg_t * tcon = (struct f1c100s_tcon_reg_t *)pdat->virttcon;
uint32_t val;
write32((virtual_addr_t)&tcon->ctrl, 0);
write32((virtual_addr_t)&tcon->int0, 0);
val = read32((virtual_addr_t)&tcon->tcon0_dclk);
val &= ~(0xf << 28);
write32((virtual_addr_t)&tcon->tcon0_dclk, val);
write32((virtual_addr_t)&tcon->tcon0_io_tristate, 0xffffffff);
write32((virtual_addr_t)&tcon->tcon1_io_tristate, 0xffffffff);
}
/*LCD配置*/
void F1C100S_LCD_Config(int width,int height,unsigned int *buff1,unsigned int *buff2){
int i;
lcd_pdat=&__lcd_pdat;
//设置地址
lcd_pdat->virtdebe = F1C100S_DEBE_BASE;
lcd_pdat->virttcon = F1C100S_TCON_BASE;
//LCD宽高
lcd_pdat->width = width;
lcd_pdat->height = height;
//像素位宽
lcd_pdat->bits_per_pixel = 18;
//设置缓存
lcd_pdat->vram[0] = buff1;
lcd_pdat->vram[1] = buff2;
f1c100s_clk_defe_enable();
f1c100s_clk_debe_enable();
f1c100s_clk_tcon_enable();
//清寄存器
for(i = 0x0800; i < 0x1000; i += 4)
write32(F1C100S_DEBE_BASE + i, 0);
f1c100s_clk_pll_video_set_enable(true);
f1c100s_clk_debe_init();
f1c100s_clk_defe_init();
//debe+tcon配置
f1c100s_tcon_disable(lcd_pdat);
Debe_Init(lcd_pdat);
Tcon_Init(lcd_pdat);
f1c100s_tcon_enable(lcd_pdat);
}
/* LCD IO初始化 */
void LCD_IO_Init(void){
int i=0;
for(i=18;i<=21;i++)gpio_set_config(GPIO_PORT_D,GPIO_PIN_0+i,IO_FUN_1,PULL_DISABLE);
for(i=1;i<=8;i++)gpio_set_config(GPIO_PORT_D,GPIO_PIN_0+i,IO_FUN_1,PULL_DISABLE);
for(i=10;i<=17;i++)gpio_set_config(GPIO_PORT_D,GPIO_PIN_0+i,IO_FUN_1,PULL_DISABLE);
}
/* LCD初始化 */
void F1C100S_LCD_Init(int width,int height,unsigned int *buff1,unsigned int *buff2){
// 多次初始化时要先关时钟
Tcon_Clk_Close();
Debe_Clk_Close();
LCD_IO_Init(); //IO初始化
F1C100S_LCD_Config(width,height,buff1,buff2);//TCON DEBE 初始化
}
最近编辑记录 tangloong (2023-11-12 13:32:54)
离线
额 话说 这就是我的gitee,里面的boot不完善,现在优化他 发现拷贝1.5M左右的应用需要3s的时间,SPI的频率调整50M还是100M感觉没区别,也不知道为什么uboot 下LINUX系统100多M 做么就10来秒就启动了,
现在想在BOOT显示图片 这样给人感觉系统里面就工作起来了
离线
dede->mode 不能使能 是还有什么其他地方需要配置么?
离线
debe 不能使能 是不是因为内存没有分配的原因呢?
离线