MT7621 openWrt插件操作GPIO(mmap)
OpenWrt 应用中操作GPIO的方式多数都是:
- 修改设备树
- 通过shell脚本export出对应的GPIO
- 通过shell脚本或操作文件的方式控制GPIO/通过LEDE LED配置控制GPIO
不用这种方式的时候,通常按照Linux方式先写驱动,然后在应用/插件中调用驱动程序接口控制GPIO
以上方式的例程和资料网上很容易找,英文阅读没问题的话,直接看官方资料就可以轻松搞定;
最近项目需要在OpenWrt 插件中根据运行情况和指令直接操作GPIO,不想写驱动;参考了网上的资料,没折腾就成功了
这种方式的好处是不用改设备树和写驱动,减少了代码维护的复杂度;用写寄存器的方式控制GPIO,速度应该快点
坏处是对对寄存器不熟悉的新手不太友好
使用基本只需要根据芯片资料修改一下代码中的寄存器相关的宏定义和mmap函数中的offset地址即可;
如果是MTK相关的芯片,直接根据芯片资料修改mmap函数中的offset地址
原代码针对的是MT7628, GPIO BASE ADDRESS 为0x10000600,故offset设为0x10000000,
而MT7621的 GPIO BASE ADDRESS 为0x1E000600,故offset设为0x1e0000000
详细代码请自行查看下方参考代码对应的github项目链接;
下方的代码非原创,完全抄袭,仅修改了函数名(原函数名前有mt7628_)和增加一条注释,
原作者未使用license,若下方代码涉及侵权, 请站内消息联系删除
static int gpio_mmap(void)
{
if ((gpio_mmap_fd = open(MMAP_PATH, O_RDWR)) < 0) {
fprintf(stderr, "unable to open mmap file");
return -1;
}
gpio_mmap_reg = (uint8_t*) mmap(NULL, 1024, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, gpio_mmap_fd, 0x1e000000);//MT7628则offset为0x10000000
if (gpio_mmap_reg == MAP_FAILED) {
perror("foo");
fprintf(stderr, "failed to mmap");
gpio_mmap_reg = NULL;
close(gpio_mmap_fd);
return -1;
}
return 0;
}
int gpio_get_pin(int pin)
{
uint32_t tmp = 0;
/* MT7621, MT7628 */
if (pin <= 31) {
tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIODATA);
tmp = (tmp >> pin) & 1u;
} else if (pin <= 63) {
tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332DATA);
tmp = (tmp >> (pin-32)) & 1u;
} else if (pin <= 95) {
tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564DATA);
tmp = (tmp >> (pin-64)) & 1u;
tmp = (tmp >> (pin-24)) & 1u;
}
return tmp;
}
void gpio_set_pin_direction(int pin, int is_output)
{
uint32_t tmp;
/* MT7621, MT7628 */
if (pin <= 31) {
tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIODIR);
if (is_output)
tmp |= (1u << pin);
else
tmp &= ~(1u << pin);
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIODIR) = tmp;
} else if (pin <= 63) {
tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332DIR);
if (is_output)
tmp |= (1u << (pin-32));
else
tmp &= ~(1u << (pin-32));
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332DIR) = tmp;
} else if (pin <= 95) {
tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564DIR);
if (is_output)
tmp |= (1u << (pin-64));
else
tmp &= ~(1u << (pin-64));
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564DIR) = tmp;
}
}
void gpio_set_pin_value(int pin, int value)
{
uint32_t tmp;
/* MT7621, MT7628 */
if (pin <= 31) {
tmp = (1u << pin);
if (value)
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIOSET) = tmp;
else
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIORESET) = tmp;
} else if (pin <= 63) {
tmp = (1u << (pin-32));
if (value)
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332SET) = tmp;
else
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332RESET) = tmp;
} else if (pin <= 95) {
tmp = (1u << (pin-64));
if (value)
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564SET) = tmp;
else
*(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564RESET) = tmp;
}
}