Subversion Repositories idreammicro-avr

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/**************************************************************************//**
 * \brief Digital I/O library - Implementation
 * \author Copyright (C) 2009  Julien Le Sech - www.idreammicro.com
 * \version 1.0
 * \date 20090314
 *
 * 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 digital_io.c
 ******************************************************************************/


/******************************************************************************
 * Header file inclusions.
 ******************************************************************************/


#include <digital_io/digital_io.h>
#include <useful/bits.h>

#include <avr/io.h>

#include <stdint.h>

/******************************************************************************
 * Private macro definitions.
 ******************************************************************************/


/**************************************************************************//**
 * \def DIGITAL_IO__PORT_DIRECTION__INPUT
 * \brief
 ******************************************************************************/

#define DIGITAL_IO__PORT_DIRECTION__INPUT   0x00

/**************************************************************************//**
 * \def DIGITAL_IO__PORT_DIRECTION__OUTPUT
 * \brief
 ******************************************************************************/

#define DIGITAL_IO__PORT_DIRECTION__OUTPUT  0xFF

/**************************************************************************//**
 * \def digital_io__get_index(port)
 * \brief
 ******************************************************************************/

#define digital_io__get_index(port)         ((port) >> 4)
 
/******************************************************************************
 * Private types.
 ******************************************************************************/


/**************************************************************************//**
 * \typedef digital_io__register_t
 * \brief Digital IO registers (input, output, direction).
 ******************************************************************************/

typedef struct digital_io__register
{
    const uint8_t volatile * const  p_input;
    uint8_t volatile * const        p_output;
    uint8_t volatile * const        p_direction;
} digital_io__register_t;

/******************************************************************************
 * Private variable definitions.
 ******************************************************************************/


static const digital_io__register_t ports[] =
{
    #ifdef PORTA
    [digital_io__get_index(DIGITAL_IO__PORT_A)]
    { // PORT A.
        .p_input                = &PINA,
        .p_output               = &PORTA,
        .p_direction    = &DDRA
    },
    #endif
    #ifdef PORTB
    [digital_io__get_index(DIGITAL_IO__PORT_B)]
    { // PORT B.
        .p_input                = &PINB,
        .p_output               = &PORTB,
        .p_direction    = &DDRB
    },
    #endif
    #ifdef PORTC
    [digital_io__get_index(DIGITAL_IO__PORT_C)]
    { // PORT C.
        .p_input                = &PINC,
        .p_output               = &PORTC,
        .p_direction    = &DDRC
    },
    #endif
    #ifdef PORTD
    [digital_io__get_index(DIGITAL_IO__PORT_D)]
    { // PORT D.
        .p_input                = &PIND,
        .p_output               = &PORTD,
        .p_direction    = &DDRD
    },
    #endif
    #ifdef PORTE
    [digital_io__get_index(DIGITAL_IO__PORT_E)]
    { // PORT E.
        .p_input                = &PINE,
        .p_output               = &PORTE,
        .p_direction    = &DDRE
    },
    #endif
    #ifdef PORTF
    [digital_io__get_index(DIGITAL_IO__PORT_F)]
    { // PORT F.
        .p_input                = &PINF,
        .p_output               = &PORTF,
        .p_direction    = &DDRF
    },
    #endif
    #ifdef PORTG
    [digital_io__get_index(DIGITAL_IO__PORT_G)]
    { // PORT G.
        .p_input                = &PING,
        .p_output               = &PORTG,
        .p_direction    = &DDRG
    },
    #endif
    #ifdef PORTH
    [digital_io__get_index(DIGITAL_IO__PORT_H)]
    { // PORT H.
        .p_input                = &PINH,
        .p_output               = &PORTH,
        .p_direction    = &DDRH
    },
    #endif
    #ifdef PORTJ
    [digital_io__get_index(DIGITAL_IO__PORT_J)]
    { // PORT J.
        .p_input                = &PINJ,
        .p_output               = &PORTJ,
        .p_direction    = &DDRJ
    },
    #endif
    #ifdef PORTK
    [digital_io__get_index(DIGITAL_IO__PORT_K)] =
    { // PORT K.
        .p_input                = &PINK,
        .p_output               = &PORTK,
        .p_direction    = &DDRK
    },
    #endif
    #ifdef PORTL
    [digital_io__get_index(DIGITAL_IO__PORT_L)]
    { // PORT L.
        .p_input                = &PINL,
        .p_output               = &PORTL,
        .p_direction    = &DDRL
    }
    #endif
};

/******************************************************************************
 * Public function definitions.
 ******************************************************************************/


