首先要学会看手册,下面拿PC来做说明。
3.18.3. Register List
Module Name Base Address
PIO 0x01C20800
Register Name Offset Description
Pn_CFG0 0x0000+N*0x24 Port n Configure Register 0 (N from 0 to 8)
Pn_CFG1 0x0004+N*0x24 Port n Configure Register 1 (N from 0 to 8)
Pn_CFG2 0x0008+N*0x24 Port n Configure Register 2 (N from 0 to 8)
Pn_CFG3 0x000C+N*0x24 Port n Configure Register 3 (N from 0 to 8)
Pn_DAT 0x0010+N*0x24 Port n Data Register (N from 0 to 8)
Pn_DRV0 0x0014+N*0x24 Port n Multi-Driving Register 0 (N from 0 to 8)
Pn_DRV1 0x0018+N*0x24 Port n Multi-Driving Register 1 (N from 0 to 8)
Pn_PUL0 0x001C+N*0x24 Port n Pull Register 0 (N from 0 to 8)
Pn_PUL1 0x0020+N*0x24 Port n Pull Register 1 (N from 0 to 8)
PIO_INT_CFG0 0x0200 PIO Interrupt Configure Register 0
PIO_INT_CFG1 0x0204 PIO Interrupt Configure Register 1
PIO_INT_CFG2 0x0208 PIO Interrupt Configure Register 2
PIO_INT_CFG3 0x020C PIO Interrupt Configure Register 3
PIO_INT_CTL 0x0210 PIO Interrupt Control Register
PIO_INT_STA 0x0214 PIO Interrupt Status Register
PIO_INT_DEB 0x0218 PIO Interrupt Debounce Register
通过上面表格可以看出 gpio的基地址是0x01C20800,后面所有的IO地址都是在次基础上计算得出,Pn_CFG0 表示功能分配,控制8个管脚,该8个管脚为一组,用4字节存储,共32位,每4位表示一个管脚的功能定义。Pn_DAT 表示数据,Pn_DRV0 表示驱动能力,Pn_PUL0 表示内部上拉下拉。
下面看PC
PC Configure Register 0(Default Value: 0x7777_7777)
寄存器0的默认值都为7,也就是8个脚的功能配置都是7,7是什么含义需要看具体的解析,下面会分析。如果PC的管脚多,就需要多个寄存器,因为PC有25个脚,所以需要4个寄存器,register0-3。
Offset: 0x0048 Register Name: PC_CFG0
Bit Read/Write Default/Hex Description
31 / / /
30:28 R/W 0x7 PC7_SELECT
000: Input 001: Output
010: NRB1 011: SDC2_CLK
100: Reserved 101: Reserved
110: Reserved 111: IO Disable
offset :0x0048,表示偏移量,是针对上面基地址的。
这个是PC7的功能配置寄存器, 因为每个脚的功能选择都是4位来存储,由于只有7种功能,所以只用后三位即可,第31位不用配,30-28三位根据填写,后面是具体描述,如果配置成输出,该4位的值位0001,看默认值是7,那就是使用了IO Disable功能。 其它功能脚的定义类似。
下面看看内部上拉下拉的配置
3.18.4.27. PC Pull Register 1(Default Value: 0x0000_4016)
Offset: 0x0068 Register Name: PC_PULL1
Bit Read/Write Default/Hex Description
31:18 / / /
[2i+1:2i] R/W 0x4016 PC_PULL
(i=0~8) PC[n] Pull-up/down Select (n = 16~24)
00: Pull-up/down disable 01: Pull-up
10: Pull-down 11: Reserved
内部上拉下拉默认值为0x00004016 ,它有两位表示上拉下来状态,因为pc有25个脚,所以 PC Pull Register 0表示 0-15脚的状态。 而现在Register 1则表示剩下的9个脚,用4字节32位的后18位即可,所以31:18这14位为空,用 / 表示。
从低位往高位数,每两位表示一个PC脚的上拉下拉状态,,具体值的说明右边以给出。可以进一步分析刚才那个默认值,对应的具体的管脚的内部pull状态。
分析一下下面代码
#define SUNXI_PIO_BASE 0x01c20800
void spi_gpio_cfg(int spi_no)
{
uint reg_val = 0;
uint reg_addr;
// PIO SETTING,PortC0:2 SPI0_MOSI SPI0_MISO SPIO_CLK
reg_addr = SUNXI_PIO_BASE + 0x48; //找到PC功能配置的地址
reg_val = readl(reg_addr); //将该PC_CFG0对应的4字节读出来
reg_val &= ~(0xfff); //因为4位表示一个脚,这里是清空pc0,pc1,pc2
reg_val |= 0x333; //将pc0 ,pc1,pc2, 配置成功能3
writel(reg_val, reg_addr); //将修改后的值写
// PIO SETTING,PortC23 SPI0_CS0
reg_addr = SUNXI_PIO_BASE + 0x50; //偏移0x50是PC_CFG2,这里8个脚是pc16-23
reg_val = readl(reg_addr); //同上,取出PC_CFG2的数据
reg_val &= ~(0xf<<28); //左移28位,清空改组第八个脚即pc23
reg_val |= 0x3<<28; //将pc23的功能配置为3
writel(reg_val, reg_addr); //写入
// PIO SETTING,PortC SPI0 pull reg
reg_val = readl(SUNXI_PIO_BASE + 0x68); //偏移0x68是PC_PULL1,也就是pc16-24 的pull功能,,取出数据
reg_val &= ~(0x03 << 14); //左移14位,清空 pc23 的pull寄存器
reg_val |= (0x01 << 14); //左移14位,将pc23 的pull寄存器设置1,即内部上拉
writel(reg_val, (SUNXI_PIO_BASE + 0x68)); //写入
SUNXI_DEBUG("Reg pull reg_val=0x%x,read=0x%x\n",reg_val,readl((0x1c20800 + 0x68)));
}
通过上面的代码分析,基本搞定寄存器地址与内容的联系。