飞思卡尔的芯片与三星的芯片有很大的不同, 从GPIO 的配置上就能看到飞思卡尔有多操蛋.
在本节中我们使用GPIO3-23 来点亮板子上的 ERR-LED.
1. 配置 IOMUX 来选择GPIO模式(IOMUXC), GPIO3-23为普通io口
2. 设置GPIO为输出(GDR)
3. 写DR寄存器
Software Mux Control Registers (SW_MUX_CTL)
选择IO口的工作模式,每一个管脚都对应一个SW_MUX_CTL寄存器
Software Pad Control Registers (SW_PAD_CTL)
设置IO口的驱动电压,回转率,驱动强度,开漏输出,上拉阻值,DDR类型等
关于io口还有8个寄存器如下:
typedef struct
{
unsinged long DR; // lqm:Data register
unsinged long GDIR; // lqm:GPIO Direction register. 0:input 1:output
unsinged long PSR; // lqm:Pad sample register. read only
unsinged long ICR1; // lqm:interrupt control register1
unsinged long ICR2; // lqm:interrupt control register2
unsinged long IMR; // lqm:interrupt mask register
unsinged long ISR; // lqm:interrupt state register
unsinged longEDGE_SEL; // lqm:edge select register
} GPIO_REG, *P_GPIO_REG;
DR表示数据寄存器,也就是IO口的高低电平. 当GPIO口设置为GPIO模式时,若设置为输出,则DR[n]返回该寄存器本身设置的值,若设置为输入,则DR[n]返回该脚外部输入的信号值。当GPIO设置为非GPIO模式时,若设置为输出,则DR[n]返回该寄存器本身设置的值,若设置为输入,则DR[n]固定返回0
GDIR表示方向寄存器,0表示输入,1表示输出, 仅当设置为gpio引脚时该寄存器才有效
PSR为只读寄存器,用户通过读取该寄存器值获取IO口的状态
ICR1,ICR2为中断控制寄存器,表明了中断触发方式
两个32-bit寄存器, 寄存器中每两位控制一条中断线,ICR1控制中断0~15, ICR2控制中断16~31
00中断是low-level触发
01中断是high-level触发
10中断是rise-edge触发
11中断时fall-edge触发
IMR为中断屏蔽寄存器,IMR对应位为0时,表示屏蔽对应GPIO的中断功能,为1时表示使能对应中断功能 , 0中断被屏蔽,
ISR 为中断状态寄存器,ISR对应位为1时,表示对应GPIO中断产生,需要通过软件清零相应位。为0时表示中断未产生。
EDGE_SEL为边沿选择寄存器,EDGE_SEL用于设置GPIO是否使用边沿触发,若对应GPIO口设置为1,表示相应GPIO采用上下沿触发,前面的ICR1,ICR2的设置将变得无效。当EDGE_SEL的对应位恢复为0时,ICR1,ICR2的相应位才会变得有效。
注意: 不论GPIO设置为输入还是输出,在读取GPIO对应的电平值时,都读取PSR的值,尽量不要读取DR的值。而设置IO口的电平时通过设置DR的值来实现。
另外在调试过程中想用P2_8来设置为输入读取高低电平, 模块编译成功且没有错误/警告, 但是在insmod的时候会发生segment fault , 原因是NULL指针
我们先来看普通的io口
gpio_direction_output(IOMUX_TO_GPIO(GPIO3_15), arg);
设置gpio模式, 并设置管脚值 1 或 0
从内核跟踪代码得出:
#define GPIO3_15 MX25_PIN_EXT_ARMCLK
MX25_PIN_EXT_ARMCLK = _MXC_BUILD_GPIO_PIN(2, 15, 0x20c, 0x0),
#define _MXC_BUILD_GPIO_PIN(gp,gi,mi,mf,pi,pf) _MXC_BUILD_PIN(gp,gi,mi,mf,pi,pf)
_MXC_BUILD_GPIO_PIN(2, 15, 0x20c, 0x0),
_MXC_BUILD_GPIO_PIN(端口-1, 引脚值, IOMUXC_SW_MUX_CTL_PAD_xxx偏移值, IOMUXC_SW_PAD_CTL_PAD_xxx偏移值), 见4-24页. 注意这里的引脚值不是全局的引脚值而是各个端口的引脚 如GPIO3-15, 这里引脚值就是15
内核为每个多路复用io组织数据的格式为:
例如 MX25_PIN_A14 引脚:
0x0010 IOMUXC_SW_MUX_CTL_PAD_A14
0x0230 IOMUXC_SW_PAD_CTL_PAD_A14
#define _MXC_BUILD__PIN(1, 0, 0x10, 0x230) ((1 << 29) | (0 << 24) | ( 0x10 << 10) | ( 0x230 << 0))
#define _MXC_BUILD_PIN(2, 15, 0x20c, 0x0) (((2) << 29) | ((15) << 24) | ((0) << 10) | ((0x20c) << 0))
P2_8不能调用mxc_iomux_set_pad 原因:
中间木有A22 这个A22就是P2_8
飞思卡尔在移植的时候这里直接给的是 0,然后代码里没有判断0 直接NULL insmod的时候就segment fault了
在arch\arm\mach-mx25\mx25_pins.h的 enum iomux_pins {...}里
像这种最后参数是0的 都不能调用 mxc_iomux_set_pad 方法 ,不然在insmod的时候会出段错误
_MXC_BUILD_GPIO_PIN(端口-1, 引脚值, IOMUXC_SW_MUX_CTL_PAD_xxx寄存器偏移值, IOMUXC_SW_PAD_CTL_PAD_xxx寄存器偏移值)
一下为追踪代码的过程:
- /********************************************************************************************************************/
- gpio_direction_output(IOMUX_TO_GPIO(GPIO3_15), arg);
- #define MUX_IO_P 29
- #define MUX_IO_I 24
- #define IOMUX_TO_GPIO(pin) ((((unsigned int)pin >> 29) << 5) + ((pin >> 24) & ((1 << (29 - 24)) -1)))
- #define GPIO3_15 MX25_PIN_EXT_ARMCLK
- MX25_PIN_EXT_ARMCLK = _MXC_BUILD_GPIO_PIN(2, 15, 0x20c, 0x0),
- #define _MXC_BUILD_GPIO_PIN(gp,gi,mi,mf,pi,pf) _MXC_BUILD_PIN(gp,gi,mi,mf,pi,pf)
- _MXC_BUILD_GPIO_PIN(2, 15, 0x20c, 0x0),
- #define _MXC_BUILD_PIN(gp, gi, mi, pi) (((2) << 29) | ((15) << 24) | ((0) << 10) | ((0x20c) << 0))
- gpio_direction_output((((2 << 29) | (15 << 24) | (0x20c << 0) | (0 << 10)) & (0xff << 9)) >> 9), 0)
- struct gpio_chip {
- int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value);
- port[i].chip.direction_output = mxc_gpio_direction_output;
- static int mxc_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
- {
- mxc_gpio_set(chip, offset, value);
- _set_gpio_direction(chip, offset, 1);
- return 0;
- }
- static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
- {
- struct mxc_gpio_port *port = container_of(chip, struct mxc_gpio_port, chip);
- void __iomem *reg = port->base + GPIO_DR;//mx25.h第438行 #define GPIO_DR 0x00
- u32 l;
- l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
- __raw_writel(l, reg);
- }
- static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, int dir)
- {
- struct mxc_gpio_port *port =
- container_of(chip, struct mxc_gpio_port, chip);
- u32 l;
- l = __raw_readl(port->base + GPIO_GDIR);
- if (dir)
- l |= 1 << offset;
- else
- l &= ~(1 << offset);
- __raw_writel(l, port->base + GPIO_GDIR);
- }
- /********************************************************************************************************************/
- /********************************************************************************************************************/
- http://blog.youkuaiyun.com/maopig/article/details/7428561
- mxc_request_iomux(MX25_PIN_EB0, MUX_CONFIG_ALT4); /*SSI4_STXD*/
- iomux_config_mux(pin, cfg);
- __raw_writel(cfg, mux_reg);
- gpio_request(IOMUX_TO_GPIO(pin), NULL);
- /********************************************************************************************************************/
- mxc_iomux_set_pad(MX25_PIN_A14, PAD_CTL_PKE_ENABLE );
- mxc_iomux_set_pad分析记录
- http://www.xuebuyuan.com/642369.html
- void mxc_iomux_set_pad(iomux_pin_name_t pin, u32 config)
- {
- void *pad_reg = IOMUXGPR + PIN_TO_IOMUX_PAD(pin);
- => mux_reg = base + 0x00000230
- BUG_ON((pad_reg > IOMUXSW_PAD_END) || (pad_reg < IOMUXSW_PAD_CTL));
- __raw_writel(config, pad_reg);
- }
- /********************************************************************************************************************/
- //1 选择io口的功能
- //配置IOMUX寄存器,把MX51_PIN_AUD3_BB_CK引脚配置为GPIO
- mxc_request_iomux(MX51_PIN_AUD3_BB_CK,IOMUX_CONFIG_GPIO);
- //linux系统通用的GPIO的操作函数,她的入口是个int的整型的数,所以需要使用IOMUX_TO_GPIO(MX51_PIN_AUD3_BB_CK)函数来转换。 “BB_CK”只是一个字符标记,填写什么内容都可以
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_AUD3_BB_CK), "BB_CK");
- //设置GPIO的方向
- gpio_direction_output(IOMUX_TO_GPIO((MX51_PIN_AUD3_BB_CK), ), 0);
- gpio_set_value(IOMUX_TO_GPIO((MX51_PIN_AUD3_BB_CK)), 1); //IO置高的操作
- gpio_set_value(IOMUX_TO_GPIO((MX51_PIN_AUD3_BB_CK)), 0); //IO置低的操作
- /* bug P2_8 */
- printk (KERN_ALERT "IOMUXGPR + PIN_TO_IOMUX_PAD(pin) = %p", IO_ADDRESS(0x43fac000) + PIN_TO_IOMUX_PAD(GPIO2_8));
- GPIO2_8
- _MXC_BUILD_GPIO_PIN(1, 8, 0x30, 0x0)
- _MXC_BUILD_PIN(1, 8, 0x30, 0x0)
- ((1 << 29) | (8 << 24) | (0x30 << 0) | (0 << 10)) => 0x28000030
- #define PIN_TO_IOMUX_PAD(0x28000030) ((0x28000030 >> 10) & ((1<<(21 - 10)) - 1))