A library for the Microchip MCP23008 I2C 8-bit I/O expander.

MCP23008.cpp

Committer:
dewyatt
Date:
2012-06-15
Revision:
0:4f712bd739d0

File content as of revision 0:4f712bd739d0:

#include "MCP23008.hpp"

namespace {
const uint8_t MCP23008_ADDRESS  = 0x40;

/* MCP23008 registers */
const uint8_t IODIR             = 0x00;
const uint8_t IPOL              = 0x01;
const uint8_t GPINTEN           = 0x02;
const uint8_t DEFVAL            = 0x03;
const uint8_t INTCON            = 0x04;
const uint8_t IOCON             = 0x05;
const uint8_t GPPU              = 0x06;
const uint8_t INTF              = 0x07;
const uint8_t INTCAP            = 0x08;
const uint8_t GPIO              = 0x09;
const uint8_t OLAT              = 0x0A;
};

MCP23008::MCP23008 ( PinName sda, PinName scl, uint8_t address, Frequency freq )
        : i2c ( sda, scl ),
        i2c_address ( MCP23008_ADDRESS | address ) {
    if ( address > 7 )
        error ( "MCP23008::MCP23008: address is out of range, must be <= 7\n" );

    i2c.frequency ( ( int ) freq );
    reset ();
}

void MCP23008::set_input_pins ( uint8_t pins ) {
    uint8_t value = read_register ( IODIR );
    write_register ( IODIR, value | pins );
}

void MCP23008::set_output_pins ( uint8_t pins ) {
    uint8_t value = read_register ( IODIR );
    write_register ( IODIR, value & ~pins );
}

void MCP23008::write_outputs ( uint8_t values ) {
    write_register ( GPIO, values );
}

uint8_t MCP23008::read_outputs () {
    return read_register ( OLAT );
}

uint8_t MCP23008::read_inputs () {
    return read_register ( GPIO );
}

void MCP23008::set_input_polarity ( uint8_t values ) {
    write_register ( IPOL, values );
}

uint8_t MCP23008::get_input_polarity () {
    return read_register ( IPOL );
}

void MCP23008::set_pullups ( uint8_t values ) {
    write_register ( GPPU, values );
}

uint8_t MCP23008::get_pullups () {
    return read_register ( GPPU );
}

void MCP23008::interrupt_on_changes ( uint8_t pins ) {
    uint8_t value = read_register ( INTCON );
    value &= ~pins;
    write_register ( INTCON, value );
    value = read_register ( GPINTEN );
    value |= pins;
    write_register ( GPINTEN, value );
}

void MCP23008::disable_interrupts ( uint8_t pins ) {
    uint8_t value = read_register ( GPINTEN );
    value &= ~pins;
    write_register ( GPINTEN, value );
}

void MCP23008::acknowledge_interrupt ( uint8_t &pin, uint8_t &values ) {
    pin = read_register ( INTF );
    values = read_register ( INTCAP );
}

uint8_t MCP23008::read_register ( uint8_t reg ) {
    char data[] = {reg};
    if ( 0 != i2c.write ( i2c_address, data, 1 ) )
        error ( "MCP23008::read_register: Missing ACK for write\n" );

    if ( 0 != i2c.read ( i2c_address, data, 1 ) )
        error ( "MCP23008:read_register: Missing ACK for read\n" );

    return data[0];
}

void MCP23008::write_register ( uint8_t reg, uint8_t value ) {
    char data[] = {reg, value};
    if ( 0 != i2c.write ( i2c_address, data, 2 ) )
        error ( "MCP23008::write_register: Missing ACK for write\n" );
}

void MCP23008::write_mask ( uint8_t reg, uint8_t mask, bool value ) {
    uint8_t val;
    val = read_register ( reg );
    if ( value )
        val |= mask;
    else
        val &= ~mask;

    write_register ( reg, val );
}

void MCP23008::reset ( ) {
    write_register ( IODIR, 0xFF );
    for ( uint8_t reg = IPOL; reg <= OLAT; reg++ )
        write_register ( reg, 0 );
}