Skip to content

Commit

Permalink
i2c/mcp23017 driver first working version
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelb42 committed Nov 6, 2015
1 parent 0db2c37 commit 41b43ba
Show file tree
Hide file tree
Showing 6 changed files with 738 additions and 0 deletions.
9 changes: 9 additions & 0 deletions doc/Configure.help
Original file line number Diff line number Diff line change
Expand Up @@ -3392,3 +3392,12 @@ CONF_SCHEDULER_NUM_DYNAMIC_TIMERS

Dynamic timers use a few byte RAM per timer.

I2C MCP23017 16-bit port extension
I2C_MCP23017_SUPPORT
Depends on:
* I2C master (I2C_MASTER_SUPPORT)

Microchip MCP23017 16-bit I/O Expander support.

The MCP23017 is a very common and cheap I2C 16-bit I/O expander
available in various packages including PDIP.
3 changes: 3 additions & 0 deletions hardware/i2c/master/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ $(I2C_PCF8574X_SUPPORT)_ECMD_SRC += hardware/i2c/master/i2c_pcf8574x_ecmd.c
$(I2C_MAX7311_SUPPORT)_SRC += hardware/i2c/master/i2c_max7311.c
$(I2C_MAX7311_SUPPORT)_ECMD_SRC += hardware/i2c/master/i2c_max7311_ecmd.c

$(I2C_MCP23017_SUPPORT)_SRC += hardware/i2c/master/i2c_mcp23017.c
$(I2C_MCP23017_SUPPORT)_ECMD_SRC += hardware/i2c/master/i2c_mcp23017_ecmd.c

$(I2C_PCA9685_SUPPORT)_SRC += hardware/i2c/master/i2c_pca9685.c

$(I2C_TMP175_SUPPORT)_SRC += hardware/i2c/master/i2c_tmp175.c
Expand Down
1 change: 1 addition & 0 deletions hardware/i2c/master/config.in
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dep_bool_menu "I2C master" I2C_MASTER_SUPPORT "$(not $I2C_SLAVE_SUPPORT)" $ARCH_
dep_bool "I2C PCF8574X 8-bit port extension" I2C_PCF8574X_SUPPORT $I2C_MASTER_SUPPORT
dep_bool "I2C PCA9555 16-bit port extension" I2C_PCA9555_SUPPORT $I2C_MASTER_SUPPORT
dep_bool "I2C MAX7311 16-bit port extension" I2C_MAX7311_SUPPORT $I2C_MASTER_SUPPORT
dep_bool "I2C MCP23017 16-bit port extension" I2C_MCP23017_SUPPORT $I2C_MASTER_SUPPORT
dep_bool "I2C to UDP gateway" I2C_UDP_SUPPORT $I2C_MASTER_SUPPORT $UDP_SUPPORT
if [ "$I2C_UDP_SUPPORT" = "y" ]; then
int "I2C to UDP gateway port" I2C_PORT 8995 $I2C_UDP_SUPPORT
Expand Down
198 changes: 198 additions & 0 deletions hardware/i2c/master/i2c_mcp23017.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*
*
* Copyright (c) 2015 Michael Brakemeier <michael@brakemeier.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/

#include <util/delay.h>
#include <util/twi.h>

#include "config.h"

#include "core/debug.h"
#include "i2c_master.h"

#include "i2c_mcp23017.h"

#ifdef DEBUG_I2C
#define DEBUG_MCP23017(fnc, msg...) debug_printf("I2C: %s: ", fnc); debug_printf(msg)
#else
#define DEBUG_MCP23017(fnc, msg...)
#endif

/**
* Read data from register reg.
*/
uint8_t
i2c_mcp23017_read_register(uint8_t address, uint8_t reg, uint8_t * data)
{
uint8_t result = 0;

*data = 0;

DEBUG_MCP23017("i2c_mcp23017_read_register",
"addr 0x%02X (%d) reg 0x%02X (%d)\n", address, address, reg,
reg);

/* select slave in write mode */
if (i2c_master_select(address, TW_WRITE))
{
/* send the register address */
TWDR = reg;
if (i2c_master_transmit_with_ack() == TW_MT_DATA_ACK)
{
/* repeated start condition */
if (i2c_master_start() == TW_REP_START)
{
/* select slave in read mode */
TWDR = (uint8_t) (address << 1) | TW_READ;
if (i2c_master_transmit() == TW_MR_SLA_ACK)
{
/* read register */
if (i2c_master_transmit() == TW_MR_DATA_NACK)
{
*data = TWDR;
result = 1;
}
}
}
}
}

/* always send stop */
i2c_master_stop();

DEBUG_MCP23017("i2c_mcp23017_read_register",
"result: %d, data: 0x%02X (%d)\n", result, *data, *data);

return result;
}


/**
* Write data to register reg.
*/
uint8_t
i2c_mcp23017_write_register(uint8_t address, uint8_t reg, uint8_t data)
{
uint8_t result = 0;

DEBUG_MCP23017("i2c_mcp23017_write_register",
"addr 0x%02X (%d) reg 0x%02X (%d) data 0x%02X (%d)\n",
address, address, reg, reg, data, data);

/* select slave in write mode */
if (i2c_master_select(address, TW_WRITE))
{
/* send the register address */
TWDR = reg;
if (i2c_master_transmit_with_ack() == TW_MT_DATA_ACK)
{
/* send data */
TWDR = data;
if (i2c_master_transmit_with_ack() == TW_MT_DATA_ACK)
{
result = 1;
}
}
}

i2c_master_stop();

DEBUG_MCP23017("i2c_mcp23017_write_register", "result: %d\n", result);

return result;
}


