8-bit A/D and D/A converter

PCF8591.cpp

Committer:
mcm
Date:
2017-09-25
Revision:
4:bdcb2b5c8cee
Parent:
3:8d2e4b9015a8

File content as of revision 4:bdcb2b5c8cee:

/**
 * @brief       PCF8591.c
 * @details     8-bit A/D and D/A converter.
 *              Functions file.
 *
 *
 * @return      NA
 *
 * @author      Manuel Caballero
 * @date        24/September/2017
 * @version     24/September/2017    The ORIGIN
 * @pre         NaN.
 * @warning     NaN
 * @pre         This code belongs to AqueronteBlog ( http://unbarquero.blogspot.com ).
 */

#include "PCF8591.h"


PCF8591::PCF8591 ( PinName sda, PinName scl, uint32_t addr, uint32_t freq )
    : i2c          ( sda, scl )
    , PCF8591_Addr  ( addr )
{
    i2c.frequency( freq );
}


PCF8591::~PCF8591()
{
}



/**
 * @brief       PCF8591_SetADC ( PCF8591_analog_input_programming_t , PCF8591_auto_increment_status_t , PCF8591_channel_number_t )
 *
 * @details     It configures the ADC.
 *
 * @param[in]    myAnalogInputs:    The analog input programming.
 * @param[in]    myAutoIncrement:   Auto-increment flag enabled/disabled.
 * @param[in]    myADCchannel:      ADC Channel number.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of PCF8591_SetADC.
 *
 *
 * @author      Manuel Caballero
 * @date        24/September/2017
 * @version     24/September/2017   The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
PCF8591::PCF8591_status_t  PCF8591::PCF8591_SetADC ( PCF8591_analog_input_programming_t myAnalogInputs, PCF8591_auto_increment_status_t myAutoIncrement, PCF8591_channel_number_t myADCchannel )
{
    char        cmd                 =    0;
    uint32_t    aux                 =    0;


    // ANALOG INPUT PROGRAMMING
    switch ( myAnalogInputs )
    {
    default:
    case PCF8591_FOUR_SINGLE_ENDED_INPUTS:
        // cmd  &=  0xCF;
        break;

    case PCF8591_THREE_DIFFERENTIAL_INPUTS:
        cmd  |=  0x10;
        break;

    case PCF8591_SINGLE_ENDED_AND_DIFFERENTIAL_MIXED:
        cmd  |=  0x20;
        break;

    case PCF8591_TWO_DIFFERENTIAL_INPUTS:
        cmd  |=  0x30;
        break;
    }

    _ANALOG_INPUT_PROGRAMMING    =   myAnalogInputs;


    // AUTO-INCREMENT FLAG
    if ( myAutoIncrement == PCF8591_AUTO_INCREMENT_ENABLED )
        cmd  |=  0x04;


    _AUTO_INCREMENT_STATUS   =   myAutoIncrement;



    // A/D CHANNEL NUMBER
    switch ( myADCchannel )
    {
    default:
    case PCF8591_CHANNEL_0:
        // cmd  &=  0xFC;
        break;

    case PCF8591_CHANNEL_1:
        cmd  |=  0x01;
        break;

    case PCF8591_CHANNEL_2:
        cmd  |=  0x02;
        break;

    case PCF8591_CHANNEL_3:
        cmd  |=  0x03;
        break;
    }


    _CHANNEL_NUMBER   =   myADCchannel;



    // Mask DAC
    if ( _DAC_STATUS == PCF8591_DAC_ENABLED )
        cmd  |=  0x40;




    // Update Control Byte
    aux = i2c.write ( PCF8591_Addr, &cmd, 1 );



    if ( aux == I2C_SUCCESS )
        return   PCF8591_SUCCESS;
    else
        return   PCF8591_FAILURE;
}



/**
 * @brief       PCF8591_ReadADC ( PCF8591_vector_data_t*  )
 *
 * @details     It gets the ADC result from the device.
 *
 * @param[in]    myinstance:        Peripheral's Instance.
 * @param[in]    myPCF8591Addr:     I2C Device address.
 *
 * @param[out]   myADC_Data:        ADC result into the chosen channel.
 *
 *
 * @return       Status of PCF8591_ReadADC.
 *
 *
 * @author      Manuel Caballero
 * @date        24/September/2017
 * @version     24/September/2017   The ORIGIN
 * @pre         First byte is descarted.
 * @warning     NaN.
 */
