Basic functions is OK. Lack interrupts function.

Dependents:   Mt05_MtSense07

AK9750.cpp

Committer:
bcc6
Date:
2017-03-23
Revision:
4:413b8ef9aed5
Parent:
3:14f634433c89

File content as of revision 4:413b8ef9aed5:

/* Copyright (c) 2016 MtM Technology Corporation, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "AK9750.h"


/* ADC to IR(current) */
struct AdcToIr {
    int16_t adc;
    float   current;    // Unit:pA
};
static const AdcToIr a2i_table[] = {
    {0x7FFF,  14286.4f},
    {0x5998,  10000.1f},
    {0x4082,   7000.1f},
    {0x08F6,   1000.2f},
    {0x0020,     14.0f},
    {0x0000,      0.0f},
    {0xFFE0,    -13.5f},
    {0xF709,  -1000.2f},
    {0xBF7D,  -7200.1f},
    {0x9667, -10000.1f},
    {0x8000, -14286.8f},
};
#define A2I_TABLE_COUNT     ((sizeof(a2i_table) / sizeof(AdcToIr)))

/* ADC to temperature('C) */
#define A2T_TEMPERATURE_OFFSET  (26.75f)
#define A2T_10BIT_RESOLUTION    (0.125f)


AK9750::AK9750(I2C &i2c, PinName int1) : _i2c(i2c), _int1(int1) {

}

void AK9750::ConfigDevice () {
    /* Soft reset */
    RegWrite(0x1D, 0x01);

    /* Mode & Fc */
//  RegWrite(0x1C, 0x0C);   // EEPMODE(Normal), EFC(0.6Hz), EMODE(ContMode0)
    RegWrite(0x1C, 0x0D);   // EEPMODE(Normal), EFC(0.6Hz), EMODE(ContMode1)

    /* Disable all interrupts */
    RegWrite(0x1B, 0x00);
}

void AK9750::GetDeviceID(uint8_t *id) {
    RegRead(0x01, (char *)id, 1); 
}

void AK9750::GetData(Data *data) {
    char status;
    char buf[10];
    
    RegRead(0x05, &status, 1);
    RegRead(0x06, buf, 10);
    RegRead(0x10, &status, 1);  // Dummy read
    
    /* Format data */
    int16_t ir1_adc = (((int16_t)buf[1]) << 8) | buf[0];
    int16_t ir2_adc = (((int16_t)buf[3]) << 8) | buf[2];
    int16_t ir3_adc = (((int16_t)buf[5]) << 8) | buf[4];
    int16_t ir4_adc = (((int16_t)buf[7]) << 8) | buf[6];
    int16_t tmp_adc = (((int16_t)buf[9]) << 8) | buf[8];
    
    /* Convert data */
    data->ir1 = ConvertAdcToIr(ir1_adc);
    data->ir2 = ConvertAdcToIr(ir2_adc);
    data->ir3 = ConvertAdcToIr(ir3_adc);
    data->ir4 = ConvertAdcToIr(ir4_adc);
    data->tmp = ConvertAdcToTemperature(tmp_adc);
}

int32_t AK9750::GetTriggeredAreaNum(Data *data) {
    int32_t index = 1;
    float max = data->ir1;
    
    if(data->ir2 > max) {
        index = 2;
        max = data->ir2;
    }
    if(data->ir3 > max) {
        index = 3;
        max = data->ir3;
    }
    if(data->ir4 > max) {
        index = 4;
        max = data->ir4;
    }
    return index;
}

void AK9750::SetIntEvent(uint8_t int_enable, void(*fptr)(void)) {
    RegWrite(0x1B, int_enable);

    _int1.mode(PullNone);   // external pull-up
    _int1.fall(fptr);       // falling edge trigger
}

uint8_t AK9750::GetIntStatus() {
    char status;
    RegRead(0x04, &status, 1);
    return status;
}

float AK9750::ConvertAdcToIr(int16_t adc) {
    const AdcToIr *a2i_up, *a2i_down;

    /* Look up */
    for(int i=0; i<(A2I_TABLE_COUNT-1); i++) {
        a2i_up   = &(a2i_table[i]);
        a2i_down = &(a2i_table[i+1]);
        
        if((a2i_up->adc >= adc) && (a2i_down->adc <= adc)) {
            /* Found & calculate */
            return (a2i_up->current - a2i_down->current) / (a2i_up->adc - a2i_down->adc) * adc;
        }
    }
    return 0;   // Shall not go here
}

float AK9750::ConvertAdcToTemperature(int16_t adc) {
    /* Shift-right with 6 bits */
    bool is_negative = (adc < 0)? true : false;
    adc >>= 6;
    if(is_negative) {
        adc |= 0xFC00;
    }
    
    /* Calculate */
    return (float)adc * A2T_10BIT_RESOLUTION + A2T_TEMPERATURE_OFFSET;
}
    
void AK9750::RegWrite(char reg, char val) {
    char data[2];
    data[0] = reg;
    data[1] = val;
    _i2c.write(AK9750_SLAVE_ADDR, data, 2, 0);
}

void AK9750::RegRead(char reg, char *val, int len) {
    _i2c.write(AK9750_SLAVE_ADDR, &reg, 1, 0);
    _i2c.read (AK9750_SLAVE_ADDR, val, len);
}

void AK9750::RegReadModifyWrite(char reg, char clr_mask, char set_mask) {
    char val;
    RegRead (reg, &val, 1);             // Read
    val = (val & ~clr_mask) | set_mask; // Modify
    RegWrite(reg, val);                 // Write
}