RM3100 SPI sample code

Dependencies:   mbed

RM3100.cpp

Committer:
BeiZhang
Date:
2019-03-10
Revision:
0:71d5c1c75f0b

File content as of revision 0:71d5c1c75f0b:

/**
* @file         RM3100.cpp
*
* @brief        Sample interface for RM3100.
*
* @authors      Betty Zhang
* @date         05/21/2018
* @copyright    (C) 2018 PNI Corp, Protonex LLC
*
* @copyright    Disclosure to third parties or reproduction in any form
*               whatsoever, without prior written consent, is strictly forbidden
*
*/
#include "RM3100.h"
#include "main.h"

void RM3100::ClearDrdyInt()
{
    //Clear Interrupt first
    cs = 0;
    spi.write(RM3100_STATUS_REG);
    int status = spi.write(0x00);
    cs = 1;
    if (status & 0x80)
    {
        ReadRM3100();
        status = 0;
    }
}
    
void RM3100::RunCMM(int flag)
{
    //Set current sample rate if it changes
    if (sample_rate != prev_rate)
    {
        SetSampleRateReg(sample_rate);
        prev_rate = sample_rate;
    }
    
    if (flag) {
        //Set Cycle Count if it changes
        SetCycleCountReg();

        //Confirm new setting and update "gain"
        DisplayCycleCount();
    }

    RegCMM cmm_reg;
    cmm_reg.bits.LDM = 0;
    cmm_reg.bits.CMX = 1;
    cmm_reg.bits.CMY = 1;
    cmm_reg.bits.CMZ = 1;
    cmm_reg.bits.Drdm = 2; //0 on any axis, 2 Drdy after completion of XYZ
    cmm_reg.bits.Alarm = 0;

    if (flag) {
        //Start CMM run
        cmm_reg.bits.Start = 1;
        cmm_reg.bits.CMX = 1;
        cmm_reg.bits.CMY = 1;
        cmm_reg.bits.CMZ = 1;
    } else {
        //Stop CMM run
        cmm_reg.bits.Start = 0;
        cmm_reg.bits.CMX = 0;
        cmm_reg.bits.CMY = 0;
        cmm_reg.bits.CMZ = 0;
    }
    
    cs = 0;
    spi.write(RM3100_CMM_REG);
    spi.write(cmm_reg.reg);
    cs = 1;
}

void RM3100::ChangeSampleRate(int flag)
{
    if (flag > 0)
        sample_rate *= 2; //increase 2 times
    if (flag < 0)
        sample_rate /= 2; //decrease 2 times
    
    if (sample_rate < 1)
        sample_rate = 1; //1hz
    else if (sample_rate > 600)
        sample_rate = 600;
}

void RM3100::SetSampleRateReg(int rate)
{
    int value;
    
    sample_rate = rate;
        
    if ((rate <= 600) && (rate >= 300))
        value = 0x92;
    else if ((rate < 300) && (rate >= 150))
        value = 0x93;
    else if ((rate < 150) && (rate >= 75))
        value = 0x94;
    else if ((rate < 75) && (rate >= 37))
        value = 0x95;
    else if ((rate < 37) && (rate >= 18))
        value = 0x96;
    else if ((rate < 18) && (rate >= 9))
        value = 0x97;
    else if ((rate < 9) && (rate >= 4))
        value = 0x98;
    else if ((rate < 4) && (rate >= 3))
        value = 0x99;
    else if ((rate < 3) && (rate >= 2))
        value = 0x9A;
    else if ((rate < 2) && (rate >= 1))
        value = 0x9B;   //About 1Hz
    else 
        value = 0x9C;   //About 0.6Hz
        
    cs = 0;
    //set sample rate
    spi.write(RM3100_TMRC_REG);
    spi.write(value); //about 1Hz
    cs = 1;
}

int RM3100::GetSampleRate(int *tmrc_reg_val)
{
    cs = 0;
    //set sample rate
    spi.write(RM3100_TMRC_REG | 0x80); //Read TMRC reg
    * tmrc_reg_val = spi.write(0);
    cs = 1;
    
    return sample_rate;
}
    
