【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第四篇 嵌入式Linux系统移植篇-第七十二章 内核配置屏幕驱动

news2024/11/15 4:29:58

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、

【公众号】迅为电子

【粉丝群】258811263


第七十二章 内核配置屏幕驱动

屏幕驱动是非常重要的一部分,本章节我们将学习如何在上个章节的基础上配置屏幕驱动。

72.1修改屏幕驱动

i.MX8M Mini 处理器的 MIPI_DSI 最高分辨率可达 WQHD1920x1080p60,24bpp),支持 123 4 个数据通道。 i.MX8MM 4 通道的 MIPI_DSI 通过 30pin 0.5mm 间距的 FPC 座引出(J9)。可连接迅为的 7 寸 mipi 显示屏。或者通过连接mipi转lvds转接板,然后再连接7寸lvds 屏,9.7寸lvds屏,10.1寸lvds屏。

NXP官方写好了mipi_dsi的节点,如下图所示:

/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/fsl-imx8mm.dtsi文件的mipi_dsi节点,如下图所示:

由上图的compatible = "fsl,imx8mm-mipi-dsim"; 可以查找到匹配的驱动文件为/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/drivers/gpu/drm/imx/sec_mipi_dsim-imx.c文件。修改此文件,如下图所示:

#include "sec_mipi_pll_1432x.h"

 

static const struct sec_mipi_dsim_plat_data imx8mm_mipi_dsim_plat_data = {
	.version	= 0x1060200,
	.max_data_lanes = 4,
	.max_data_rate  = 1500000000ULL,
	.dphy_pll       = &pll_1432x,
	.dphy_timing	= dphy_timing_ln14lpp_v1p2,
	.num_dphy_timing = ARRAY_SIZE(dphy_timing_ln14lpp_v1p2),
	.dphy_timing_cmp = dphy_timing_default_cmp,
	.mode_valid	= NULL,
};

 

然后将网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\3.Linux系统移植\8.移植内核需要用到的文件\01 适配屏幕需要使用的文件”目录下的sec_mipi_pll_1432x.h文件拷贝到/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/drivers/gpu/drm/imx/目录下。

修改/home/topeet/imx8mm/linux/linux/linux-imx/drivers/gpu/drm/bridge/sec-dsim.c文件,修改如下内容:

添加如下内容:

#define MIPI_HFP_PKT_OVERHEAD   6

#define MIPI_HBP_PKT_OVERHEAD   6

#define MIPI_HSA_PKT_OVERHEAD   6

添加如下内容:

uint32_t pref_clk;

 

 添加如下内容:

#if 1	//add by cym 20201127
static int sec_mipi_dsim_set_pref_rate(struct sec_mipi_dsim *dsim)
{
        int ret;
        uint32_t rate;
        struct device *dev = dsim->dev;
        const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
        const struct sec_mipi_dsim_pll *dpll = pdata->dphy_pll;
        const struct sec_mipi_dsim_range *fin_range = &dpll->fin;

        ret = of_property_read_u32(dev->of_node, "pref-rate", &rate);
        if (ret < 0) {
                dev_dbg(dev, "no valid rate assigned for pref clock\n");
                dsim->pref_clk = PHY_REF_CLK;
        } else {
                if (unlikely(rate < fin_range->min || rate > fin_range->max)) {
                        dev_warn(dev, "pref-rate get is invalid: %uKHz\n",
                                 rate);
                        dsim->pref_clk = PHY_REF_CLK;
                } else
                        dsim->pref_clk = rate;
        }

set_rate:
        ret = clk_set_rate(dsim->clk_pllref,
                           ((unsigned long)dsim->pref_clk) * 1000);
        if (ret) {
                dev_err(dev, "failed to set pll ref clock rate\n");
                return ret;
        }

        rate = clk_get_rate(dsim->clk_pllref) / 1000;
        if (unlikely(!rate)) {
                dev_err(dev, "failed to get pll ref clock rate\n");
                return -EINVAL;
        }

        if (rate != dsim->pref_clk) {
                if (unlikely(dsim->pref_clk == PHY_REF_CLK)) {
                        /* set default rate failed */
                        dev_err(dev, "no valid pll ref clock rate\n");
                        return -EINVAL;
                }

                dev_warn(dev, "invalid assigned rate for pref: %uKHz\n",
                         dsim->pref_clk);
                dev_warn(dev, "use default pref rate instead: %uKHz\n",
                         PHY_REF_CLK);

                dsim->pref_clk = PHY_REF_CLK;
                goto set_rate;
        }

        return 0;
}
#endif

注释掉如下内容:

//escmode |= ESCMODE_FORCEBTA;

 

修改如下红字的部分,修改为如下图所示: 

static void sec_mipi_dsim_set_main_mode(struct sec_mipi_dsim *dsim)
{
	uint32_t bpp, hfp_wc, hbp_wc, hsa_wc, wc;
	uint32_t mdresol = 0, mvporch = 0, mhporch = 0, msync = 0;
	struct videomode *vmode = &dsim->vmode;

	mdresol |= MDRESOL_SET_MAINVRESOL(vmode->vactive) |
		   MDRESOL_SET_MAINHRESOL(vmode->hactive);
	dsim_write(dsim, mdresol, DSIM_MDRESOL);

	mvporch |= MVPORCH_SET_MAINVBP(vmode->vback_porch)    |
		   MVPORCH_SET_STABLEVFP(vmode->vfront_porch) |
		   MVPORCH_SET_CMDALLOW(0x0);
	dsim_write(dsim, mvporch, DSIM_MVPORCH);

	bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);

	/* calculate hfp & hbp word counts */
#if 0
	if (dsim->panel || !dsim->hpar) {
		hfp_wc = vmode->hfront_porch * (bpp >> 3);
		hbp_wc = vmode->hback_porch * (bpp >> 3);
	} else {
		hfp_wc = dsim->hpar->hfp_wc;
		hbp_wc = dsim->hpar->hbp_wc;
	}
#else
	if (!dsim->hpar) {
                wc = DIV_ROUND_UP(vmode->hfront_porch * (bpp >> 3),
                                  dsim->lanes);
                hfp_wc = wc > MIPI_HFP_PKT_OVERHEAD ?
                         wc - MIPI_HFP_PKT_OVERHEAD : vmode->hfront_porch;
                wc = DIV_ROUND_UP(vmode->hback_porch * (bpp >> 3),
                                  dsim->lanes);
                hbp_wc = wc > MIPI_HBP_PKT_OVERHEAD ?
                         wc - MIPI_HBP_PKT_OVERHEAD : vmode->hback_porch;
        } else {
                hfp_wc = dsim->hpar->hfp_wc;
                hbp_wc = dsim->hpar->hbp_wc;
        }
