I/O芯片扩展开发

QCA9563外接I/O扩展芯片

  • 概述
  • 实现
  • 总结

概述

CPU上的GPIO口特别有限,所以想着给现有的单板做一个I/O扩展。方案是QCA9563通过I2C,外接MCP23017,可以外出16路I/O口。配置I/O口为固定方向,8个为一组,一组输出一组输入。

实现

刚开始打算直接通过QCA9563自带的I2C口控制器进行控制MCP23017芯片,但是在开发的过程中才发现没有I2C控制器驱动代码。可能由于这款芯片太新了,开源代码还没有适配,最后想着用GPIO模拟I2C的方式进行控制的。

  1. 首先选中GPIO模拟I2C驱动部分
    I/O芯片扩展开发_第1张图片
  2. 注册I2C设备
    static struct ath79_i2c_platform_data ath79_i2c_pdata = {
    .sda_pin = 5,//选中的GPIO口,串行数据线
    .scl_pin = 6,//选中的GPIO口,串行时钟线
    .udelay = 5,
    .timeout = 100,
    .sda_is_open_drain = 1,
    .scl_is_open_drain = 1,
    };
    static struct resource ath79_i2c_resources[] = {
    	{
    		.flags = IORESOURCE_MEM,
    		.start = AR71XX_GPIO_BASE,
    		.end = AR71XX_GPIO_BASE + AR71XX_GPIO_SIZE - 1,
    	},
    	{
    		.start	= ATH79_MISC_IRQ(8),
    		.end	= ATH79_MISC_IRQ(8),
    		.flags	= IORESOURCE_IRQ,
    	},
    };
    static struct platform_device ath79_i2c_device = {
    	.name		= "i2c-gpio",
    	.id		= -1,
    	.resource	= ath79_i2c_resources,
    	.num_resources	= ARRAY_SIZE(ath79_i2c_resources),
    	.dev = {
    		.platform_data	= &ath79_i2c_pdata
    	},
    };
    platform_device_register(&ath79_i2c_device);
    
    驱动跑起来之后,会创建一个i2c设备/dev/i2c-0.
  3. 应用层开发
    提供读写接口:
    #define MCP23017_ADDRESS 0x20 /* mcp23017 address 通过查手册和硬件走线即可确定*/
    //通过/dev/i2c-0设备进行读
    int mcp23017_read(unsigned char regaddr, unsigned char *value)
    {
        int ret = 0;
        /* read data from mcp23017 */
        /* we used to start singnal */
        memset(buf1, 0, sizeof(buf1));
        memset(buf2, 0, sizeof(buf2));
        i2c_data.nmsgs = 2;
        i2c_data.msgs[0].len = 1;
        i2c_data.msgs[0].addr = MCP23017_ADDRESS;
        i2c_data.msgs[0].flags = 0;     /* write */
        i2c_data.msgs[0].buf = buf1;
        buf1[0] = regaddr;   /* regaddr */
        
        i2c_data.msgs[1].len = 1;   /* test read twice ,2 */
        i2c_data.msgs[1].addr = 0x20;
        i2c_data.msgs[1].flags = I2C_M_RD;
        i2c_data.msgs[1].buf = buf2;   /* read buff */
    
        ret = ioctl (i2c_fd, I2C_RDWR, (unsigned long)&i2c_data);
        if (ret < 0)
        {
    #ifdef IOEXTEND_DEBUG
            print_file("[%s %d]ioctl read error\n", __FILE__, __LINE__);
    #endif
            return RET_ERR;
        }
    
        *value = buf2[0];
    #ifdef IOEXTEND_DEBUG
        print_file("[%s %d]%s value:0x%2x\n", __FILE__, __LINE__, register_to_string[regaddr], buf2[0]);
    #endif
        return RET_OK;
    }
    
    //通过/dev/i2c-0设备进行写
    int mcp23017_write(unsigned char regaddr, unsigned char value)
    {
        int ret = 0;
        /* write data to mcp23017 */
        i2c_data.nmsgs = 1;
        i2c_data.msgs[0].len = 2;
        i2c_data.msgs[0].addr = MCP23017_ADDRESS;  /* 0100 A2A1A0 R/W  7-bit i2c addresses */
        i2c_data.msgs[0].flags = 0;   /* write */
        i2c_data.msgs[0].buf = buf1;
        buf1[0] = regaddr;  /* regaddr*/
        buf1[1] = value;   /* write value */
    
        ret = ioctl (i2c_fd, I2C_RDWR, (unsigned long)&i2c_data);
        if (ret < 0)
        {
    #ifdef IOEXTEND_DEBUG
            print_file("[%s %d]ioctl read error\n", __FILE__, __LINE__);
    #endif
            return RET_ERR;
        }
        return RET_OK;
    }
    
    //初始化/dev/i2c-0
    int mcp23017_init()
    {
        i2c_fd = open("/dev/i2c-0", O_RDWR);
        if (i2c_fd < 0)
        {
    #ifdef IOEXTEND_DEBUG
            print_file("[%s %d]Error on opening the /dev/i2c-0 file i2c_fd:%d\n", __FILE__, __LINE__, i2c_fd);
    #endif
            return RET_ERR;
        }
        ioctl(i2c_fd, I2C_TIMEOUT, 2);
        ioctl(i2c_fd, I2C_RETRIES, 1);
    
        i2c_data.nmsgs = 2;
        i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs * sizeof(struct i2c_msg));
        if (!i2c_data.msgs)
        {
    #ifdef IOEXTEND_DEBUG
            print_file("[%s %d]Memory alloc error\n", __FILE__, __LINE__);  
    #endif
            close(i2c_fd);
            return RET_ERR;
        }
        mcp23017_write(REG_IODIRA, 0x00); /* out put module */
        mcp23017_write(REG_IODIRB, 0xff);  /* in put module */
        mcp23017_write(REG_GPIOA,  0xff);
        return RET_OK;
    }
    

总结

通过read、write接口就可以控制MCP23017芯片,如果想要实时获取芯片上的状态,需要把芯片上的中断引脚解出来,根据中断来读。或者采用轮询模式进行读状态。

你可能感兴趣的:(以太网驱动开发)