void RM3100::ReadRM3100()
{
    int mag[9];
    int count[3];

    __disable_irq();    // Disable Interrupts
    cs = 0;
    spi.write(RM3100_MX_REG);

    comport.printf("Mag = 0x");
    for (int i = 0; i < 9; i++) {
        mag[i] = spi.write(0x00);
        comport.printf("%x", mag[i]);
        if ((i < 8) && ((i+1) % 3) == 0)
            comport.printf(" 0x");
    }
    cs = 1;
        
    comport.printf(", ");
    //Process the 24-bit signed measurement in count
    int measurement = 0;
    int index = 0;
    for (int j = 0; j < 9; j += 3) {
        if (mag[j] & 0x80)
            measurement = 0xFF;
        measurement <<= 24; //left shift 24-bit
        measurement |= (mag[j+2] | (mag[j+1] | (mag[j] << 8)) << 8);
        comport.printf("%d ", measurement);
        count[index] = measurement;
        measurement = 0;
        index++;
    }

    comport.printf(", ");
    //Convert to uT (microTesla)
    for (int k = 0; k < 3; k++) {
        comport.printf("%5.3fuT ", (float)count[k]/current_gain[k]);
    }

    comport.printf("\n\r");
    
    __enable_irq();     // Enable Interrupts

}

void RM3100::SetDrdyIntFlag(u8 flag)
{
    rm3100_service_flag = flag;
    if (flag)
        drdy.disable_irq();
    else
        drdy.enable_irq();
}

u8 RM3100::GetDrdyIntFlag(void)
{
    return rm3100_service_flag;
}

void RM3100::ProcessDrdyInt()
{
    SetDrdyIntFlag(1);
}

void RM3100::DrdyCallBack(void)
{
    // attach ProcessDrdyInt function of this RM3100 instance
    drdy.rise(callback(this, &RM3100::ProcessDrdyInt)); 
}

void RM3100::DisplayCycleCount()
{
    int cc[6];
    int c_count[3];
    float maxrate;

    //Read CC reg
    __disable_irq();    // Disable Interrupts
    cs = 0;
    int cc_reg = RM3100_CCXLSB_REG | 0x80; //"| 0x80" to read CC Reg
    spi.write(cc_reg);

    comport.printf("CC = 0x");
    for (int i = 0; i < 6; i++) {
        cc[i] = spi.write(0);
        comport.printf("%x", cc[i]);
        if ((i < 5) && ((i+1) % 2) == 0)
            comport.printf(" 0x");
    }
    cs = 1;

    comport.printf(", ");
    //Process the 16-bit unsigned cycle count
    int temp = 0;
    int index = 0;
    for (int j = 0; j < 6; j += 2) {
        if (cc[j] & 0x80)
            temp = 0xFF;
        temp <<= 8; //left shift 8-bit
        temp |= (cc[j+1] | (cc[j] << 8));
        c_count[index++] = temp; //save CC values 
        comport.printf("%d ", temp);
        temp = 0;
    }

    //Calculate gain from CC, gain = 0.375 * cc;
    comport.printf(", Gain = ");
    for (int k = 0; k < 3; k++) {
        if (c_count[k])
            current_gain[k] = c_count[k] * DEFAULTGAIN/DEFAULTCCOUNT;
        comport.printf("%d ", current_gain[k]);
    }
    
    //Calculate max sample rate, assume CC same for 3 axes
    if (c_count[0] == 50)
        maxrate = 1600.0 / 3.0;
    else if (c_count[0] == 100)
        maxrate = 850.0 / 3.0;
    else if (c_count[0] == 200)
        maxrate = 440.0 / 3.0;
    else if (c_count[0] == 225)
        maxrate = 370.0 / 3.0;
    else if (c_count[0] == 250)
        maxrate = 350.0 / 3.0;
    else if (c_count[0] < 100)
        maxrate = (-15.0 * c_count[0] + 2350.0) / 3.0;
    else if (c_count[0] < 225)
        maxrate = (-14.0 * c_count[0]/5.0 + 1000.0) / 3.0;
    else if (c_count[0] < 250)
        maxrate = (-4.0 * c_count[0]/5.0 + 550.0) / 3.0;
    else if (c_count[0] <= 400)
        maxrate = (-4.0 * c_count[0] /5.0 + 550.0) / 3.0;

    comport.printf("MaxRate = %3.2f Hz\n\r", maxrate);

    __enable_irq();     // Enable Interrupts
}

void RM3100::DisplayREVIDReg()
{
    //Read REVID reg
    __disable_irq();    // Disable Interrupts
    cs = 0;
    int reg = RM3100_REVID_REG;
    spi.write(reg);
    int revid = spi.write(0);
    __enable_irq();    // Enable Interrupts
    cs = 1;

    comport.printf("RM3100 REVID = %2D\n\r", revid);
}