/**
* Set or clear pin.
*/
uint8_t
i2c_mcp23017_modify_pin(uint8_t address, uint8_t reg, uint8_t * data,
uint8_t bit, i2c_mcp23017_output_state state)
{
uint8_t tmp;

*data = 0;

/* read-modify-write */
if (i2c_mcp23017_read_register(address, reg, &tmp) > 0)
{
/* bit set, clear or toggle */
switch (state)
{
case ON:
tmp |= (uint8_t) (1 << (bit));
break;
case OFF:
tmp &= (uint8_t) ~ (1 << (bit));
break;
case TOGGLE:
tmp ^= (uint8_t) (1 << (bit));
break;
}

if (i2c_mcp23017_write_register(address, reg, tmp) > 0)
{
*data = tmp;
return 1;
}
}

return 0;
}


/**
* Toggle pin to create a pulse with duration time.
*/
uint8_t
i2c_mcp23017_pulse_pin(uint8_t address, uint8_t reg, uint8_t * data,
uint8_t bit, uint16_t time)
{
uint8_t tmp;

*data = 0;

/* read-modify-write twice */
if (i2c_mcp23017_read_register(address, reg, &tmp) > 0)
{
/* bit flip */
tmp ^= (uint8_t) (1 << (bit));
if (i2c_mcp23017_write_register(address, reg, tmp) > 0)
{
/* and delay... */
while (time--)
_delay_ms(1);
if (i2c_mcp23017_read_register(address, reg, &tmp) > 0)
{
/* flip bit back */
tmp ^= (uint8_t) (1 << (bit));
if (i2c_mcp23017_write_register(address, reg, tmp) > 0)
{
*data = tmp;
return 1;
}
}
}
}

return 0;
}
99 changes: 99 additions & 0 deletions hardware/i2c/master/i2c_mcp23017.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
*
* Copyright (c) 2015 Michael Brakemeier <michael@brakemeier.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* For more information on the GPL, please go to:
* http://www.gnu.org/copyleft/gpl.html
*/

#ifndef I2C_MCP23017_H
#define I2C_MCP23017_H

#include <stdint.h>
#include <avr/io.h>

#include "config.h"

/*
* MCP23017 base address 0x20 - 0x27.
*
* NOTE:
* MCP23017 addresses COLLIDE with those of the PCF8574 I/O Expander!!
*
*/
#define I2C_SLA_MCP23017 0x20

// CONTROL REGISTER SUMMARY (IOCON.BANK = 0)
// Register Address(hex) bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 POR/RST value
#define MCP23017_IODIRA 0x00 // IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
#define MCP23017_IODIRB 0x01 // IO7 IO6 IO5 IO4 IO3 IO2 IO1 IO0 1111 1111
#define MCP23017_IPOLA 0x02 // IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
#define MCP23017_IPOLB 0x03 // IP7 IP6 IP5 IP4 IP3 IP2 IP1 IP0 0000 0000
#define MCP23017_GPINTENA 0x04 // GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
#define MCP23017_GPINTENB 0x05 // GPINT7 GPINT6 GPINT5 GPINT4 GPINT3 GPINT2 GPINT1 GPINT0 0000 0000
#define MCP23017_DEFVALA 0x06 // DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
#define MCP23017_DEFVALB 0x07 // DEF7 DEF6 DEF5 DEF4 DEF3 DEF2 DEF1 DEF0 0000 0000
#define MCP23017_INTCONA 0x08 // IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
#define MCP23017_INTCONB 0x09 // IOC7 IOC6 IOC5 IOC4 IOC3 IOC2 IOC1 IOC0 0000 0000
#define MCP23017_IOCON 0x0A // BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL — 0000 0000
// Note: There is ONE IOCON register only! 0x0A and 0x0B addresses the same register!
// #define MCP23017_IOCON 0x0B // BANK MIRROR SEQOP DISSLW HAEN ODR INTPOL — 0000 0000
#define MCP23017_GPPUA 0x0C // PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
#define MCP23017_GPPUB 0x0D // PU7 PU6 PU5 PU4 PU3 PU2 PU1 PU0 0000 0000
#define MCP23017_INTFA 0x0E // INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
#define MCP23017_INTFB 0x0F // INT7 INT6 INT5 INT4 INT3 INT2 INT1 INTO 0000 0000
#define MCP23017_INTCAPA 0x10 // ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
#define MCP23017_INTCAPB 0x11 // ICP7 ICP6 ICP5 ICP4 ICP3 ICP2 ICP1 ICP0 0000 0000
#define MCP23017_GPIOA 0x12 // GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
#define MCP23017_GPIOB 0x13 // GP7 GP6 GP5 GP4 GP3 GP2 GP1 GP0 0000 0000
#define MCP23017_OLATA 0x14 // OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000
#define MCP23017_OLATB 0x15 // OL7 OL6 OL5 OL4 OL3 OL2 OL1 OL0 0000 0000


typedef enum _i2c_mcp23017_output_state
{
ON,
OFF,
TOGGLE
} i2c_mcp23017_output_state;


/**
* Read data from register reg.
*/
uint8_t i2c_mcp23017_read_register(uint8_t address, uint8_t reg,
uint8_t * data);

/**
* Write data to register reg.
*/
uint8_t i2c_mcp23017_write_register(uint8_t address, uint8_t reg,
uint8_t data);

/**
* Set or clear pin.
*/
uint8_t i2c_mcp23017_modify_pin(uint8_t address, uint8_t reg, uint8_t * data,
uint8_t bit, i2c_mcp23017_output_state state);

/**
* Toggle pin to create a pulse with duration time.
*/
uint8_t i2c_mcp23017_pulse_pin(uint8_t address, uint8_t reg, uint8_t * data,
uint8_t bit, uint16_t time);

#endif /* I2C_MCP23017_H */
Loading

0 comments on commit 41b43ba

Please sign in to comment.