最近研究freescale的i.MX25系列处理器,发现在控制方面很多地方和三星的处理器都不太一样。包括最基础的GPIO口控制,也是大不相同。
i.MX25系列的GPIO口大多是复用口,如果我们想将某IO口设置为输入或输出,首先需通过复用配置寄存器将该IO口配置为GPIO,然后再配置GPIO的相关寄存器。
通过配置SW_MUX_CTL寄存器选择IO口的工作模式,每一个管脚都对应一个SW_MUX_CTL寄存器,具体通过如下描述:
IOMUXC_SW_MUX_CTL_PAD_<Pin_Name>
这里<Pin_Name>为管脚名。寄存器对应描述见表1:
表1:SW_MUX_CTL寄存器描述
通过配置SW_PAD_CTL设置IO口的驱动电压,回转率,驱动强度,开漏,上拉,DDR类型等。有些管脚需要通过SW_PAD_CTL_GRP设置一组IO口。SW_PAD_CTL寄存器通过如下描述:
IOMUXC_SW_PAD_CTL_PAD_<Pin_Name>
这里<Pin_Name>为管脚名。寄存器对应描述见表2及表3:
表2:SW_PAD_CTL寄存器描述(一)
表3:SW_PAD_CTL寄存器描述(二)
这里DDR相关管脚比较特殊,其寄存器描述有所不同,见表4所示:
表4:DDR对应SW_PAD_CTL寄存器描述
有些IO口需要成组设置,具体各自寄存器设置可查看i.MX25手册。
关于各IO口具体复用的功能,以及如何设置SW_MUX_CTL来决定IO口模式,可查看i.MX25手册的表4-18[IMX25RM.pdf]。
例如我们需要设置某IO口为输入或输出,首先通过上面的方法设置完复用功能相关寄存器,接着要设置GPIO的相关寄存器。每个GPIO都对应有8个寄存器设置,在程序中通过结构体封装如下:
typedef struct
{
UINT32 DR; // lqm:Data register
UINT32 GDIR; // lqm:GPIO Direction register. 0:input 1:output
UINT32 PSR; // lqm:Pad sample register. read only
UINT32 ICR1; // lqm:interrupt control register1
UINT32 ICR2; // lqm:interrupt control register2
UINT32 IMR; // lqm:interrupt mask register
UINT32 ISR; // lqm:interrupt state register
UINT32 EDGE_SEL; // lqm:edge select register
} CSP_GPIO_REGS, *PCSP_GPIO_REGS;
其中DR表示数据寄存器,也就是IO口的高低电平。GDIR表示方向寄存器,0表示输入,1表示输出。PSR为只读寄存器,用户通过读取该寄存器值获取IO口的状态。ICR1,ICR2为中断控制寄存器,表明了中断触发方式;IMR为中断屏蔽寄存器,ISR为中断状态寄存器,EDGE_SEL为边沿选择寄存器。
当GPIO口设置为GPIO模式时,若设置为输出,则DR[n]返回该寄存器本身设置的值,若设置为输入,则DR[n]返回该脚外部输入的信号值。
当GPIO设置为非GPIO模式时,若设置为输出,则DR[n]返回该寄存器本身设置的值,若设置为输入,则DR[n]固定返回0。
ICR1描述了GPIO[0:15]的中断触发方式,具体见表5:
表5:中断触发方式
ICR2描述了GPIO[16:31]的中断触发方式,具体见表6:
表6:中断触发方式
IMR对应位为0时,表示屏蔽对应GPIO的中断功能,为1时表示使能对应中断功能。ISR对应位为1时,表示对应GPIO中断产生,需要通过软件清零相应位。为0时表示中断未产生。
EDGE_SEL用于设置GPIO是否使用边沿触发,若对应GPIO口设置为1,表示相应GPIO采用上下沿触发,前面的ICR1,ICR2的设置将变得无效。当EDGE_SEL的对应位恢复为0时,ICR1,ICR2的相应位才会变得有效。
不论GPIO设置为输入还是输出,在读取GPIO对应的电平值时,都读取PSR的值,尽量不要读取DR的值。而设置IO口的电平时通过设置DR的值来实现。