Pintrl LINUX 下管脚复用添加CAN复用实例

SOC由于外设众多管脚不够用普片使用管脚复用,在LINUX下专门有个Pinctrl的子系统进行复用管脚的管理。我再这就描述相关的系统架构,只是简单的描述一下实例和使用说明。我使用的810芯片CAN1管脚需要配置复用,下面是我操作实现方式。

详细介绍建议查看https://blog.csdn.net/u012830148/article/details/80609337 相关说明。

添加一个Pintrl定义CAN1

LINUX驱动下SOC的PIN管脚控制已经完整的定义好了,无需要去修改。我们添加一个Pintrl的定义其实只是提供一个Pin的复用选择组合,我们拿CAN1的Pintrl添加进行说明。

1.首先是添加一个CAN1 pin管脚组合,pin管脚组合表示CAN1要使用到哪个管脚:

static const u32 can_1_pins[] = {8, 9};

其中管脚定义8 9 从下面来的,SOC中的CAN和UART1_RXD、UART1_TXD复用。在管脚描述时只用了UART1的名称。但是没有关系只是个名称不影响使用,我们直接选用8、9。

static const struct pinctrl_pin_desc oa**1_pins[] = {
	/* Pins along the ***1 Pin Assignment Table */
	DEFINE_PINCTRL_REG(6, "UART0_RXD", &pin_6_func),
	DEFINE_PINCTRL_REG(7, "UART0_TXD", &pin_7_func),
	DEFINE_PINCTRL_REG(8, "UART1_RXD", &pin_8_func),
	DEFINE_PINCTRL_REG(9, "UART1_TXD", &pin_9_func),
	******

2.在添加DEFINE_OA***1_PINCTRL_GRP(can_1, 1), 注意后面的是1,表明复用选择是复用1而不是上电默认复用0。

static const struct OA***1_pctrl_group OA***1_pctrl_groups[] = {
******
	DEFINE_OA***1_PINCTRL_GRP(can_1, 1),
	DEFINE_OA***1_PINCTRL_GRP(ext_irq, 1),
******	

3.需要确认一下pin_8和pin_9的pin share设置有加入,而且是加入到对应的第二项。

static const struct pin_share_reg pin_8[] = {
	PIN_SHARE_REG(0, 0x190, 4, 0, 0x198, 21, 0),	/* UART1 RXD */
	PIN_SHARE_REG(1, 0x190, 4, 1, 0x198, 21, 0),	/* CAN1 RXD */
	PIN_SHARE_REG(2, 0x190, 4, 0, 0x198, 21, 1),	/* 2ND GPIO 35 */
};
static const struct pin_function pin_8_func = PIN_SHARE_FUN(pin_8);

static const struct pin_share_reg pin_9[] = {
	PIN_SHARE_REG(0, 0x190, 4, 0, 0x198, 22, 0),	/* UART1 TXD */
	PIN_SHARE_REG(1, 0x190, 4, 1, 0x198, 22, 0),	/* CAN1 TXD */
	PIN_SHARE_REG(2, 0x190, 4, 0, 0x198, 22, 1),	/* 2ND GPIO 36 */
};
static const struct pin_function pin_9_func = PIN_SHARE_FUN(pin_9);

4.添加funtion groups 这个部分将和DTS中的管脚复用选择关联。

static const char *const can_1_groups[] = {"can_1_grp"};

5.在定义中加入can_1的枚举(注意该部分和后面的 pmux_functions有关联,添加顺序要对应)

enum oa***1_pmux_functions_e {
*****
	oa***1_pmux_can_0,
	oa***1_pmux_can_1,
	oa***1_pmux_ext_irq,
*****	

5.添加一个const struct 对应的can1 ,需要注意的是这个部分和前面的enum oa***1_pmux_functions_e有关联,相关添加内容位置要对应。

#define DEFINE_OA***1_PINMUX_FUNCTION(fname) \
	[oa***1_pmux_##fname] = { \
		.name = #fname, \
		.groups = fname##_groups, \
		.ngroups = ARRAY_SIZE(fname##_groups), \
	}

static const struct oa***1_pmux_function oa***1_pmux_functions[] = {
	*****
	DEFINE_OA***1_PINCTRL_GRP(can_0, 0),
	DEFINE_OA***1_PINCTRL_GRP(can_1, 1),
	DEFINE_OA***1_PINCTRL_GRP(ext_irq, 1),
	*****

已配置好的管脚复用使用说明

如果相关的管脚配置在程序中已经配置完成了只需在你的DTS对应的模块中添加相关选择:
目录:
在这里插入图片描述
在pinctrl的DST中添加,注意名称对应关系

pinctrl: pinctrl@0xf0c20000 { 
            *****
			mux {
				function = "can_1";//对应驱动中的DEFINE_OA***1_PINCTRL_GRP(can_1, 1),
				groups = "can_1_grp";//对应驱动中的static const char *const can_1_groups[] = {"can_1_grp"};
			};
			*****
		};

例如CAN 添加 pinctrl-0 = <&can_0>; 如果有多个复用pinctrl-names比如有2个,可以继续添加 pinctrl-1 = <&**>对应pinctrl-names的第二个;
这样当初始化该模块功能是对应的Pintrl将自动初始化对应GPIO复用功能。

can1@f0bd0000 {
compatible = “XXX,sja1000”;
reg = <0xf0bd0000 0x4000>;
interrupts = <0 41 4>;
clocks = <&high_apb_clk>;
orbita,external-clock-frequency = <100000000>;
orbita,tx-output-config = <0x16>;
orbita,no-comparator-bypass;
reg-io-width = <0x4>;
pinctrl-names = “default”;
pinctrl-0 = <&can_1>;
status = “okay”;
};

SPI 外扩CAN

&pio {
	exti-nirqs = <16>;
	adc22:adc22{
		pins = "PB5";
		function = "adc22_ir";
	};

	gpio_mcp_out:gpio_mcp_out{//MCP TX PIN
		pins = "PA2", "PA3", "PA4";
		function = "gpio";
		xrobot,drive = <xrobot_PINCTRL_2_MA>;
		xrobot,pull = <xrobot_PINCTRL_PULL_UP>;
	};
};
&spi1 {
	status = "okay";
	compatible = "XXXX,r7-spi";
	dmas = <&dma0 DMA0_HARDTRIG_SRC_SPI1_RX>, <&dma0 DMA0_HARDTRIG_SRC_SPI1_TX>;
	dma-names = "rx", "tx";
	fifo_trig_level = <8>;

	pinctrl-names = "default";
	#if 0
	pinctrl-0 = <&spi1_9 &gpio_mcp_out>;//多个并列
	#else
	pinctrl-0 = <&spi1_9>;
	#endif
	
	//pinctrl-0 = <&spi0_5>;
	//bus-width = <1>;

	mcp251x0: can@1 {
		compatible = "microchip,mcp2515";
		reg = <0>;
		clocks = <&clk20m>;
		reset-gpios = <&pio 5 13 GPIO_ACTIVE_HIGH>; /* PF13 */  	
		interrupt-parent = <&pio>;
		interrupts = <94 IRQ_TYPE_EDGE_FALLING>;/* PF14=16*5+14 */
		spi-max-frequency = <10000000>;
		status = "okay";
	};
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面分别举例说明复用推挽输出和复用开漏输出的使用实例。 1. 复用推挽输出 假设我们需要使用一个单片机控制一个LED灯的开关,并且还需要使用一个按键控制该LED灯的状态切换。通常情况下,我们需要使用两个引脚来实现这个功能,一个引脚用于输出控制信号给LED灯,另一个引脚用于输入按键信号。但是如果引脚资源比较紧张,我们可以使用一个引脚来实现这个功能,做法如下: 将该引脚配置为输出状态时,输出高电平,LED灯亮;输出低电平,LED灯灭。将该引脚配置为输入状态时,读取该引脚的输入状态,如果检测到按键按下,则将该引脚的输出状态反转,从而实现LED灯的状态切换。 这里需要注意的是,当该引脚配置为输出状态时,其输出电平可能会受到其他外部电路的影响,因此需要进行适当的防抖处理。 2. 复用开漏输出 假设我们需要使用一个单片机控制多个LED灯的开关,并且还需要使用一个按键控制这些LED灯的状态切换。如果每个LED灯都需要一个引脚来控制,那么需要的引脚数量将会比较多。为了节省引脚资源,我们可以使用一个引脚来控制多个LED灯的开关,做法如下: 将该引脚配置为开漏输出模式时,输出低电平,所有LED灯都灭;输出高阻态,所有LED灯都不受控制。将该引脚配置为输入状态时,读取该引脚的输入状态,如果检测到按键按下,则将该引脚的输出状态反转,从而实现多个LED灯的状态切换。 这里需要注意的是,开漏输出模式只能输出低电平,因此需要根据实际情况进行逻辑电路设计,并且需要添加外部上拉电阻,以确保该引脚在输出高阻态时不会漂浮。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值