void RM3100::SelfTest()
{
    comport.printf("SelfTest \n\r");

    RegBIST regbist;
    RegPOLL regpoll;

    //Set BIST
    //bit#7 STE=1, bit#6#5#4 = 0, bit#3 BW1=1, bit#2 BW0=1, bit#1 BP1=1, bit#0 BP0=1
    regbist.bits.BP = 3;
    regbist.bits.BW = 3;
    regbist.bits.XYZOK = 0;
    regbist.bits.STE = 1;

    //Set POLL reg
    regpoll.bits.LowNibble = 0;
    regpoll.bits.PMX = 1;
    regpoll.bits.PMY = 1;
    regpoll.bits.PMZ = 1;
    regpoll.bits.MSB = 0;

    //Start Self Test
    __disable_irq();    // Disable Interrupts
    cs = 0;

    //stop continuous mode
    spi.write(RM3100_CMM_REG);
    spi.write(0);
    cs = 1;

    cs = 0;
    spi.write(RM3100_BIST_REG);
    spi.write(regbist.reg);
    comport.printf("bist val= 0x%X, poll val = 0x%X \n\r", regbist.reg, regpoll.reg);

    cs = 1;

    cs = 0;
    //POLL 1 measurement on XYZ
    spi.write(RM3100_POLL_REG);
    spi.write(regpoll.reg);
    cs = 1;

    //Get result
    cs = 0;
    spi.write(RM3100_STATUS_REG | 0x80);
    int value = spi.write(0);
    comport.printf("Poll a measurement and Check status reg val = 0x%X \n\r", value);

    cs = 1;

    if (value) {
        //Read RM3100_BIST_REG;
        cs = 0;
        spi.write(RM3100_BIST_REG | 0x80);
        value = spi.write(0);
        cs = 1;

        //Check result here
        comport.printf("Check BIST reg 0x%X\n\r", value);
        if (value & 0x70)
            comport.printf("Result = 0x%X Pass\n\r", value);
        else
            comport.printf("Result = 0x%X Fail\n\r", value);

    } else
        comport.printf("Measurement not Ready\n\r");

    //It's important to Reset SeltTest reg
    cs = 0;
    spi.write(RM3100_BIST_REG);
    spi.write(0);
    cs = 1;

    __enable_irq();    // Enable Interrupts

}

void RM3100::ChangeCycleCount(int flag)
{    
    for (int i = 0; i < 3; i++)
    {
        if (flag > 0) 
        {
            current_ccount[i] += 10;
        } 
        else if (flag < 0) 
        {
            current_ccount[i] -= 10;
        }
        
        if (current_ccount[i] < LOWERCYCLECOUNT)
            current_ccount[i] = LOWERCYCLECOUNT;
            
        if (current_ccount[i] > UPPERCYCLECOUNT)
            current_ccount[i] = UPPERCYCLECOUNT;
          
    }
}


//Set Cycle Count Reg
void RM3100::SetCycleCountReg()
{   
    static int prev_ccount = DEFAULTCCOUNT;
    
    //Check any changes on CC. Should check 3 axes, just X-axis as example
    if (prev_ccount != current_ccount[0]) {
        
        prev_ccount = current_ccount[0];

        //Read CC reg
        __disable_irq();    // Disable Interrupts
        cs = 0;
        int cc_reg = RM3100_CCXLSB_REG;
        spi.write(cc_reg);

        for (int i = 0; i < 3; i++) {
            spi.write((current_ccount[i] & 0xFF00)>>8); //MSB
            spi.write(current_ccount[i] & 0x00FF); //LSB
        }
        cs = 1;

        __enable_irq();     // Enable Interrupts
    }
}


//constructor
RM3100::RM3100(): rm3100_service_flag(0),   //init to 0
    sample_rate(1), //init to 1 Hz
    prev_rate(1),  //init to 1 Hz
    cs(SPI_CS),     //init to SPI_CS
    drdy(D9),        //init to D9
    spi(SPI_MOSI, SPI_MISO, SPI_SCK) //spi pins init
{ 
    //Init to default
    for (int i = 0; i < 3; i++)
    {
        current_ccount[i] = DEFAULTCCOUNT;
        current_gain[i] = DEFAULTGAIN;
    }
        
};