#endif

	mhporch |= MHPORCH_SET_MAINHFP(hfp_wc) |
		   MHPORCH_SET_MAINHBP(hbp_wc);

	dsim_write(dsim, mhporch, DSIM_MHPORCH);

	/* calculate hsa word counts */
#if 0
	if (dsim->panel || !dsim->hpar)
		hsa_wc = vmode->hsync_len * (bpp >> 3);
	else
		hsa_wc = dsim->hpar->hsa_wc;

	msync |= MSYNC_SET_MAINVSA(vmode->vsync_len) |
		 MSYNC_SET_MAINHSA(hsa_wc);
#else
	if (!dsim->hpar) {
                wc = DIV_ROUND_UP(vmode->hsync_len * (bpp >> 3),
                                  dsim->lanes);
                hsa_wc = wc > MIPI_HSA_PKT_OVERHEAD ?
                         wc - MIPI_HSA_PKT_OVERHEAD : vmode->hsync_len;
        } else
                hsa_wc = dsim->hpar->hsa_wc;

	msync |= MSYNC_SET_MAINVSA(vmode->vsync_len) |
                 MSYNC_SET_MAINHSA(hsa_wc);
#endif

	dsim_write(dsim, msync, DSIM_MSYNC);
}

修改如下图所示内容:

//esc_prescaler = DIV_ROUND_UP_ULL(byte_clk, MAX_ESC_CLK_FREQ);

esc_prescaler = DIV_ROUND_UP(byte_clk, MAX_ESC_CLK_FREQ);

 添加如下内容,如下图所示:

#if 1
struct dsim_pll_pms *sec_mipi_dsim_calc_pmsk(struct sec_mipi_dsim *dsim)
{
        uint32_t p, m, s;
        uint32_t best_p = 0, best_m = 0, best_s = 0;
        uint32_t fin, fout;
        uint32_t s_pow_2, raw_s;
        uint64_t mfin, pfvco, pfout, psfout;
        uint32_t delta, best_delta = ~0U;
        struct dsim_pll_pms *pll_pms;
        struct device *dev = dsim->dev;
        const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
        struct sec_mipi_dsim_pll dpll = *pdata->dphy_pll;

        struct sec_mipi_dsim_range *prange = &dpll.p;
        struct sec_mipi_dsim_range *mrange = &dpll.m;
        struct sec_mipi_dsim_range *srange = &dpll.s;
        struct sec_mipi_dsim_range *krange = &dpll.k;
        struct sec_mipi_dsim_range *fvco_range  = &dpll.fvco;
        struct sec_mipi_dsim_range *fpref_range = &dpll.fpref;
        struct sec_mipi_dsim_range pr_new = *prange;
        struct sec_mipi_dsim_range sr_new = *srange;

        pll_pms = devm_kzalloc(dev, sizeof(*pll_pms), GFP_KERNEL);
        if (!pll_pms) {
                dev_err(dev, "Unable to allocate 'pll_pms'\n");
                return ERR_PTR(-ENOMEM);
        }

        fout = dsim->bit_clk;
        fin  = dsim->pref_clk;

        /* TODO: ignore 'k' for PMS calculation,
         * only use 'p', 'm' and 's' to generate
         * the requested PLL output clock.
         */
        krange->min = 0;
        krange->max = 0;

        /* narrow 'p' range via 'Fpref' limitation:
         * Fpref : [2MHz ~ 30MHz] (Fpref = Fin / p)
         */
        prange->min = max(prange->min, DIV_ROUND_UP(fin, fpref_range->max));
        prange->max = min(prange->max, fin / fpref_range->min);

        /* narrow 'm' range via 'Fvco' limitation:
         * Fvco: [1050MHz ~ 2100MHz] (Fvco = ((m + k / 65536) * Fin) / p)
         * So, m = Fvco * p / Fin and Fvco > Fin;
         */
        pfvco = (uint64_t)fvco_range->min * prange->min;
        mrange->min = max_t(uint32_t, mrange->min,
                            DIV_ROUND_UP_ULL(pfvco, fin));
        pfvco = (uint64_t)fvco_range->max * prange->max;
        mrange->max = min_t(uint32_t, mrange->max,
                            DIV_ROUND_UP_ULL(pfvco, fin));

        dev_dbg(dev, "p: min = %u, max = %u, "
                     "m: min = %u, max = %u, "
                     "s: min = %u, max = %u\n",
                prange->min, prange->max, mrange->min,
                mrange->max, srange->min, srange->max);

        /* first determine 'm', then can determine 'p', last determine 's' */
        for (m = mrange->min; m <= mrange->max; m++) {
                /* p = m * Fin / Fvco */
                mfin = (uint64_t)m * fin;
                pr_new.min = max_t(uint32_t, prange->min,
                                   DIV_ROUND_UP_ULL(mfin, fvco_range->max));
                pr_new.max = min_t(uint32_t, prange->max,
                                   (mfin / fvco_range->min));

                if (pr_new.max < pr_new.min || pr_new.min < prange->min)
                        continue;

                for (p = pr_new.min; p <= pr_new.max; p++) {
                        /* s = order_pow_of_two((m * Fin) / (p * Fout)) */
                        pfout = (uint64_t)p * fout;
                        raw_s = DIV_ROUND_CLOSEST_ULL(mfin, pfout);

                        s_pow_2 = rounddown_pow_of_two(raw_s);
                        sr_new.min = max_t(uint32_t, srange->min,
                                           order_base_2(s_pow_2));

                        s_pow_2 = roundup_pow_of_two(DIV_ROUND_CLOSEST_ULL(mfin, pfout));
                        sr_new.max = min_t(uint32_t, srange->max,
                                           order_base_2(s_pow_2));

                        if (sr_new.max < sr_new.min || sr_new.min < srange->min)
                                continue;

                        for (s = sr_new.min; s <= sr_new.max; s++) {
                                /* fout = m * Fin / (p * 2^s) */
                                psfout = pfout * (1 << s);
                                delta = abs(psfout - mfin);
                                if (delta < best_delta) {
                                        best_p = p;
                                        best_m = m;
                                        best_s = s;
                                        best_delta = delta;
                                }
                        }
                }
        }

        if (best_delta == ~0U) {
                devm_kfree(dev, pll_pms);
                return ERR_PTR(-EINVAL);
        }

        pll_pms->p = best_p;
        pll_pms->m = best_m;
        pll_pms->s = best_s;

        dev_dbg(dev, "fout = %u, fin = %u, m = %u, "
                     "p = %u, s = %u, best_delta = %u\n",
                fout, fin, pll_pms->m, pll_pms->p, pll_pms->s, best_delta);

        return pll_pms;
}
#endif

 

修改如下所示内容。红色部分是修改过的。 

int sec_mipi_dsim_check_pll_out(void *driver_private,
				const struct drm_display_mode *mode)
{
	int bpp;
	uint64_t pix_clk, bit_clk, ref_clk;
	struct sec_mipi_dsim *dsim = driver_private;
	const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
	const struct dsim_hblank_par *hpar;
	const struct dsim_pll_pms *pmsk;

	bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
	if (bpp < 0)
		return -EINVAL;
#if 0
	pix_clk = mode->clock * 1000;
	bit_clk = DIV_ROUND_UP_ULL(pix_clk * bpp, dsim->lanes);

	if (bit_clk > pdata->max_data_rate) {
		dev_err(dsim->dev,
			"reuest bit clk freq exceeds lane's maximum value\n");
		return -EINVAL;
	}

	dsim->pix_clk = DIV_ROUND_UP_ULL(pix_clk, 1000);
	dsim->bit_clk = DIV_ROUND_UP_ULL(bit_clk, 1000);

	dsim->pms = 0x4210;
	dsim->hpar = NULL;
	if (dsim->panel)
		return 0;
#else
	pix_clk = mode->clock;
        bit_clk = DIV_ROUND_UP(pix_clk * bpp, dsim->lanes);

        if (bit_clk * 1000 > pdata->max_data_rate) {
                dev_err(dsim->dev,
                        "reuest bit clk freq exceeds lane's maximum value\n");
                return -EINVAL;
        }

        dsim->pix_clk = pix_clk;
        dsim->bit_clk = bit_clk;
        dsim->hpar = NULL;

        pmsk = sec_mipi_dsim_calc_pmsk(dsim);
        if (IS_ERR(pmsk)) {
                dev_err(dsim->dev,
                        "failed to get pmsk for: fin = %u, fout = %u\n",
                        dsim->pref_clk, dsim->bit_clk);
                return -EINVAL;
        }

        dsim->pms = PLLCTRL_SET_P(pmsk->p) |
                    PLLCTRL_SET_M(pmsk->m) |
                    PLLCTRL_SET_S(pmsk->s);

        /* free 'dsim_pll_pms' structure data which is
         * allocated in 'sec_mipi_dsim_calc_pmsk()'.
         */
        devm_kfree(dsim->dev, (void *)pmsk);
#endif

#if 0
	if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
		hpar = sec_mipi_dsim_get_hblank_par(mode->name,
						    mode->vrefresh,
						    dsim->lanes);
		if (!hpar)
			return -EINVAL;
		dsim->hpar = hpar;

		pms = sec_mipi_dsim_get_pms(dsim->bit_clk);
		if (WARN_ON(!pms))
			return -EINVAL;

		ref_clk = PHY_REF_CLK / 1000;
		/* TODO: add PMS calculate and check
		 * Only support '1080p@60Hz' for now,
		 * add other modes support later
		 */
		dsim->pms = PLLCTRL_SET_P(pms->p) |
			    PLLCTRL_SET_M(pms->m) |
			    PLLCTRL_SET_S(pms->s);
	}
#else
	if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
                hpar = sec_mipi_dsim_get_hblank_par(mode->name,
                                                    mode->vrefresh,
                                                    dsim->lanes);
                dsim->hpar = hpar;
                if (!hpar)
                        dev_dbg(dsim->dev, "no pre-exist hpar can be used\n");
        }
#endif

	return 0;
}

修改为如下图所示,红色部分是修改过的内容。

static void sec_mipi_dsim_set_main_mode(struct sec_mipi_dsim *dsim)
{
	uint32_t bpp, hfp_wc, hbp_wc, hsa_wc, wc;
	uint32_t mdresol = 0, mvporch = 0, mhporch = 0, msync = 0;
	struct videomode *vmode = &dsim->vmode;

	mdresol |= MDRESOL_SET_MAINVRESOL(vmode->vactive) |
		   MDRESOL_SET_MAINHRESOL(vmode->hactive);
	dsim_write(dsim, mdresol, DSIM_MDRESOL);

	mvporch |= MVPORCH_SET_MAINVBP(vmode->vback_porch)    |
		   MVPORCH_SET_STABLEVFP(vmode->vfront_porch) |
		   MVPORCH_SET_CMDALLOW(0x0);
	dsim_write(dsim, mvporch, DSIM_MVPORCH);

	bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);

	/* calculate hfp & hbp word counts */
#if 0
	if (dsim->panel || !dsim->hpar) {
		hfp_wc = vmode->hfront_porch * (bpp >> 3);
		hbp_wc = vmode->hback_porch * (bpp >> 3);
	} else {
		hfp_wc = dsim->hpar->hfp_wc;
		hbp_wc = dsim->hpar->hbp_wc;
	}
#else
	if (!dsim->hpar) {
                wc = DIV_ROUND_UP(vmode->hfront_porch * (bpp >> 3),
                                  dsim->lanes);
                hfp_wc = wc > MIPI_HFP_PKT_OVERHEAD ?
                         wc - MIPI_HFP_PKT_OVERHEAD : vmode->hfront_porch;
                wc = DIV_ROUND_UP(vmode->hback_porch * (bpp >> 3),
                                  dsim->lanes);
                hbp_wc = wc > MIPI_HBP_PKT_OVERHEAD ?
                         wc - MIPI_HBP_PKT_OVERHEAD : vmode->hback_porch;
        } else {
                hfp_wc = dsim->hpar->hfp_wc;
                hbp_wc = dsim->hpar->hbp_wc;
        }
#endif

	mhporch |= MHPORCH_SET_MAINHFP(hfp_wc) |
		   MHPORCH_SET_MAINHBP(hbp_wc);

	dsim_write(dsim, mhporch, DSIM_MHPORCH);

	/* calculate hsa word counts */
#if 0
	if (dsim->panel || !dsim->hpar)
		hsa_wc = vmode->hsync_len * (bpp >> 3);
	else
		hsa_wc = dsim->hpar->hsa_wc;

	msync |= MSYNC_SET_MAINVSA(vmode->vsync_len) |
		 MSYNC_SET_MAINHSA(hsa_wc);
#else
	if (!dsim->hpar) {
                wc = DIV_ROUND_UP(vmode->hsync_len * (bpp >> 3),
                                  dsim->lanes);
                hsa_wc = wc > MIPI_HSA_PKT_OVERHEAD ?
                         wc - MIPI_HSA_PKT_OVERHEAD : vmode->hsync_len;
        } else
                hsa_wc = dsim->hpar->hsa_wc;

	msync |= MSYNC_SET_MAINVSA(vmode->vsync_len) |
                 MSYNC_SET_MAINHSA(hsa_wc);
#endif

	dsim_write(dsim, msync, DSIM_MSYNC);
}

添加如下内容:

#if 0
	{
		//cym
#if 0
		dsim_write(dsim, 0x91f80002, DSIM_CLKCTRL);
		dsim_write(dsim, 0x82570400, DSIM_MDRESOL);
		dsim_write(dsim, 0x20018, DSIM_MVPORCH);
		dsim_write(dsim, 0xc0072, DSIM_MHPORCH);
		dsim_write(dsim, 0xc00051, DSIM_MSYNC);
		dsim_write(dsim, 0x7ac7bfff, DSIM_RXFIFO);
		dsim_write(dsim, 0x825904, DSIM_PLLCTRL);
		dsim_write(dsim, 0x203, DSIM_PHYTIMING);
		dsim_write(dsim, 0x20d0803, DSIM_PHYTIMING1);
		dsim_write(dsim, 0x30305, DSIM_PHYTIMING2);
#endif

		printk("DSIM_STATUS:0x%x\n", dsim_read(dsim, DSIM_STATUS));
		printk("DSIM_RGB_STATUS:0x%x\n", dsim_read(dsim, DSIM_RGB_STATUS));
		printk("DSIM_SWRST:0x%x\n", dsim_read(dsim, DSIM_SWRST));
		printk("DSIM_CLKCTRL:0x%x\n", dsim_read(dsim, DSIM_CLKCTRL));
		printk("DSIM_TIMEOUT:0x%x\n", dsim_read(dsim, DSIM_TIMEOUT));
		printk("DSIM_CONFIG:0x%x\n", dsim_read(dsim, DSIM_CONFIG));
		printk("DSIM_ESCMODE:0x%x\n", dsim_read(dsim, DSIM_ESCMODE));
		printk("DSIM_MDRESOL:0x%x\n", dsim_read(dsim, DSIM_MDRESOL));
		printk("DSIM_MVPORCH:0x%x\n", dsim_read(dsim, DSIM_MVPORCH));
		printk("DSIM_MHPORCH:0x%x\n", dsim_read(dsim, DSIM_MHPORCH));
		printk("DSIM_MSYNC:0x%x\n", dsim_read(dsim, DSIM_MSYNC));
		printk("DSIM_SDRESOL:0x%x\n", dsim_read(dsim, DSIM_SDRESOL));
		printk("DSIM_INTSRC:0x%x\n", dsim_read(dsim, DSIM_INTSRC));
		printk("DSIM_INTMSK:0x%x\n", dsim_read(dsim, DSIM_INTMSK));
		printk("DSIM_PKTHDR:0x%x\n", dsim_read(dsim, DSIM_PKTHDR));
		printk("DSIM_PAYLOAD:0x%x\n", dsim_read(dsim, DSIM_PAYLOAD));
		printk("DSIM_RXFIFO:0x%x\n", dsim_read(dsim, DSIM_RXFIFO));
		printk("DSIM_FIFOTHLD:0x%x\n", dsim_read(dsim, DSIM_FIFOTHLD));
		printk("DSIM_FIFOCTRL:0x%x\n", dsim_read(dsim, DSIM_FIFOCTRL));
		printk("DSIM_MEMACCHR:0x%x\n", dsim_read(dsim, DSIM_MEMACCHR));
		printk("DSIM_MULTI_PKT:0x%x\n", dsim_read(dsim, DSIM_MULTI_PKT));
		printk("DSIM_PLLCTRL_1G:0x%x\n", dsim_read(dsim, DSIM_PLLCTRL_1G));
		printk("DSIM_PLLCTRL:0x%x\n", dsim_read(dsim, DSIM_PLLCTRL));
		printk("DSIM_PLLCTRL1:0x%x\n", dsim_read(dsim, DSIM_PLLCTRL1));
		printk("DSIM_PLLCTRL2:0x%x\n", dsim_read(dsim, DSIM_PLLCTRL2));
		printk("DSIM_PLLTMR:0x%x\n", dsim_read(dsim, DSIM_PLLTMR));
		printk("DSIM_PHYTIMING:0x%x\n", dsim_read(dsim, DSIM_PHYTIMING));
		printk("DSIM_PHYTIMING1:0x%x\n", dsim_read(dsim, DSIM_PHYTIMING1));
		printk("DSIM_PHYTIMING2:0x%x\n", dsim_read(dsim, DSIM_PHYTIMING2));
	}
#endif

修改如下图所示:

#if 0	//modify by cym 20201127
	/* TODO: set pll ref clock rate to be fixed with 27MHz */
	ret = clk_set_rate(dsim->clk_pllref, PHY_REF_CLK);
#else
	/* set suitable rate for phy ref clock */
        ret = sec_mipi_dsim_set_pref_rate(dsim);
#endif

修改/home/topeet/imx8mm/linux/linux/linux-imx/include/drm/bridge/sec_mipi_dsim.h,添加如下所示代码,红色部分是修改过的代码 

#ifndef __SEC_MIPI_DSIM_H__
#define __SEC_MIPI_DSIM_H__

#include <drm/drmP.h>
#include <linux/bsearch.h>

struct sec_mipi_dsim_dphy_timing;
struct sec_mipi_dsim_pll;//add by cym 20201127

struct sec_mipi_dsim_plat_data {
	uint32_t version;
	uint32_t max_data_lanes;
	uint64_t max_data_rate;
	const struct sec_mipi_dsim_dphy_timing *dphy_timing;
	uint32_t num_dphy_timing;
	const struct sec_mipi_dsim_pll *dphy_pll;//add by cym 20201127
	int (*dphy_timing_cmp)(const void *key, const void *elt);
	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
					   struct drm_display_mode *mode);
};

/* add by cym 20201127 */
/* DPHY PLL structure */
struct sec_mipi_dsim_range {
        uint32_t min;
        uint32_t max;
};

struct sec_mipi_dsim_pll {
        struct sec_mipi_dsim_range p;
        struct sec_mipi_dsim_range m;
        struct sec_mipi_dsim_range s;
        struct sec_mipi_dsim_range k;
        struct sec_mipi_dsim_range fin;
        struct sec_mipi_dsim_range fpref;
        struct sec_mipi_dsim_range fvco;
};
/* end add */

/* DPHY timings structure */
struct sec_mipi_dsim_dphy_timing {
	uint32_t bit_clk;	/* MHz */

	uint32_t clk_prepare;
	uint32_t clk_zero;
	uint32_t clk_post;
	uint32_t clk_trail;

	uint32_t hs_prepare;
	uint32_t hs_zero;
	uint32_t hs_trail;

	uint32_t lpx;
	uint32_t hs_exit;
};

#define DSIM_DPHY_TIMING(bclk, cpre, czero, cpost, ctrail,	\
			 hpre, hzero, htrail, lp, hexit)	\
	.bit_clk	= bclk,					\
	.clk_prepare	= cpre,					\
	.clk_zero	= czero,				\
	.clk_post	= cpost,				\
	.clk_trail	= ctrail,				\
	.hs_prepare	= hpre,					\
	.hs_zero	= hzero,				\
	.hs_trail	= htrail,				\
	.lpx		= lp,					\
	.hs_exit	= hexit

static inline int dphy_timing_default_cmp(const void *key, const void *elt)
{
	const struct sec_mipi_dsim_dphy_timing *_key = key;
	const struct sec_mipi_dsim_dphy_timing *_elt = elt;

	/* find an element whose 'bit_clk' is equal to the
	 * the key's 'bit_clk' value or, the difference
	 * between them is less than 5.
	 */
	if (abs((int)(_elt->bit_clk - _key->bit_clk)) <= 5)
		return 0;

	if (_key->bit_clk < _elt->bit_clk)
		/* search bottom half */
		return 1;
	else
		/* search top half */
		return -1;
}

int sec_mipi_dsim_check_pll_out(void *driver_private,
				const struct drm_display_mode *mode);
int sec_mipi_dsim_bind(struct device *dev, struct device *master, void *data,
		       struct drm_encoder *encoder, struct resource *res,
		       int irq, const struct sec_mipi_dsim_plat_data *pdata);
void sec_mipi_dsim_unbind(struct device *dev, struct device *master, void *data);

void sec_mipi_dsim_suspend(struct device *dev);
void sec_mipi_dsim_resume(struct device *dev);

#endif

然后我们修改/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts设备树文件,&mipi_dsi节点如下图所示:

我们只需要在这个节点下配置屏幕设备树节点,因为要支持四种屏幕,所以我们先来设置四种屏幕的宏定义,如下所示,如果我们想要编译某种屏幕,将某种屏幕的宏定义使能就好了。

//#define LCD_TYPE_10_1         1
#define LCD_TYPE_7_0          1
//#define LCD_TYPE_9_7          1
//#define LCD_TYPE_MIPI_7_0       1

首先我们删除原来节点下的内容: 

然后我们写个逻辑框架,如下所示,数字代表是我们要添加的代码,mipi 7寸屏的配置写在数字111处,依次类推。

我们先来配置mipi 7寸屏幕,以下代码填写在111处 

panel@0 {/* 7.0 inch lvds screen */
    /*compatible是系统用来决定绑定到设备的设备驱动的关键,在内核源码driver目录下搜索toshiba,panel-tc358775会找到对应的驱动文件*/
	compatible = "toshiba,panel-tc358775";  	/*匹配驱动的值*/
reg = <0>;
	pinctrl-0 = <&pinctrl_mipi_dsi_en>; /*使用到的IO*/
	reset-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>; /*重置GPIO*/
	status = "okay";	/*状态为okay*/
	panel-width-mm = <154>; 
	panel-height-mm = <85>; 
	dsi-lanes = <4>;  /*显示通道设置为四通道*/

	backlight = <&backlight0>; /*背光*/
	client-device  = <&tc358775>; /*客户端*/
	display-timings {
					native-mode = <&timing0>;/*时序信息*/
					timing0:timing0{
							clock-frequency = <70000000>;*//*LCD像素时钟,单位是Hz*/
							hactive = <800>; /*LCD  X轴像素个数*/
							hsync-len = <10>;	/*LCD hspw参数*/						
hback-porch = <100>;/* important *//*LCD hbp参数*/
							hfront-porch = <24>;/*LCD hfp参数*/
							vactive = <1280>;/*LCD  Y轴像素个数*/
							vsync-len = <10>;/*LCD vspw参数*/
							vback-porch = <25>;/*LCD vbp参数*/
							vfront-porch = <10>;/*LCD vfp参数*/

							vsync-active = <0>;/*vsync 数据线极性*/
							hsync-active =<0>;/*hsync 数据线极性*/
							de-active =<0>;/*de 数据线极性*/
							pixelclk-active =<0>;/*clk数据线极性*/
					};
	};
};

上面我们已经解释了设备树配置的参数,那么屏幕的时序信息是什么意思呢?

我们把屏幕想象成一幅画,显示的过程其实就是用笔在不同的像素点画上不同的颜色,这根笔按照从左到右,从上到下的顺序画每个像素点,当画完最后一个像素点,一幅画也就画好了。我们画一个示意图,如下所示:

Hsync 是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图的最左边,Vsync是垂直同步信号,也叫做同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在上图的左上角。其实真正显示的是中间白色的部分。

显示完一行后会发出Hsync信号,然后电子枪会关闭,然后很快移动到屏幕的左边,hsync信号结束之后便可以显示新的一行数据,电子枪会打开,那么hsync信号结束到开始之间会插入一段延时,这个延时就是hbp,同理,vbp也是这样的道理,HBP HFP VBP VFP就是导致黑边的原因,这四个值的具体值得查阅LCD数据手册。

接下来我们来配置lvds 7寸屏幕,以下代码填写在222处

    panel@0 {/* 7.0 inch lvds screen */
                compatible = "toshiba,panel-tc358775";
                reg = <0>;
                pinctrl-0 = <&pinctrl_mipi_dsi_en>;
                reset-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
                status = "okay";
				panel-width-mm = <154>;
                panel-height-mm = <85>;
                dsi-lanes = <4>;

                backlight = <&backlight0>;
                client-device  = <&tc358775>;
                display-timings {
                                native-mode = <&timing0>;
                                timing0:timing0{
                                        clock-frequency = <70000000>;/*<70000000>;*/
                                        hactive = <800>;
                                        hsync-len = <10>;
                                        hback-porch = <100>;/* important */
                                        hfront-porch = <24>;
                                        vactive = <1280>;
                                        vsync-len = <10>;
                                        vback-porch = <25>;
                                        vfront-porch = <10>;

                                        vsync-active = <0>;
                                        hsync-active =<0>;
                                        de-active =<0>;
                                        pixelclk-active =<0>;
                                };
                };
        };

 接下来我们来配置lvds 9.7寸屏幕,以下代码填写在333处

   panel@1 {/* 9.7 inch screen */
                compatible = "toshiba,panel-tc358775";
                reg = <0>;
                pinctrl-0 = <&pinctrl_mipi_dsi_en>;
                reset-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
                status = "okay";/*"disabled";*/
                panel-width-mm = <154>;
                panel-height-mm = <85>;
                dsi-lanes = <4>;

                backlight = <&backlight0>;
                client-device  = <&tc358775>;

                display-timings {
                        timing {
                                clock-frequency = <65000000>;//<132000000>;
                                hactive = <1024>;
                                vactive = <768>;
                                hfront-porch = <4>;
                                hsync-len = <116>;
                                hback-porch = <20>;
                                vfront-porch = <2>;
                                vsync-len = <10>;//<12>;//<4>;
                                vback-porch = <20>;//<16>;//<6>;
                                hsync-active = <0>;
                                vsync-active = <0>;
                                de-active = <0>;
                                pixelclk-active = <0>;
                        };
                };
        };

接下来我们来配置lvds 10.1寸屏幕,以下代码填写在444处。

 panel@0 {/* 10.1 inch screen */
                compatible = "toshiba,panel-tc358775";
                reg = <0>;
                pinctrl-0 = <&pinctrl_mipi_dsi_en>;
                reset-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
                status = "okay";
                panel-width-mm = <154>;
                panel-height-mm = <85>;
                dsi-lanes = <4>;

                backlight = <&backlight0>;
                client-device  = <&tc358775>;
                display-timings {
                                native-mode = <&timing0>;
                                timing0:timing0{
                                        clock-frequency = <50000000>;
                                        hactive = <1024>;
                                        hsync-len = <116>;
                                        hback-porch = <160>;
                                        hfront-porch = <24>;
                                        vactive = <600>;
                                        vsync-len = <3>;
                                        vback-porch = <24>;
                                        vfront-porch = <2>;

                                        vsync-active = <0>;
                                        hsync-active =<0>;
                                        de-active =<0>;
                                        pixelclk-active =<0>;
                                };
                };
        };

然后在根目录下配置背光信息,添加backlight0节点,如下图所示:

backlight0: backlight@0 {
		compatible = "pwm-backlight";
		pwms = <&pwm1 0 50000 0>;

		brightness-levels = < 0 23 23 23 23 23 23 23 23 23
					23 23 23 23 23 23 23 23 23 23 
					23 23 23 23 24 25 26 27 28 29
					30 31 32 33 34 35 36 37 38 39
					40 41 42 43 44 45 46 47 48 49
					50 51 52 53 54 55 56 57 58 59
					60 61 62 63 64 65 66 67 68 69
					70 71 72 73 74 75 76 77 78 79
					80 81 82 83 84 85 86 87 88 89
					90 91 92 93 94 95 96 97 98 99
					100>;
                default-brightness-level = <89>;
        };

然后在根目录下配置&pwm1节点,如下图所示:

&pwm1 {

        pinctrl-names = "default";

        pinctrl-0 = <&pinctrl_pwm1>;

        status = "okay";

};

然后在pinctrl中添加pwm1信息,如下图所示:

在&iomuxc中默认配置好了引脚

pinctrl_mipi_dsi_en: mipi_dsi_en {
	fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO08_GPIO1_IO8		0x16
			>;
		};
pinctrl_pwm1: pwm1 {
	fsl,pins = <
			MX8MM_IOMUXC_GPIO1_IO01_PWM1_OUT                0x1d0
			>;
		};

 然后再i2c2下面注释掉以下节点

/*
	adv_bridge: adv7535@3d {
		compatible = "adi,adv7533";
		reg = <0x3d>;
		adi,addr-cec = <0x3b>;
		adi,dsi-lanes = <4>;
		status = "okay";

		port {
			adv7535_from_dsim: endpoint {
				remote-endpoint = <&dsim_to_adv7535>;
			};
		};
	};
*/

然后再i2c2节点下面配置

tc358775:tc358775@0x0f{

                compatible = "toshiba,tc358775";

                reg  = <0x0f>;

                status = "okay";

        };

 

 

72.2配置屏幕驱动

将网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\3.Linux系统移植\8.移植内核需要用到的文件\01 适配屏幕需要使用的文件”目录下的panel-itop_mipi_screen.c和tc358775_i2c.c和panel-tc358775.c拷贝到内核源码的

/linux-imx/drivers/gpu/drm/panel/目录下。

然后修改linux-imx/drivers/gpu/drm/panel/目录下Makefile文件,添加如下内容:

obj-$(CONFIG_DRM_PANEL_ITOP_MIPI) += panel-itop_mipi_screen.o
obj-$(CONFIG_DRM_PANEL_TC358775) += panel-tc358775.o
obj-$(CONFIG_DRM_PANEL_TC358775) += tc358775_i2c.o

然后修改linux-imx/drivers/gpu/drm/panel/目录下kconfig文件,添加如下内容: 

        tristate "itop mipi screen panel"
        depends on OF
        depends on DRM_MIPI_DSI
        depends on BACKLIGHT_CLASS_DEVICE
        help
          Say Y here if you want to enable support for itop mipi screen panel
          DSI panel.

config DRM_PANEL_TC358775
        tristate "TC358775 FHD panel"
        depends on OF
        depends on DRM_MIPI_DSI
        depends on BACKLIGHT_CLASS_DEVICE
        help
          Say Y here if you want to enable support for  TC358775 FHD
          DSI panel.

72.3编译屏幕驱动到内核

在上面小节配置完毕,保存修改,然后重新打开一个终端,输入以下命令,将默认的配置文件写入到.config文件。

make defconfig

然后输入以下命令进入menuconfig进行配置,如下所示:

export ARCH=arm64

make menuconfig

然后按如下图所示的路径,配置上屏幕,如下图所示:

 

72.4使能 Linux logo 显示 

Linux 内核启动的时候可以选择显示小企鹅 logo,只要这个小企鹅 logo 显示没问题那么我们的 LCD 驱动基本就工作正常了。这个 logo显示是要配置的,不过 Linux 内核一般都会默认开启 logo 显示,但是奔着学习的目的,我们还是来看一下如何使能 Linux logo 显示。打开 Linux 内核图形化配置界面,按下路径找到对应的配置项:

-> Device Drivers 
-> Graphics support 
-> Bootup logo (LOGO [=y]) 
-> Standard black and white Linux logo 
-> Standard 16-color Linux logo 
-> Standard 224-color Linux logo 

最后保存配置文件到arch/arm64/configs/defconfig文件,如下图所示: 

72.5配置触摸驱动

Mipi 7寸屏幕,lvds7 寸屏幕 ,lvds9.7寸屏幕使用的触摸芯片是ft5x06, lvds 10.1寸屏幕使用的触摸芯片是gt911。

首先修改/home/topeet/bsp_kernel_imx/bsp_kernel_imx/linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts设备树文件 ,配置触摸芯片的节点,如下图示,挂载在i2c2上。

&i2c2{
.............................................................................................

     #if defined(LCD_TYPE_7_0) || defined(LCD_TYPE_9_7) || defined(LCD_TYPE_MIPI_7_0)
        ft5x06_ts@38 {
                compatible = "edt,edt-ft5x06";
                reg = <0x38>;
                pinctrl-names = "defaults";
                pinctrl-0 = <&pinctrl_ft5x06_int>;
                interrupt-parent = <&gpio1>;
                interrupts = <15 2>;
                status = "okay";
        };
#elif defined(LCD_TYPE_10_1)
        gt911@14 {
                compatible = "goodix,gt911";
                reg = <0x14>;/*<0x5d>;*//*<0x14>;*/
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_ft5x06_int>;

                interrupt-parent = <&gpio1>;
                interrupts = <15 2>;/*<15  IRQ_TYPE_EDGE_RISING>;*/
                /*synaptics,y-rotation;*/
                esd-recovery-timeout-ms = <2000>;
                irq-gpios = <&gpio1 15 0>;/*<&gpio1 15 GPIO_ACTIVE_HIGH>;*/
                reset-gpios = <&gpio3 23 0>;/*<&gpio3 23 GPIO_ACTIVE_HIGH>;*/
                status = "okay";

        };
.............................................................................................
};

然后配置pinctrl信息,如下图所示:

&iomuxc {

..................................................................................................
    pinctrl_ft5x06_int: ft5x06_int {
         fsl,pins = <
         /*MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9               0x159*/
         MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15              0x159
         MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23               0x41
         >;
    };

..................................................................................................

接下来拷贝“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\3.Linux系统移植\8.移植内核需要用到的文件\01 适配屏幕需要使用的文件”目录下的edt-ft5x06.c文件拷贝到内核源码linux-imx/drivers/input/touchscreen目录下。 

72.6 编译驱动进内核

在上面小节配置完毕,保存修改,然后重新打开一个终端,输入以下命令,将默认的配置文件写入到.config文件。

make defconfig

然后输入以下命令进入menuconfig进行配置,如下所示:

export ARCH=arm64

make menuconfig

然后按如下图所示的路径,配置上屏幕,如下图所示:

     -> Device Drivers                                                   

         -> Input device support                                           

           -> Generic input layer (needed for keyboard, mouse, ...) (INPUT │

-> Touchscreens

 

最后保存配置文件到arch/arm64/configs/defconfig文件,如下图所示: 

72.7设定屏幕

如果要设置 7 mipi 屏幕,则进入 linux 源码路径下,编辑 itop8mm-evk.dts 设备树。

vim linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts

#define LCD_TYPE_MIPI_7_0   1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

 

如果要设置 7 lvds 屏幕,则进入 linux 源码路径下,编辑 itop8mm-evk.dts 设备树。

vim linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts

#define LCD_TYPE_7_0    1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

然后编辑 panel-tc358775.c

vim linux-imx/drivers/gpu/drm/panel/panel-tc358775.c

 

修改触摸文件 edt-ft5x06.c

vim linux-imx/drivers/input/touchscreen/edt-ft5x06.c

#define CONFIG_LVDS_7_0_800x1280    1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

如果要设置 9.7 lvds 屏幕,则进入 linux 源码路径下,编辑 itop8mm-evk.dts 设备树。

vim linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts

#define LCD_TYPE_9_7  1 取消注释,其他屏幕的宏定义加上注释,如下图所示

 

然后编辑 panel-tc358775.c。

vim linux-imx/drivers/gpu/drm/panel/panel-tc358775.c

#define LCD_TYPE_9_7   1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

 

修改触摸文件 edt-ft5x06.c

vim linux-imx/drivers/input/touchscreen/edt-ft5x06.c

#define CONFIG_LVDS_9_7_1024x768    1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

 

如果要设置 10.1 lvds 屏幕,则进入 linux 源码路径下,编辑 itop8mm-evk.dts 设备树。

vim linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dts

#define LCD_TYPE_10_1    1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

 

然后编辑 panel-tc358775.c

vim linux-imx/drivers/gpu/drm/panel/panel-tc358775.c

#define LCD_TYPE_10_1    1 取消注释,其他屏幕的宏定义加上注释,如下图所示:

 

然后再回到之前的终端窗口进行编译镜像。编译之后烧写镜像,系统启动后如下图所示,作者连接的是mipi屏幕,触摸显示正常。如下图所示: 

输入以下命令查看触摸节点

cat /proc/bus/input/devices

然后输入以下命令,触摸屏幕会上报信息。

hexdump /dev/input/event1

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1966590.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT:数据库不符合第二范式示例

ChatGPT&#xff1a;数据库不符合第二范式示例 这张图片为什么不符合数据库第二范式 这个表格不符合数据库第二范式&#xff08;2NF&#xff09;的原因如下&#xff1a; 1. 数据库第二范式&#xff08;2NF&#xff09;定义 第二范式要求一个数据库表格在满足第一范式&#xf…

【Hot100】LeetCode—169. 多数元素

目录 题目1- 思路2- 实现⭐169. 多数元素——题解思路 3- ACM 实现 题目 原题连接&#xff1a;169. 多数元素 1- 思路 定义两个变量 一个是 count&#xff1a;维护当前元素的出现次数一个是 ret &#xff1a;维护当前元素 思路 遍历整个数组**①如果 count 0 **&#xff…

了解对称加密与密钥协商技术

1.对称加密算法 加密的理论基础是替代和换位。替代主要用于扰乱&#xff0c;使用不同的位、字符或字符分组来替换原来的位、字符或字符分组。换位主要用于扩散&#xff0c;并不使用不同的文本来替换原来的文本&#xff0c;而是对原有的值进行置换&#xff0c;即重新排列原来的位…

Django开发企业官网

1.在本地创建一个website的文件夹&#xff0c;在vc里面打开文件夹 2.创建虚拟环境和安装django 终端执行命令 python -m venv venv&#xff08;创建一个虚拟文件名字叫venv&#xff09; venv\Scripts\activate(启动虚拟环境) pip install django&#xff08;安装django&#x…

CRC的手算过程——MODBUS

软件计算结果&#xff1a; 原理参考下面的文章&#xff1a; https://www.cnblogs.com/esestt/archive/2007/08/09/848856.html https://blog.csdn.net/weixin_44256803/article/details/105805628 https://blog.csdn.net/d_leo/article/details/73572373 手算过程如下&#x…

Day27 | 贪心算法 452. 用最少数量的箭引爆气球 435. 无重叠区间 763.划分字母区间

语言 Java 452. 用最少数量的箭引爆气球 用最少数量的箭引爆气球 题目 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐…

MATLAB(3)训练模型

前言 在MATLAB中训练模型通常涉及到选择一个合适的机器学习算法或深度学习框架&#xff0c;并准备相应的数据集。这里我将给出一个使用MATLAB的机器学习工具箱来训练一个简单的分类模型的示例代码。我们将使用逻辑回归&#xff08;Logistic Regression&#xff09;来分类一个简…

OpenCV 图像处理 轮廓检测基本原理

文章目录 基本原理关键函数和参数注意事项 示例代码示例效果代码详解findContours 函数原型findContours函数变体 基本原理 轮廓发现是图像处理中的一个重要步骤&#xff0c;用于检测物体的边界和形状。 图像预处理&#xff1a; 轮廓发现通常在灰度图像上进行。因此&#xff0…

科研经历——8/1——第一次审稿教程

文章目录 引言正文审稿通知审核论文界面Add reviewRequest view 评审结果 总结 引言 头一次被ICONIP选做审稿人&#xff0c;我还是听懵的&#xff0c;毕竟我也是主要的提交者之一&#xff0c;居然让我审人家的的文章&#xff0c;还是挺懵的&#xff01;不过&#xff0c;还是很…

【吊打面试官系列-Dubbo面试题】Dubbo 和 Dubbox 之间的区别?

大家好&#xff0c;我是锋哥。今天分享关于 【Dubbo 和 Dubbox 之间的区别&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; Dubbo 和 Dubbox 之间的区别&#xff1f; Dubbo 和 Dubbox 是两个在 Java 开发领域中使用的 RPC 框架。它们之间的关系比较复杂&#x…

HT for Web 轻松构建组态拓扑结构

在现代的数据可视化和网络管理中&#xff0c;拓扑图是一种非常重要的工具。它可以直观地展示节点(Node)和节点之间的关系(Edge)。无论是在 2D 还是 3D 环境中&#xff0c;拓扑图都可以帮助我们更好地理解和管理复杂的系统。 然而&#xff0c;由于这些拓扑图通常极为复杂&#…

JAVA(多线程)day 7.31

ok了家人们今天学习多线程&#xff0c; 一.多线程相关概念 1.1 并行与并发 并行&#xff1a;在同一时刻&#xff0c;有多个任务在多个 CPU 上同时执行。 并发&#xff1a;在同一时刻&#xff0c;有多个任务在单个 CPU 上交替执行。 1.2 多线程 cpu同时执行多个程序。 好处…

Mix、Lab是一种生活状态#Mixlab夏日T恤

shadow&#xff1a;这款怎么样&#xff1f; 混合实验家 千*然 15:53&#xff1a; " 夸夸&#xff0c;帅爆 logo很有细胞活力啊&#xff01; 再开个白款&#xff0c;夏天凉快&#xff01;大T&#xff0c;冲&#xff01; ” shadow: 往常都是孵化社区成员的项目&#xff0c…

非线性面板数据实证模型及 Stata 具体操作步骤

目录 一、引言 二、文献综述 三、理论原理 四、实证模型 五、稳健性检验 六、程序代码及解释 一、引言 在当今的经济和社会研究中&#xff0c;非线性面板数据模型的应用日益广泛。这类模型能够更好地捕捉数据中的复杂关系&#xff0c;为研究者提供更深入和准确的分析结果。…

json-server(快速搭建本地 RESTful API 的工具)

json-server 是什么? Json-server 是一个零代码快速搭建本地 RESTful API 的工具。它使用 JSON 文件作为数据源,并提供了一组简单的路由和端点,可以模拟后端服务器的行为。 github地址:GitHub - typicode/json-server: Get a full fake REST API with zero coding in less…

VS code-解决云服务器重装镜像后vs code无法连接的问题

问题描述&#xff1a;从centos换到ubantu后&#xff0c;xshell能直接连接上&#xff08;没有更改ssh配置信息&#xff09;&#xff0c;但是vscode连不上&#xff08;配置文件因为端口号和ip是一样的&#xff0c;也没法改&#xff09; 解决办法&#xff1a; 找到vs code config…

从DevOps到DevSecOps是怎样之中转变?

DevSecOps是DevOps实践的自然演进&#xff0c;其重点是将安全集成到软件开发和部署流程中。在DevOps和DevSecOps发展之前&#xff0c;企业通常在在软件部署前进行集中的安全测试&#xff0c;导致安全介入严重滞后&#xff0c;漏洞分风险无法及时修复&#xff0c;影响上线交付。…

MGTR-250M 以电折水设备-助力取水计量监测体系建设

一体式以电折水智能终端通过高度集成化设计&#xff0c;巧妙融合了空气开关、开关电源、隔离变压器、接触器、智能电表、RTU、4G通信模块、定位模块等八大核心功能&#xff0c;不仅展现了经济高效和智能运维的双重优势&#xff0c;更以其超强的安全防护能力确保了使用的高度安全…

CV相关知识

在计算机科学和人工智能领域&#xff0c;"CV" 通常指的是 "Computer Vision"&#xff08;计算机视觉&#xff09;。计算机视觉是研究如何使计算机能够从图像或视频中获取、处理和理解视觉信息的科学和技术。计算机视觉的目标是使计算机能够自动执行人类视觉…

干净清爽的网页给用户浏览体验的重要性!此刻便展现了出来

干净清爽的网页给用户浏览体验的重要性 艾斯视觉作为ui设计和前端开发从业者&#xff0c;其观点始终认为&#xff1a;网页已成为信息传播和交流的重要平台。一个干净清爽的网页设计不仅能够吸引用户的眼球&#xff0c;更能提升用户的浏览体验&#xff0c;从而在激烈的网络竞争…