I2C Piezo Haptic Driver with Integrated Boost Converter and Digital Front End

drv2665.cpp

Committer:
akashvibhute
Date:
2016-05-30
Revision:
1:e2c726c628dc
Parent:
0:b85fd3fdfcfa

File content as of revision 1:e2c726c628dc:

/**
 *  DRV2665 library
 *
 *  @author Akash Vibhute
 *  @author < akash . roboticist [at] gmail . com >
 *  @version 0.1
 *  @date May/24/2016
 */

#include "drv2665.h"
#define M_PI 3.14159265358979

static const uint8_t drv2665_sine_wave_form[] = {
    0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
    0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
    0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
    0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
    0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
    0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
    0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
    0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
    0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
    0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
    0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
    0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
};

DRV2665_DIGITAL::DRV2665_DIGITAL( PinName sda, PinName scl ):i2c_(sda, scl)
{
    i2c_.frequency(100000);
    i2c_addr = DRV2665_I2C_ADDRESS << 1;
    wait_ms(2); //wait 2ms for i2c bus
}

void DRV2665_DIGITAL::init(uint8_t output_gain, uint8_t idle_timeout)
{
    write(DRV2665_CTRL_2, DRV2665_DEV_RST); //reset
    write(DRV2665_CTRL_2, 0); //clear standby
    //write(DRV2665_CTRL_1, (DRV2665_DIGITAL_IN | output_gain)); //set mode digital, set gain
    write(DRV2665_CTRL_1, DRV2665_DIGITAL_IN); //set mode digital, set gain
    write(DRV2665_CTRL_1, DRV2665_100_VPP_GAIN); //set mode digital, set gain
    write(DRV2665_CTRL_2, idle_timeout); //set timeout period
}

void DRV2665_DIGITAL::reset()
{
    write(DRV2665_CTRL_2, DRV2665_DEV_RST);
}

void DRV2665_DIGITAL::outputWave(int8_t waveform[], uint8_t length)
{
    char reg;
    char buff[100];
    
    buff[0] = DRV2665_FIFO;
    length = 81;
    
    /*
    for(int i=0; i<length; i++)
        buff[i+1] = drv2665_sine_wave_form[i];
    
    //while(!fifo_check());
    
    i2c_.write(i2c_addr, buff, 42);
    */
    
    if(fifo_check()) {
        //i2c_.write(i2c_addr, buff, 42);
        
        for(int i=0; i<length; i++) {
            write(DRV2665_FIFO, drv2665_sine_wave_form[i]);
            wait_us(20);
        }
        
    } else
        return;
        
}

void DRV2665_DIGITAL::outputSine(uint16_t hz)
{
    int8_t waveform_byte;
    uint16_t length;
    uint8_t repeat = 1;

    //in the linux driver example, a 41 byte waveform plays back at 8kHz
    //wavelength 41 -> wave time 125us -> frequency 8kHz
    //hence per byte sampling time = 125us / 41 = 3.04878049
    //ie 41 bytes :: 8kHz -> 328 bytes :: 1000Hz
    //calculations done here are from this factor

    //length = (1000 * 328) / hz;
    
    
    //If the above assumption is incorrect, it could be that the DRV plays 
    //anything in its FIFO at a fix rate of 8ksps in that case, it would mean 
    //a per byte play time of 125us, ie for a 100byte wavelength -> a playback
    //time of 12.5ms (80Hz)
    //So, 100B :: 80Hz -> 100*80B :: 1Hz
    //For 'n' Hz :: (100*80/n) B

    length = (100 * 80) / hz;
    
    
    for(int j=0; j<repeat; j++) {

        for(int i=0; i<length; i++) {
            waveform_byte = 100.0 * sin( 2*M_PI * i/(length-1) ); //102 is the max +ve / -ve value, typecasting in uint8 turns -ve values into 2's complement required by the driver

            write(DRV2665_FIFO, (uint8_t)waveform_byte);
            wait_us(20);
        }
    }
}

bool DRV2665_DIGITAL::fifo_check()
{
    uint8_t reply;
    reply = read(DRV2665_STATUS);

    if((reply & 0x01) == 0)
        return(true);
    else
        return(false);
}

void DRV2665_DIGITAL::en_override(uint8_t en)
{
    char buff[2];
    
    buff[0] = DRV2665_BOOST_EN;
    buff[1] = en;
    
    write(DRV2665_CTRL_2, DRV2665_BOOST_EN);
}

uint8_t DRV2665_DIGITAL::read(char reg)
{
    //Create a temporary buffer
    char buff[2];

    //Select the register
    i2c_.write(i2c_addr, &reg, 1, true);

    //Read the 16-bit register
    i2c_.read(i2c_addr, buff, 2);

    //Return the combined 16-bit value
    return (buff[0] << 8) | buff[1];
}

void DRV2665_DIGITAL::write(char reg, uint8_t data)
{
    //Create a temporary buffer
    char buff[2];

    //Load the register address and 16-bit data
    buff[0] = reg;
    buff[1] = data;

    //Write the data
    i2c_.write(i2c_addr, buff, 2);
}