您尚未登录。

楼主 # 2023-11-12 13:27:18

tangloong
会员
注册时间: 2023-04-11
已发帖子: 212
积分: 191

咨询: F1C100S rtt boot 移植fb 显示logo dede->mode 设置程序就崩溃了

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)

离线

楼主 #2 2023-11-12 18:43:12

tangloong
会员
注册时间: 2023-04-11
已发帖子: 212
积分: 191

Re: 咨询: F1C100S rtt boot 移植fb 显示logo dede->mode 设置程序就崩溃了

额  话说 这就是我的gitee,里面的boot不完善,现在优化他 发现拷贝1.5M左右的应用需要3s的时间,SPI的频率调整50M还是100M感觉没区别,也不知道为什么uboot 下LINUX系统100多M 做么就10来秒就启动了,

现在想在BOOT显示图片 这样给人感觉系统里面就工作起来了

离线

楼主 #3 2023-11-12 19:46:18

tangloong
会员
注册时间: 2023-04-11
已发帖子: 212
积分: 191

Re: 咨询: F1C100S rtt boot 移植fb 显示logo dede->mode 设置程序就崩溃了

dede->mode 不能使能  是还有什么其他地方需要配置么?

离线

楼主 #4 2023-11-12 19:52:57

tangloong
会员
注册时间: 2023-04-11
已发帖子: 212
积分: 191

Re: 咨询: F1C100S rtt boot 移植fb 显示logo dede->mode 设置程序就崩溃了

debe 不能使能   是不是因为内存没有分配的原因呢?

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn