Linux内核驱动 --- CCF框架 provider驱动的编写

这篇具有很好参考价值的文章主要介绍了Linux内核驱动 --- CCF框架 provider驱动的编写。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Provider驱动编写流程

复制上节内容中对Provider驱动编写流程的总结:
1)分析硬件的clock tree,按照上面所描述的分类,将这些clock分类。

2)将clock tree在DTS中描述出来,需要注意以下几2点:

a)对于fixed rate clocks,.compatible固定填充"fixed-clock",并提供"clock-frequency"和"clock-output-names"关键字。之后不需要再driver中做任何处理,clock framework core会帮我们搞定一切。

b)同样,对于fixed factor clock,.compatible为"fixed-factor-clock",并提供"clock-div"、"clock-mult"和"clock-output-names"关键字。clock framework core会帮我们搞定一切。

切记,尽量利用kernel已有资源,不要多写一行代码,简洁的就是美的!

3)对于不能由clock framework core处理的clock,需要在driver中使用struct of_device_id进行匹配,并在初始化时,调用OF模块,查找所有的DTS匹配项,并执行合适的regitser接口,注册clock。

4)注册clock的同时,将返回的struct clk指针,保存在一个数组中,并调用of_clk_add_provider接口,告知clock framework core。

5)最后,也是最重要的一点,多看kernel源代码,多模仿,多抄几遍,什么都熟悉了!

这一节用实际例子来写一个Provider驱动

平台:TsingMicro-TX5112

设计思路

不同芯片的时钟树上的clk对象和他们的继承关系肯定不同。如果为每颗芯片都实现一份clk驱动就会产生大量的冗余和重复。
可以将公共部分放在ts_clk.c中(公共部分指注册clk然后使用of_clk_add_provider告知clock framework core)。
设计一个接口,接口中包含所有种类的clk对象的注册函数。
Linux内核驱动 --- CCF框架 provider驱动的编写
针对一款芯片的时钟树上的对不同种类clk注册函数的实现 在clk的初始化阶段绑定到该接口的实例上:
Linux内核驱动 --- CCF框架 provider驱动的编写
这样每款芯片只需要专注于实现自己的clk_xxx_register_plls, clk_xxx_register_comps等这些函数即可,这些函数的实现可以单独放在一个文件中,如clk-tx5112/clk-tx5215.clk/等等。
对于不同芯片的编译的区分在makefile和defconfig中实现。

将需要注册的clk模块的一些信息抽象出来:
Linux内核驱动 --- CCF框架 provider驱动的编写
其中clk_onecell_data是内核提供的结构

struct clk_onecell_data {
         struct clk **clks;
         unsigned int clk_num;
};
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);

用于保存所有的clk对象以及描述clk对象的总体个数。
clock provider需要把这些struct clk结构保存起来,并调用clock framework的接口,将这些对应信息告知framework的OF模块,这样才可以帮助将clock consumer的DTS描述转换为struct clk结构。该接口如下:

int of_clk_add_provider(struct device_node *np,
         struct clk *(*clk_src_get)(struct of_phandle_args *args, void *data),
         void *data);

其中np为clk的设备节点,
clk_src_get为获取struct clk指针的回调函数,由clock provider根据实际的逻辑实现。典型的,对于onecell的clk对象内核提供的就是上面提到的of_clk_src_onecell_get函数,他有两个参数:

  • args,struct of_phandle_args类型的指针,由DTS在解析参数时传递。例如上面的“clocks = <&clock 32>, <&clock 45>;”,32、45就是通过这个指针传进来的;
  • data,保存struct clk结构的指针,通常是一个数组,具体由provider决定。

data,和回调函数中的data意义相同,只是这里由provider提供,get时由clock framework core传递给回调函数。

第0步 clk模块的初始化过程:

static bool probed;

static void __init ts_clk_init(struct device_node *np)
{
	int ret;
	struct ts_clk_params *paras = NULL;

	//pr_info("%s enter.\n", __func__);

	if (probed)
		return;

	paras = (struct ts_clk_params *)ts_clk_get_para();
	ret = ts_clk_of_parse(np, paras);
	if (ret) {
		pr_err("%s of parse failed, ret %d\n", __func__, ret);
		return;
	}
	ts_clk_init_funcs(&paras->funcs);

	/* PLL clocks */
	ret = ts_clk_register_plls(paras);
	if (ret) {
		pr_err("%s register plls failed, ret %d\n", __func__, ret);
		return;
	}

	/* Composite clocks with mux, with or without divider or gate */
	ret = ts_clk_register_comps(paras);
	if (ret) {
		pr_err("%s register comps, ret %d\n", __func__, ret);
		return;
	}

	/* Composite clocks without mux */
	ret = ts_clk_register_comps_without_mux(paras);
	if (ret) {
		pr_err("%s register comps without mux failed, ret %d\n",
			__func__, ret);
		return;
	}

	/* Dividing clocks */
	ret = ts_clk_register_dividers(paras);
	if (ret) {
		pr_err("%s register dividers failed, ret %d\n", __func__, ret);
		return;
	}

	/* Gated clocks */
	ret = ts_clk_register_gates(paras);
	if (ret) {
		pr_err("%s register gates, ret %d\n", __func__, ret);
		return;
	}

	ret = ts_clk_add_provider(np, paras);
	if (ret) {
		pr_err("%s add provider, ret %d\n", __func__, ret);
		return;
	}

	probed = true;
	//pr_info("%s exit.\n", __func__);
}

CLK_OF_DECLARE(ts_clk, "ts,ts-common-clk", ts_clk_init);

这里的ts_clk_register_xxx内部就调用到了接口中的相应的函数:
Linux内核驱动 --- CCF框架 provider驱动的编写

第2步:实现接口中对应的注册函数

分析硬件的clock tree,按照上面所描述的分类,将这些clock分类。
对于多种clk这里不可能全部讲一遍,挑选某种clk来讲解更现实,这里选取gate类clk的注册讲解。

针对一块芯片上的所有clk对象的描述,用静态定义的方式描述在代码中:

#define GATE_LIST \
	GATE(TS_CLK_TX5112_SKE_CLK, BUS_CLK_AXI_EN, 4, 0) \
	GATE(TS_CLK_TX5112_OCRAM_ACLK, BUS_CLK_AXI_EN, 3, 0) \
	GATE(TS_CLK_TX5112_MEM_DMA_ACLK, BUS_CLK_AXI_EN, 2, 0) \
	GATE(TS_CLK_TX5112_AUD_CODEC_HCLK, BUS_CLK_AHB_EN, 10, 0) \
	GATE(TS_CLK_TX5112_OSPI_HCLK, BUS_CLK_AHB_EN, 9, 0) \
	GATE(TS_CLK_TX5112_GMAC_HCLK, BUS_CLK_AHB_EN, 8, 0) \
	GATE(TS_CLK_TX5112_USB2C_HCLK, BUS_CLK_AHB_EN, 7, 0) \
	GATE(TS_CLK_TX5112_SDHC1_HCLK, BUS_CLK_AHB_EN, 6, 0) \
	GATE(TS_CLK_TX5112_SDHC0_HCLK, BUS_CLK_AHB_EN, 5, 0) \
	GATE(TS_CLK_TX5112_PERI_DMA1_HCLK, BUS_CLK_AHB_EN, 4, 0) \
	GATE(TS_CLK_TX5112_PERI_DMA0_HCLK, BUS_CLK_AHB_EN, 3, 0) \
	GATE(TS_CLK_TX5112_BOOTROM_HCLK, BUS_CLK_AHB_EN, 2, 0) \
	GATE(TS_CLK_TX5112_GPIO_B_PCLK, BUS_CLK_APB_EN, 31, 4) \
	GATE(TS_CLK_TX5112_GPIO_A_PCLK, BUS_CLK_APB_EN, 30, 4) \
	GATE(TS_CLK_TX5112_PDM_PCLK, BUS_CLK_APB_EN, 29, 3) \
	GATE(TS_CLK_TX5112_SYS_REG_PCLK, BUS_CLK_APB_EN, 27, 9) \
	GATE(TS_CLK_TX5112_OTPC_PCLK, BUS_CLK_APB_EN, 26, 9) \
	GATE(TS_CLK_TX5112_OSPI_PCLK, BUS_CLK_APB_EN, 25, 8) \
	GATE(TS_CLK_TX5112_PWM_PCLK, BUS_CLK_APB_EN, 24, 7) \
	GATE(TS_CLK_TX5112_TMR_PCLK, BUS_CLK_APB_EN, 23, 6) \
	GATE(TS_CLK_TX5112_WDT_PCLK, BUS_CLK_APB_EN, 22, 5) \
	GATE(TS_CLK_TX5112_GPIO_PCLK, BUS_CLK_APB_EN, 21, 4) \
	GATE(TS_CLK_TX5112_ADC_PCLK, BUS_CLK_APB_EN, 20, 3) \
	GATE(TS_CLK_TX5112_I2S0_PCLK, BUS_CLK_APB_EN, 19, 3) \
	GATE(TS_CLK_TX5112_USI1_PCLK, BUS_CLK_APB_EN, 18, 2) \
	GATE(TS_CLK_TX5112_USI0_PCLK, BUS_CLK_APB_EN, 17, 2) \
	GATE(TS_CLK_TX5112_UART1_PCLK, BUS_CLK_APB_EN, 15, 1) \
	GATE(TS_CLK_TX5112_UART0_PCLK, BUS_CLK_APB_EN, 14, 1) \
	GATE(TS_CLK_TX5112_SD0_CCLK_SMPL, SDHC0_CCLK_CFG, 12, 0) \
	GATE(TS_CLK_TX5112_SD0_CCLK_DRV, SDHC0_CCLK_CFG, 11, 0) \
	GATE(TS_CLK_TX5112_SD0_CCLK_SMP_EDGE, SDHC0_CCLK_CFG, 10, 0) \
	GATE(TS_CLK_TX5112_SD0_CCLK_DRV_EDGE, SDHC0_CCLK_CFG, 9, 0) \
	GATE(TS_CLK_TX5112_SD0_CCLK, SDHC0_CCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_SD1_CCLK_SMPL, SDHC1_CCLK_CFG, 12, 0) \
	GATE(TS_CLK_TX5112_SD1_CCLK_DRV, SDHC1_CCLK_CFG, 11, 0) \
	GATE(TS_CLK_TX5112_SD1_CCLK_SMP_EDGE, SDHC1_CCLK_CFG, 10, 0) \
	GATE(TS_CLK_TX5112_SD1_CCLK_DRV_EDGE, SDHC1_CCLK_CFG, 9, 0) \
	GATE(TS_CLK_TX5112_SD1_CCLK, SDHC1_CCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_OSPI_REF_CLK, OSPI_RCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_USB_REF_CLK, USB_PHY_CLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_I2C1_PCLK, I2C_ICCLK_CFG0, 3, 0) \
	GATE(TS_CLK_TX5112_I2C0_PCLK, I2C_ICCLK_CFG0, 2, 0) \
	GATE(TS_CLK_TX5112_I2C2_PCLK, I2C_ICCLK_CFG1, 3, 0) \
	GATE(TS_CLK_TX5112_SPI_PCLK, SPI_SSICLK_CFG, 3, 0) \
	GATE(TS_CLK_TX5112_TMR_T4CLK, TMR_TCLK_CFG0, 3, 0) \
	GATE(TS_CLK_TX5112_TMR_T3CLK, TMR_TCLK_CFG0, 2, 0) \
	GATE(TS_CLK_TX5112_TMR_T6CLK, TMR_TCLK_CFG1, 3, 0) \
	GATE(TS_CLK_TX5112_TMR_T5CLK, TMR_TCLK_CFG1, 2, 0) \
	GATE(TS_CLK_TX5112_TMR_T8CLK, TMR_TCLK_CFG2, 3, 0) \
	GATE(TS_CLK_TX5112_TMR_T7CLK, TMR_TCLK_CFG2, 2, 0) \
	GATE(TS_CLK_TX5112_I2S0_OCLK_O, I2S0_MCLK_CFG, 10, 0) \
	GATE(TS_CLK_TX5112_I2S0_OCLK, I2S0_MCLK_CFG, 3, 0) \
	GATE(TS_CLK_TX5112_I2S0_MCLK, I2S0_MCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_PDM_MCLK, PDM_MCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_AUD_DAC_PBCLK_INV, AUD_DAC_CLK_CFG0, 7, 0) \
	GATE(TS_CLK_TX5112_AUD_DAC_CCLK, AUD_DAC_CLK_CFG0, 3, 0) \
	GATE(TS_CLK_TX5112_AUD_DAC_PBCLK, AUD_DAC_CLK_CFG0, 2, 0) \
	GATE(TS_CLK_TX5112_AUD_TMR_STRB, AUD_DAC_CLK_CFG1, 2, 0) \
	GATE(TS_CLK_TX5112_AUD_ADC_CCLK, AUD_ADC_CLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_VI_DDR_ACLK, MCTL_ACLK_CFG0, 11, 0) \
	GATE(TS_CLK_TX5112_DDRC_CORE_CLK, MCTL_ACLK_CFG0, 8, 0) \
	GATE(TS_CLK_TX5112_DDR_PHY_PCLK, MCTL_ACLK_CFG0, 7, 0) \
	GATE(TS_CLK_TX5112_UMCTL_PCLK, MCTL_ACLK_CFG0, 6, 0) \
	GATE(TS_CLK_TX5112_MCTL_P3_ACLK, MCTL_ACLK_CFG0, 5, 0) \
	GATE(TS_CLK_TX5112_MCTL_P2_ACLK, MCTL_ACLK_CFG0, 4, 0) \
	GATE(TS_CLK_TX5112_MCTL_P1_ACLK, MCTL_ACLK_CFG0, 3, 0) \
	GATE(TS_CLK_TX5112_MCTL_P0_ACLK, MCTL_ACLK_CFG0, 2, 0) \
	GATE(TS_CLK_TX5112_HDR_SCLK, VI_BUS_CLK_EN, 16, 0) \
	GATE(TS_CLK_TX5112_VPE_ISP_CLK, VI_BUS_CLK_EN, 15, 0) \
	GATE(TS_CLK_TX5112_MIPI_RX1_PIXCLK, VI_BUS_CLK_EN, 14, 0) \
	GATE(TS_CLK_TX5112_MIPI_RX0_PIXCLK1, VI_BUS_CLK_EN, 13, 0) \
	GATE(TS_CLK_TX5112_MIPI_RX0_PIXCLK0, VI_BUS_CLK_EN, 12, 0) \
	GATE(TS_CLK_TX5112_MIPI_RX1_PCLK, VI_BUS_CLK_EN, 10, 0) \
	GATE(TS_CLK_TX5112_MIPI_RX0_PCLK, VI_BUS_CLK_EN, 9, 0) \
	GATE(TS_CLK_TX5112_HDR_HCLK, VI_BUS_CLK_EN, 8, 0) \
	GATE(TS_CLK_TX5112_VPE_HCLK, VI_BUS_CLK_EN, 7, 0) \
	GATE(TS_CLK_TX5112_VI_CFG_HCLK, VI_BUS_CLK_EN, 6, 0) \
	GATE(TS_CLK_TX5112_HDR_ACLK, VI_BUS_CLK_EN, 5, 0) \
	GATE(TS_CLK_TX5112_VPE_ACLK, VI_BUS_CLK_EN, 4, 0) \
	GATE(TS_CLK_TX5112_ISP_ACLK, VI_BUS_CLK_EN, 3, 0) \
	GATE(TS_CLK_TX5112_ISP_SCLK, ISP_SCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_VPE_CCLK, VPE_CCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_MIPI_TXCLKESC, MIPI_CLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_AMR_HCLK, AMR_CCLK_CFG, 4, 0) \
	GATE(TS_CLK_TX5112_AMR_ACLK, AMR_CCLK_CFG, 3, 0) \
	GATE(TS_CLK_TX5112_AMR_CCLK, AMR_CCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_RNE_CLK, RNE_CCLK_CFG, 6, 0) \
	GATE(TS_CLK_TX5112_AI_ACLK, RNE_CCLK_CFG, 5, 0) \
	GATE(TS_CLK_TX5112_RNE_HCLK, RNE_CCLK_CFG, 4, 0) \
	GATE(TS_CLK_TX5112_RNE_ACLK, RNE_CCLK_CFG, 3, 0) \
	GATE(TS_CLK_TX5112_RNE_CCLK, RNE_CCLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_VPU_HCLK, VPU_CLK_CFG, 7, 0) \
	GATE(TS_CLK_TX5112_H265_CCLK, VPU_CLK_CFG, 6, 0) \
	GATE(TS_CLK_TX5112_H265_PCLK, VPU_CLK_CFG, 5, 0) \
	GATE(TS_CLK_TX5112_H265_ACLK, VPU_CLK_CFG, 4, 0) \
	GATE(TS_CLK_TX5112_H264_PCLK, VPU_CLK_CFG, 3, 0) \
	GATE(TS_CLK_TX5112_H264_ACLK, VPU_CLK_CFG, 2, 0) \
	GATE(TS_CLK_TX5112_CHIP_OCLK_I3, CHIP_OCLK_CFG, 5, 0) \
	GATE(TS_CLK_TX5112_CHIP_OCLK_I2, CHIP_OCLK_CFG, 4, 0) \
	GATE(TS_CLK_TX5112_CHIP_OCLK_I1, CHIP_OCLK_CFG, 3, 0) \
	GATE(TS_CLK_TX5112_CHIP_OCLK_I0, CHIP_OCLK_CFG, 2, 0)

#define _GATEIFY(id) TS_CLK_TX5112_GATE_##id
#define GATEIFY(id) _GATEIFY(id)

enum ts_gate_ids {
#define GATE(id, ...) GATEIFY(id),
	GATE_LIST
#undef GATE
	TS_CLK_GATE_NONE,
};

static const struct ts_gate_params ts_tx5112_gates[] = {
#define GATE(id, _off, _idx, _we) \
	[GATEIFY(id)] = { \
		.off = (_off), \
		.bit_idx = (_idx), \
		.we = (_we), \
	},
	GATE_LIST
#undef GATE
};

#define REGISTER_GATE(id, name, parent) do { \
		const struct ts_gate_params *params = &ts_tx5112_gates[GATEIFY(id)]; \
		clk_dm(id, name, \
			clk_register_gate(NULL, name, parent, 0, \
				top_base + params->off, \
				params->bit_idx, 0, NULL)); \
	} while (false)

这里面的宏的写法比较复杂,展开后ts_gate_ids里自动列出TS_CLK_TX5112_GATE_##id, id为dt-bindings里的所有宏,列出的枚举量从0自增,最后一个值为TS_CLK_GATE_NONE。

ts_tx5112_gates中重定义了GATE宏,此时GATE_LIST里所有的item都会被扩展为对struct ts_gate_params对象的初始化,存在ts_tx5112_gates里。

REGISTER_GATE宏用于将初始化的 ts_tx5112_gates 数组中的对象,按id取出来,并调用clk_dm来对tx_tx5112_clks进行填充
tx_tx5112_clks这个数组最后会被of_clk_add_provider一起提交。

static inline void clk_dm(ulong id, const char *name, struct clk *clk)
{
	int ret;

	if (id >= TS_CLK_TX5112_MAX) {
		pr_err("clk_register_clkdev %s failed\n", name);
		return;
	}

	if (IS_ERR_OR_NULL(clk)) {
		pr_err("%s %lu failed\n", __func__, id);
		return;
	}

	ret = clk_register_clkdev(clk, name, NULL);
	if (ret) {
		pr_err("clk_register_clkdev %s failed\n", name);
		return;
	}

	tx_tx5112_clks[id] = clk;
}

clk_register_gate为内核提供的针对gate类型的clk对象的注册函数,上一节已经详细说过
其内部调用了clk_hw_register_gate,

struct clk *clk_register_gate(struct device *dev, const char *name,
		const char *parent_name, unsigned long flags,
		void __iomem *reg, u8 bit_idx,
		u8 clk_gate_flags, spinlock_t *lock)
{
	struct clk_hw *hw;

	hw = clk_hw_register_gate(dev, name, parent_name, flags, reg,
				  bit_idx, clk_gate_flags, lock);
	if (IS_ERR(hw))
		return ERR_CAST(hw);
	return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_gate);

framework提供了struct clk_hw结构,从clock provider的角度,描述clock
clock provider负责把系统中每个clock的静态数据准备好,然后交给clock framework的核心逻辑,剩下的事情,clock provider就不用操心了。这个过程,就是clock driver的编写过程。
现在我们静态数据已经准备好,通过clk_hw_register_gate提交即可,所以这里就是provider的注册重点。文章来源地址https://www.toymoban.com/news/detail-472245.html

到了这里,关于Linux内核驱动 --- CCF框架 provider驱动的编写的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • i.MX 6ULL 驱动开发 二十九:向 Linux 内核中添加自己编写驱动

    Linux 内核编译流程如下: 1、配置 Linux 内核。 2、编译 Linux 内核。 说明:进入 Linux 内核源码,使用 make help 参看相关配置。 1、 menuconfig 它本身是一个软件,只提供图形界面配置的一些逻辑,并不负责提供内容。 2、 menuconfig 是内核源码树的各目录下的 kconfig 提供的。 3、 m

    2023年04月10日
    浏览(72)
  • Microsoft OLE DB Provider for ODBC Drivers 错误 ‘80004005‘[Microsoft][ODBC 驱动程序管理器] - 解决方案

    Microsoft OLE DB Provider for ODBC Drivers 错误 \\\'80004005\\\' [Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配 解决办法: 64位操作系统不支持Microsoft OLE DB Provider for Jet驱动程序,也不支持更早的Microsoft Access Driver (*.mdb)方式连接。 所以,程序里面

    2024年02月12日
    浏览(43)
  • 【嵌入式Linux内核驱动】SPI子系统 | 硬件原理 | 应用编程 | 内核驱动 | 总体框架

    1.1 SPI通信协议 SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select) 同步,全双工 支持总线挂载多设备(一主多从) 1.2 硬件连接 多NSS独立片选方式 菊花

    2024年02月16日
    浏览(64)
  • 【嵌入式Linux内核驱动】05_IIC子系统 | 硬件原理与常见面试问题 | 应用编程 | 内核驱动 | 总体框架

    1.1 IIC 基础 IIC协议简介—学习笔记_iic标准协议_越吃越胖的黄的博客-CSDN博客 I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器、传感器、存储器和其他外设。 I2C使用两条线(SDA和SCL)进行通信,可以连接多个设备,每个设备都有一个唯一的地址。I2C总线上的

    2024年02月09日
    浏览(59)
  • linux-2.6.22.6内核i2c驱动框架源码分析

    i2c是常见的通信协议,协议比较简单,只有数据和时钟两条线(SDA和SCL),i2c的通信分为主机和从机,主机一般占主导地位,从机可以有多个。 i2c通信的数据格式为(SDA上的数据):开始的7位里面指定了设备地址(因为有多个从机),第8位是读或写信号,表示此次传输是读还

    2024年02月11日
    浏览(51)
  • Flutter 状态管理 Provider

    Flutter基于声明式构建UI,原生则是命令式,状态管理是用于解决声明式开发带来的问题。 例:命令式的原生,数据更新需要拿到对应控件并更改其显示值;而声明式则需要更改数据值并通过setstate更新状态,重新构建组件 Flutter 中有这么一种说法: UI = f(state): 优势: 无需繁琐

    2024年02月13日
    浏览(35)
  • Flutter Provider使用

    Provider 之状态管理 下载地址: https://pub-web.flutter-io.cn/packages/provider 导入依赖: 导入头文件: 创建 Model 混入 ChangeNotifier 。 Counter 中的私有属性 _count 变化时 ,添加监听 notifyListeners() 设置组件监听使用 MultiProvider ,其中 providers 属性设置需要绑定的数据,即上面的 Counter 类,这

    2024年02月16日
    浏览(36)
  • Flutter的状态管理之Provider

    Flutter Provider是Flutter中一个非常流行的状态管理库,它可以帮助开发者更加方便地管理应用程序中的状态。Provider提供了一种简单的方式来共享和管理应用程序中的数据,并且可以根据数据的变化来自动更新UI界面。 Provider的核心思想是将数据作为一个全局的单例对象,然后通

    2024年02月08日
    浏览(53)
  • 探索 Flutter 的 Provider:介绍与用法

    在 Flutter 应用开发中,状态管理始终是一个核心话题。随着 Flutter 的不断发展,各种状态管理方案应运而生。Provider,作为一个轻量级且高效的状态管理库,在社区中获得了广泛的认可和使用。本文将深入探讨 Provider 的最新特性和用法,帮助开发者更好地在 Flutter 应用中实现

    2024年01月16日
    浏览(37)
  • Flutter 文件读写---path_provider

    在Flutter中,可以通过 path_provider 库来实现文件的读写操作。这个库提供了许多方法,可以方便地获取设备上的常用目录,比如文档目录、下载目录、临时目录等。 在 pubspec.yaml 文件中添加 path_provider 依赖: 然后运行 flutter pub get 命令安装依赖。 首先需要导入 path_provider 库:

    2024年02月08日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包