Rev 31 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| Download
| RSS feed
/**************************************************************************//**
* \brief MCP23008 library
* \author Copyright (C) 2012 Julien Le Sech - www.idreammicro.com
* \version 1.0
* \date 201201025
*
* This file is part of the iDreamMicro library.
*
* This library is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This library 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see http://www.gnu.org/licenses/
******************************************************************************/
/**************************************************************************//**
* \file mcp23008.c
******************************************************************************/
/******************************************************************************
* Header file inclusions.
******************************************************************************/
#include <mcp23008/mcp23008.h>
#include <twi/twi.h>
#include <useful/bits.h>
#include <stdint.h>
/******************************************************************************
* Private macros.
******************************************************************************/
/**************************************************************************//**
* \def MCP23008__ADDRESS
* \brief MCP23008 address on TWI bus (doesn't include hardware address).
* This value is given by the datasheet.
******************************************************************************/
#define MCP23008__ADDRESS 0x20
/**************************************************************************//**
* \def MCP23008__REG_IODIR
* \brief I/O direction register.
******************************************************************************/
#define MCP23008__REG_IODIR 0x00
/**************************************************************************//**
* \def MCP23008__REG_IPOL
* \brief Input polarity register.
******************************************************************************/
#define MCP23008__REG_IPOL 0x01
/**************************************************************************//**
* \def MCP23008__REG_GPINTEN
* \brief Interrupt on change control register.
******************************************************************************/
#define MCP23008__REG_GPINTEN 0x02
/**************************************************************************//**
* \def MCP23008__REG_DEFVAL
* \brief Default compare register for interrupt on change.
******************************************************************************/
#define MCP23008__REG_DEFVAL 0x03
/**************************************************************************//**
* \def MCP23008__REG_INTCON
* \brief Interrupt control register.
******************************************************************************/
#define MCP23008__REG_INTCON 0x04
/**************************************************************************//**
* \def MCP23008__REG_IOCON
* \brief Configuration register.
******************************************************************************/
#define MCP23008__REG_IOCON 0x05
/**************************************************************************//**
* \def MCP23008__REG_GPPU
* \brief Pull-up resistor configuration register.
******************************************************************************/
#define MCP23008__REG_GPPU 0x06
/**************************************************************************//**
* \def MCP23008__REG_INTF
* \brief Interrupt flag register.
******************************************************************************/
#define MCP23008__REG_INTF 0x07
/**************************************************************************//**
* \def MCP23008__REG_INTCAP
* \brief Interrupt capture register.
******************************************************************************/
#define MCP23008__REG_INTCAP 0x08
/**************************************************************************//**
* \def MCP23008__REG_GPIO
* \brief Port register.
******************************************************************************/
#define MCP23008__REG_GPIO 0x09
/**************************************************************************//**
* \def MCP23008__REG_OLAT
* \brief Output latch register.
******************************************************************************/
#define MCP23008__REG_OLAT 0x0A
/**************************************************************************//**
* \def MCP23008__CLOCK_RATE
* \brief MCP23008 frequency in Hertz.
* On ATmega, can be 100 kHz or 400 Khz.
******************************************************************************/
#define MCP23008__CLOCK_RATE 400000
/******************************************************************************
* Private function prototypes.
******************************************************************************/
/**************************************************************************//**
* \fn static uint8_t mcp23008__read_register(uint8_t address)
*
* \brief Read MCP23008 register value.
*
* \param address Address of the register to read value.
******************************************************************************/
static
uint8_t
mcp23008__read_register
(
uint8_t address
);
/**************************************************************************//**
* \fn static void mcp23008__write_register(uint8_t address, uint8_t value)
*
* \brief Write MCP23008 register value.
*
* \param address Address of the register to write value.
* \param value Value to write.
******************************************************************************/
static
void
mcp23008__write_register
(
uint8_t address,
uint8_t value
);
/******************************************************************************
* Private variable declarations.
******************************************************************************/
static uint8_t mcp23008__twi_address = 0;
/******************************************************************************
* Public function definitions.
******************************************************************************/
/**************************************************************************//**
* \fn void mcp23008__initialize(uint8_t hardware_address)
*
* \brief Initialize MCP23008.
*
* \param hardware_address Hardware address defined by pins A0 to A2.
******************************************************************************/
void
mcp23008__initialize
(
uint8_t hardware_address
){
// Initialize TWI.
twi__initialize(MCP23008__CLOCK_RATE);
// Compute MCP23008 TWI address.
mcp23008__twi_address = (MCP23008__ADDRESS | hardware_address) << 1;
twi__start();
twi__send_slaw(mcp23008__twi_address);
twi__send_data(MCP23008__REG_IODIR);
twi__send_data(0xFF);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__send_data(0x00);
twi__stop();
}
/**************************************************************************//**
* \fn void mcp23008__configure pin(
* mcp23008__gpio_t pin,
* mcp23008__direction_t direction)
*
* \brief Configure pin direction.
*
* \param pin Pin to configure.
* \param direction Pin direction.
******************************************************************************/
void
mcp23008__configure_pin
(
mcp23008__gpio_t pin,
mcp23008__direction_t direction
){
uint8_t port_configuration = mcp23008__read_register(MCP23008__REG_IODIR);
if (MCP23008__DIRECTION__INPUT == direction)
{
BIT__SET(port_configuration, pin);
}
else
{
BIT__RST(port_configuration, pin);
}
mcp23008__write_register(MCP23008__REG_IODIR, port_configuration);
}
/**************************************************************************//**
* \fn void mcp23008__configure_port(mcp23008__direction_t direction)
*
* \brief Configure port direction.
*
* \param direction Port direction.
******************************************************************************/
void
mcp23008__configure_port
(
mcp23008__direction_t direction
){
mcp23008__write_register(MCP23008__REG_IODIR, direction);
}
/**************************************************************************//**
* \fn mcp23008__level_t mcp23008__get_pin_level(mcp23008__gpio_t pin)
*
* \brief Get pin level.
*
* \param pin Pin to get level.
*
* \return Pin level.
******************************************************************************/
mcp23008__level_t
mcp23008__get_pin_level
(
mcp23008__gpio_t pin
){
uint8_t port_value = mcp23008__read_register(MCP23008__REG_GPIO);
mcp23008__level_t level = BIT__TST(port_value, pin);
return level;
}
/**************************************************************************//**
* \fn void mcp23008__set_pin_level(
* mcp23008__gpio_t pin,
* mcp23008__level_t level)
*
* \brief Set pin level.
*
* \param pin Pin to set level.
* \param level Level to set.
******************************************************************************/
void
mcp23008__set_pin_level
(
mcp23008__gpio_t pin,
mcp23008__level_t level
){
uint8_t port_value = mcp23008__read_register(MCP23008__REG_GPIO);
if (MCP23008__LEVEL__HIGH == level)
{
BIT__SET(port_value, pin);
}
else
{
BIT__RST(port_value, pin);
}
mcp23008__write_register(MCP23008__REG_GPIO, port_value);
}
/**************************************************************************//**
* \fn uin8_t mcp23008__get_port_value(void)
*
* \brief Get port value.
*
* \return Port value.
******************************************************************************/
uint8_t
mcp23008__get_port_value
(
void
){
uint8_t value = mcp23008__read_register(MCP23008__REG_GPIO);
return value;
}
/**************************************************************************//**
* \fn void mcp23008__set_port_value(uint8_t value)
*
* \brief Set port value.
*
* \param value Value to set.
******************************************************************************/
void
mcp23008__set_port_value
(
uint8_t value
){
mcp23008__write_register(MCP23008__REG_GPIO, value);
}
/******************************************************************************
* Private function definitions.
******************************************************************************/
/**************************************************************************//**
* \fn static uint8_t mcp23008__read_register(uint8_t address)
*
* \brief Read MCP23008 register value.
*
* \param address Address of the register to read value.
******************************************************************************/
static
uint8_t
mcp23008__read_register
(
uint8_t address
){
uint8_t value = 0;
twi__start();
twi__send_slaw(mcp23008__twi_address);
twi__send_data(address);
twi__stop();
twi__start();
twi__send_slar(mcp23008__twi_address);
twi__receive_data_nack(&value);
twi__stop();
return value;
}
/**************************************************************************//**
* \fn static void mcp23008__write_register(uint8_t address, uint8_t value)
*
* \brief Write MCP23008 register value.
*
* \param address Address of the register to write value.
* \param value Value to write.
******************************************************************************/
static
void
mcp23008__write_register
(
uint8_t address,
uint8_t value
){
twi__start();
twi__send_slaw(mcp23008__twi_address);
twi__send_data(address);
twi__send_data(value);
twi__stop();
}