PCF8591::PCF8591_status_t  PCF8591::PCF8591_ReadADC ( PCF8591_vector_data_t* myADC_Data )
{
    char        cmd[]               =    { 0, 0, 0, 0, 0 };
    uint32_t    aux                 =    0;
    uint32_t    myNumberReadings    =    0;



    // Check if Auto-increment flag is enabled
    if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        myNumberReadings    =   5;
    else
        myNumberReadings    =   2;


    // Read the data
    aux = i2c.read ( PCF8591_Addr, &cmd[0], myNumberReadings );



    // Store the data in the right position
    switch ( _CHANNEL_NUMBER )
    {
    default:
    case PCF8591_CHANNEL_0:
        myADC_Data->ADC_Channel_0    =   cmd[ 1 ];

        if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        {
            myADC_Data->ADC_Channel_1    =   cmd[ 2 ];
            myADC_Data->ADC_Channel_2    =   cmd[ 3 ];
            myADC_Data->ADC_Channel_3    =   cmd[ 4 ];
        }
        break;

    case PCF8591_CHANNEL_1:
        myADC_Data->ADC_Channel_1    =   cmd[ 1 ];

        if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        {
            myADC_Data->ADC_Channel_2    =   cmd[ 2 ];
            myADC_Data->ADC_Channel_3    =   cmd[ 3 ];
            myADC_Data->ADC_Channel_0    =   cmd[ 4 ];
        }
        break;

    case PCF8591_CHANNEL_2:
        myADC_Data->ADC_Channel_2    =   cmd[ 1 ];

        if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        {
            myADC_Data->ADC_Channel_3    =   cmd[ 2 ];
            myADC_Data->ADC_Channel_0    =   cmd[ 3 ];
            myADC_Data->ADC_Channel_1    =   cmd[ 4 ];
        }
        break;

    case PCF8591_CHANNEL_3:
        myADC_Data->ADC_Channel_3    =   cmd[ 1 ];

        if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        {
            myADC_Data->ADC_Channel_0    =   cmd[ 2 ];
            myADC_Data->ADC_Channel_1    =   cmd[ 3 ];
            myADC_Data->ADC_Channel_2    =   cmd[ 4 ];
        }
        break;
    }




    if ( aux == I2C_SUCCESS )
        return   PCF8591_SUCCESS;
    else
        return   PCF8591_FAILURE;
}



/**
 * @brief       PCF8591_SetDAC ( PCF8591_dac_status_t )
 *
 * @details     It enables/disables the DAC.
 *
 * @param[in]    myDAC_Status:      Enable/Disable DAC.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of PCF8591_SetDAC.
 *
 *
 * @author      Manuel Caballero
 * @date        24/September/2017
 * @version     24/September/2017   The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
PCF8591::PCF8591_status_t  PCF8591::PCF8591_SetDAC ( PCF8591_dac_status_t myDAC_Status )
{
    char        cmd                 =    0;
    uint32_t    aux                 =    0;


    // Mask ANALOG INPUT PROGRAMMING
    switch ( _ANALOG_INPUT_PROGRAMMING )
    {
    default:
    case PCF8591_FOUR_SINGLE_ENDED_INPUTS:
        // cmd  &=  0xCF;
        break;

    case PCF8591_THREE_DIFFERENTIAL_INPUTS:
        cmd  |=  0x10;
        break;

    case PCF8591_SINGLE_ENDED_AND_DIFFERENTIAL_MIXED:
        cmd  |=  0x20;
        break;

    case PCF8591_TWO_DIFFERENTIAL_INPUTS:
        cmd  |=  0x30;
        break;
    }


    // Mask AUTO-INCREMENT FLAG
    if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        cmd  |=  0x04;



    // Mask A/D CHANNEL NUMBER
    switch ( _CHANNEL_NUMBER )
    {
    default:
    case PCF8591_CHANNEL_0:
        // cmd  &=  0xFC;
        break;

    case PCF8591_CHANNEL_1:
        cmd  |=  0x01;
        break;

    case PCF8591_CHANNEL_2:
        cmd  |=  0x02;
        break;

    case PCF8591_CHANNEL_3:
        cmd  |=  0x03;
        break;
    }



    // DAC
    if ( myDAC_Status == PCF8591_DAC_ENABLED )
        cmd  |=  0x40;


    _DAC_STATUS  =   myDAC_Status;



    // Update Control Byte
    aux = i2c.write ( PCF8591_Addr, &cmd, 1 );



    if ( aux == I2C_SUCCESS )
        return   PCF8591_SUCCESS;
    else
        return   PCF8591_FAILURE;
}



/**
 * @brief       PCF8591_NewDACValue ( uint8_t )
 *
 * @details     It enables/disables the DAC.
 *
 * @param[in]    myNewDACValue:     New DAC value.
 *
 * @param[out]   NaN.
 *
 *
 * @return       Status of PCF8591_NewDACValue.
 *
 *
 * @author      Manuel Caballero
 * @date        24/September/2017
 * @version     24/September/2017   The ORIGIN
 * @pre         NaN
 * @warning     NaN.
 */
PCF8591::PCF8591_status_t  PCF8591::PCF8591_NewDACValue ( uint8_t myNewDACValue )
{
    char        cmd[]               =    { 0, 0 };
    uint32_t    aux                 =    0;


    // Mask ANALOG INPUT PROGRAMMING
    switch ( _ANALOG_INPUT_PROGRAMMING )
    {
    default:
    case PCF8591_FOUR_SINGLE_ENDED_INPUTS:
        // cmd[ 0 ]  &=  0xCF;
        break;

    case PCF8591_THREE_DIFFERENTIAL_INPUTS:
        cmd[ 0 ]  |=  0x10;
        break;

    case PCF8591_SINGLE_ENDED_AND_DIFFERENTIAL_MIXED:
        cmd[ 0 ]  |=  0x20;
        break;

    case PCF8591_TWO_DIFFERENTIAL_INPUTS:
        cmd[ 0 ]  |=  0x30;
        break;
    }


    // Mask AUTO-INCREMENT FLAG
    if ( _AUTO_INCREMENT_STATUS == PCF8591_AUTO_INCREMENT_ENABLED )
        cmd[ 0 ]  |=  0x04;



    // Mask A/D CHANNEL NUMBER
    switch ( _CHANNEL_NUMBER )
    {
    default:
    case PCF8591_CHANNEL_0:
        // cmd[ 0 ]  &=  0xFC;
        break;

    case PCF8591_CHANNEL_1:
        cmd[ 0 ]  |=  0x01;
        break;

    case PCF8591_CHANNEL_2:
        cmd[ 0 ]  |=  0x02;
        break;

    case PCF8591_CHANNEL_3:
        cmd[ 0 ]  |=  0x03;
        break;
    }



    // Mask DAC
    if ( _DAC_STATUS == PCF8591_DAC_ENABLED )
        cmd[ 0 ]  |=  0x40;




    // Update Control Byte and the DAC output
    cmd[ 1 ]     =   myNewDACValue;
    aux = i2c.write ( PCF8591_Addr, &cmd[0], 2 );




    if ( aux == I2C_SUCCESS )
        return   PCF8591_SUCCESS;
    else
        return   PCF8591_FAILURE;
}