/**************************************************************************//**
 * \fn void digital_io__configure_pin(
 * digital_io__pin_position_t   pin_position,
 * digital_io__direction_t      direction)
 *
 * \brief Configure a pin.
 *
 * \param[in]   pin_position    pin position to configure
 * \param       direction       pin direction
 ******************************************************************************/

void
digital_io__configure_pin
(
        digital_io__pin_position_t  pin_position,
        digital_io__direction_t     direction
){
        // Alias.
        digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(pin_position)]);

        if (DIGITAL_IO__DIRECTION__INPUT == direction)
        {
        BIT__RST(*(p_register->p_direction), digital_io__get_pin(pin_position));
        }
        else
        {
        BIT__SET(*(p_register->p_direction), digital_io__get_pin(pin_position));
        }
}

/**************************************************************************//**
 * \fn digital_io__level_t digital_io__get_pin_level(
 * digital_io__pin_position_t pin_position)
 *
 * \brief Get the level of a pin.
 *
 * \param   pin_position    pin position to get level
 *
 * \return digital io level
 ******************************************************************************/

digital_io__level_t
digital_io__get_pin_level
(
        digital_io__pin_position_t  pin_position
){
        // Alias.
        digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(pin_position)]);

        digital_io__level_t level =
        BIT__TST(*(p_register->p_input), digital_io__get_pin(pin_position)) ?
                DIGITAL_IO__LEVEL__HIGH : DIGITAL_IO__LEVEL__LOW;

        return level;
}

/**************************************************************************//**
 * \fn void digital_io__set_pin_level(
 * digital_io__pin_position_t   pin_position,
 * digital_io__level_t          level)
 *
 * \brief Set the level of a pin.
 *
 * \param[in]   pin_position    pin position to set level
 * \param       level           level to set
 ******************************************************************************/

void
digital_io__set_pin_level
(
        digital_io__pin_position_t  pin_position,
        digital_io__level_t         level
){
        // Alias.
        digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(pin_position)]);

        if (DIGITAL_IO__LEVEL__LOW == level)
        {
        BIT__RST(*(p_register->p_output), digital_io__get_pin(pin_position));
        }
        else
        {
        BIT__SET(*(p_register->p_output), digital_io__get_pin(pin_position));
        }
}

/**************************************************************************//**
 * \fn void digital_io__toggle_pin_level(
 * digital_io__pin_position_t pin_position)
 *
 * \brief Toggle the level of a pin.
 *
 * \param   pin_position    pin position to toggle level
 ******************************************************************************/

void
digital_io__toggle_pin_level
(
        digital_io__pin_position_t  pin_position
){
    // Alias.
    digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(pin_position)]);

    BIT__TGL(*(p_register->p_output), digital_io__get_pin(pin_position));
}

/**************************************************************************//**
 * \fn void digital_io__configure_port(
 * digital_io__port_t       port,
 * digital_io__direction_t  direction)
 *
 * \brief Configure a port.
 *
 * \param   port        port to configure
 * \param   direction   port direction to configure
 ******************************************************************************/

void
digital_io__configure_port
(
    digital_io__port_t      port,
    digital_io__direction_t direction
){
        // Alias.
        digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(port)]);

        if (DIGITAL_IO__DIRECTION__INPUT == direction)
        {
                *(p_register->p_direction) = DIGITAL_IO__PORT_DIRECTION__INPUT;
        }
        else
        {
                *(p_register->p_direction) = DIGITAL_IO__PORT_DIRECTION__OUTPUT;
        }
}

/**************************************************************************//**
 * \fn uint8_t digital_io__get_port_value(digital_io__port_t port)
 *
 * \brief Get the value of a port.
 *
 * \param   port    port to get value
 *
 * \return port value
 ******************************************************************************/

digital_io__port_value_t
digital_io__get_port_value
(
    digital_io__port_t  port
){
        // Alias.
        digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(port)]);

        uint8_t value = *(p_register->p_input);

        return value;
}

/**************************************************************************//**
 * \fn void digital_io__set_port_value(
 * digital_io__port_t       port,
 * digital_io__port_value_t value)
 *
 * \brief Set the value of a port.
 *
 * \param   port  port to set value
 * \param   value port value to set
 ******************************************************************************/

void
digital_io__set_port_value
(
    digital_io__port_t          port,
    digital_io__port_value_t    value
){
        // Alias.
        digital_io__register_t const* p_register =
        &(ports[digital_io__get_port(port)]);

        *(p_register->p_output) = value;
}