i.mx257的gpio简要理解

飞思卡尔的芯片与三星的芯片有很大的不同, 从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类型等

i.mx257的gpio简要理解_第1张图片

i.mx257的gpio简要理解_第2张图片

关于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寄存器偏移值)


一下为追踪代码的过程:

[cpp] view plain copy print ?
  1. /********************************************************************************************************************/
  2. gpio_direction_output(IOMUX_TO_GPIO(GPIO3_15), arg);
  3. #define MUX_IO_P 29
  4. #define MUX_IO_I 24
  5. #define IOMUX_TO_GPIO(pin) ((((unsigned int)pin >> 29) << 5) + ((pin >> 24) & ((1 << (29 - 24)) -1)))
  6. #define GPIO3_15 MX25_PIN_EXT_ARMCLK
  7. MX25_PIN_EXT_ARMCLK = _MXC_BUILD_GPIO_PIN(2, 15, 0x20c, 0x0),
  8. #define _MXC_BUILD_GPIO_PIN(gp,gi,mi,mf,pi,pf) _MXC_BUILD_PIN(gp,gi,mi,mf,pi,pf)
  9. _MXC_BUILD_GPIO_PIN(2, 15, 0x20c, 0x0),
  10. #define _MXC_BUILD_PIN(gp, gi, mi, pi) (((2) << 29) | ((15) << 24) | ((0) << 10) | ((0x20c) << 0))
  11. gpio_direction_output((((2 << 29) | (15 << 24) | (0x20c << 0) | (0 << 10)) & (0xff << 9)) >> 9), 0)
  12. struct gpio_chip {
  13. int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value);
  14. port[i].chip.direction_output = mxc_gpio_direction_output;
  15. static int mxc_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
  16. {
  17. mxc_gpio_set(chip, offset, value);
  18. _set_gpio_direction(chip, offset, 1);
  19. return 0;
  20. }
  21. static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  22. {
  23. struct mxc_gpio_port *port = container_of(chip, struct mxc_gpio_port, chip);
  24. void __iomem *reg = port->base + GPIO_DR;//mx25.h第438行 #define GPIO_DR 0x00
  25. u32 l;
  26. l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
  27. __raw_writel(l, reg);
  28. }
  29. static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, int dir)
  30. {
  31. struct mxc_gpio_port *port =
  32. container_of(chip, struct mxc_gpio_port, chip);
  33. u32 l;
  34. l = __raw_readl(port->base + GPIO_GDIR);
  35. if (dir)
  36. l |= 1 << offset;
  37. else
  38. l &= ~(1 << offset);
  39. __raw_writel(l, port->base + GPIO_GDIR);
  40. }
  41. /********************************************************************************************************************/
  42. /********************************************************************************************************************/
  43. http://blog.csdn.net/maopig/article/details/7428561
  44. mxc_request_iomux(MX25_PIN_EB0, MUX_CONFIG_ALT4); /*SSI4_STXD*/
  45. iomux_config_mux(pin, cfg);
  46. __raw_writel(cfg, mux_reg);
  47. gpio_request(IOMUX_TO_GPIO(pin), NULL);
  48. /********************************************************************************************************************/
  49. mxc_iomux_set_pad(MX25_PIN_A14, PAD_CTL_PKE_ENABLE );
  50. mxc_iomux_set_pad分析记录
  51. http://www.xuebuyuan.com/642369.html
  52. void mxc_iomux_set_pad(iomux_pin_name_t pin, u32 config)
  53. {
  54. void *pad_reg = IOMUXGPR + PIN_TO_IOMUX_PAD(pin);
  55. => mux_reg = base + 0x00000230
  56. BUG_ON((pad_reg > IOMUXSW_PAD_END) || (pad_reg < IOMUXSW_PAD_CTL));
  57. __raw_writel(config, pad_reg);
  58. }
  59. /********************************************************************************************************************/
  60. //1 选择io口的功能
  61. //配置IOMUX寄存器,把MX51_PIN_AUD3_BB_CK引脚配置为GPIO
  62. mxc_request_iomux(MX51_PIN_AUD3_BB_CK,IOMUX_CONFIG_GPIO);
  63. //linux系统通用的GPIO的操作函数,她的入口是个int的整型的数,所以需要使用IOMUX_TO_GPIO(MX51_PIN_AUD3_BB_CK)函数来转换。 “BB_CK”只是一个字符标记,填写什么内容都可以
  64. gpio_request(IOMUX_TO_GPIO(MX51_PIN_AUD3_BB_CK), "BB_CK");
  65. //设置GPIO的方向
  66. gpio_direction_output(IOMUX_TO_GPIO((MX51_PIN_AUD3_BB_CK), ), 0);
  67. gpio_set_value(IOMUX_TO_GPIO((MX51_PIN_AUD3_BB_CK)), 1); //IO置高的操作
  68. gpio_set_value(IOMUX_TO_GPIO((MX51_PIN_AUD3_BB_CK)), 0); //IO置低的操作
  69. /* bug P2_8 */
  70. printk (KERN_ALERT "IOMUXGPR + PIN_TO_IOMUX_PAD(pin) = %p", IO_ADDRESS(0x43fac000) + PIN_TO_IOMUX_PAD(GPIO2_8));
  71. GPIO2_8
  72. _MXC_BUILD_GPIO_PIN(1, 8, 0x30, 0x0)
  73. _MXC_BUILD_PIN(1, 8, 0x30, 0x0)
  74. ((1 << 29) | (8 << 24) | (0x30 << 0) | (0 << 10)) => 0x28000030
  75. #define PIN_TO_IOMUX_PAD(0x28000030) ((0x28000030 >> 10) & ((1<<(21 - 10)) - 1))

你可能感兴趣的:(i.mx257的gpio简要理解)