Seeed-Studio/Grove_Drivers_for_Wio

Rework of Sunlight sensor doesn't work

airdissy opened this issue · 5 comments

Hello,
I'm tying to convert the official arduino driver for sunllight sensor with suli support.
I could pass ./scan_drivers.py without errors now.
After trying on my wio link, all answers remain 0 for all functions.

could it be a wrong address? I took it from official driver

define SI114X_ADDRESS (0x60<<1)

Wrong way to use Suly on the two read functions?

/*--------------------------------------------------------//
read half word(2 bytes) data from si114x
 */
uint16_t GroveSI114X::ReadHalfWord(uint8_t reg)
{
    uint8_t buffer2[2];
    suli_i2c_read(this->i2c, SI114X_ADDRESS, buffer2, 2);
}

and

/*--------------------------------------------------------//
read one byte data from si114x
 */
uint8_t GroveSI114X::ReadByte(uint8_t reg)
{
    uint8_t buffer[1];
    suli_i2c_read(this->i2c, SI114X_ADDRESS, buffer, 1);
}

thanks for help

Here are my two files

/*
 * grove_sunlight.h
 * Copyright (c) 2015 seeed technology inc.
 * Website : www.seeed.cc
 * Author : Fuhua.Chen adapted by Airdissy for Wiolink
 * Modified Time: August 2016
 *
 * The MIT License (MIT)
 *
 * 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.
 */

#ifndef __GROVE_SUNLIGHT_H__
#define __GROVE_SUNLIGHT_H__

#include "suli2.h"

//GROVE_NAME        "Grove - Sunlight Sensor2"
//SKU               101020089
//IF_TYPE           I2C
//IMAGE_URL         http://www.seeedstudio.com/wiki/images/b/b5/Grove_sunlight_sensor_view.jpg
//DESCRIPTION       "Grove - Sunlight Sensor is a multi-channel digital light sensor, which has the ability to detect UV-light, visible light and infrared light"
//WIKI_URL          http://www.seeedstudio.com/wiki/Grove_-_Sunlight_Sensor
//ADDED_AT          "2016-07-21"
//AUTHOR            "Fuhua.Chen adapted by Airdissy for Wiolink"

#define SI114X_ADDRESS  (0x60<<1)

#define SI114X_QUERY 0X80
#define SI114X_SET 0XA0
#define SI114X_NOP 0X0
#define SI114X_RESET 0X01
#define SI114X_BUSADDR 0X02
#define SI114X_PS_FORCE 0X05
#define SI114X_GET_CAL 0X12
#define SI114X_ALS_FORCE 0X06
#define SI114X_PSALS_FORCE 0X07
#define SI114X_PS_PAUSE 0X09
#define SI114X_ALS_PAUSE 0X0A
#define SI114X_PSALS_PAUSE 0XB
#define SI114X_PS_AUTO 0X0D
#define SI114X_ALS_AUTO 0X0E
#define SI114X_PSALS_AUTO 0X0F
//
//IIC REGISTERS
//
#define SI114X_PART_ID 0X00
#define SI114X_REV_ID 0X01
#define SI114X_SEQ_ID 0X02
#define SI114X_INT_CFG 0X03
#define SI114X_IRQ_ENABLE 0X04
#define SI114X_IRQ_MODE1 0x05
#define SI114X_IRQ_MODE2 0x06
#define SI114X_HW_KEY 0X07
#define SI114X_MEAS_RATE0 0X08
#define SI114X_MEAS_RATE1 0X09
#define SI114X_PS_RATE 0X0A
#define SI114X_PS_LED21 0X0F
#define SI114X_PS_LED3 0X10
#define SI114X_UCOEFF0 0X13
#define SI114X_UCOEFF1 0X14
#define SI114X_UCOEFF2 0X15
#define SI114X_UCOEFF3 0X16
#define SI114X_WR 0X17
#define SI114X_COMMAND 0X18
#define SI114X_RESPONSE 0X20
#define SI114X_IRQ_STATUS 0X21
#define SI114X_ALS_VIS_DATA0 0X22
#define SI114X_ALS_VIS_DATA1 0X23
#define SI114X_ALS_IR_DATA0 0X24
#define SI114X_ALS_IR_DATA1 0X25
#define SI114X_PS1_DATA0 0X26
#define SI114X_PS1_DATA1 0X27
#define SI114X_PS2_DATA0 0X28
#define SI114X_PS2_DATA1 0X29
#define SI114X_PS3_DATA0 0X2A
#define SI114X_PS3_DATA1 0X2B
#define SI114X_AUX_DATA0_UVINDEX0 0X2C
#define SI114X_AUX_DATA1_UVINDEX1 0X2D
#define SI114X_RD 0X2E
#define SI114X_CHIP_STAT 0X30
//
//Parameters
//

#define SI114X_CHLIST 0X01
#define SI114X_CHLIST_ENUV 0x80
#define SI114X_CHLIST_ENAUX 0x40
#define SI114X_CHLIST_ENALSIR 0x20
#define SI114X_CHLIST_ENALSVIS 0x10
#define SI114X_CHLIST_ENPS1 0x01
#define SI114X_CHLIST_ENPS2 0x02
#define SI114X_CHLIST_ENPS3 0x04

#define SI114X_PSLED12_SELECT 0X02
#define SI114X_PSLED3_SELECT 0X03

#define SI114X_PS_ENCODE 0X05
#define SI114X_ALS_ENCODE 0X06

#define SI114X_PS1_ADCMUX 0X07
#define SI114X_PS2_ADCMUX 0X08
#define SI114X_PS3_ADCMUX 0X09

#define SI114X_PS_ADC_COUNTER 0X0A
#define SI114X_PS_ADC_GAIN 0X0B
#define SI114X_PS_ADC_MISC 0X0C

#define SI114X_ALS_IR_ADC_MUX 0X0E
#define SI114X_AUX_ADC_MUX 0X0F

#define SI114X_ALS_VIS_ADC_COUNTER 0X10
#define SI114X_ALS_VIS_ADC_GAIN 0X11
#define SI114X_ALS_VIS_ADC_MISC 0X12

#define SI114X_LED_REC 0X1C

#define SI114X_ALS_IR_ADC_COUNTER 0X1D
#define SI114X_ALS_IR_ADC_GAIN 0X1E
#define SI114X_ALS_IR_ADC_MISC 0X1F
//
//USER SETTINGS DEFINE
//
//ADCMUX
#define SI114X_ADCMUX_SMALL_IR 0x00
#define SI114X_ADCMUX_VISIABLE 0x02
#define SI114X_ADCMUX_LARGE_IR 0x03
#define SI114X_ADCMUX_NO 0x06
#define SI114X_ADCMUX_GND 0x25
#define SI114X_ADCMUX_TEMPERATURE 0x65
#define SI114X_ADCMUX_VDD 0x75
//LED SEL
#define SI114X_PSLED12_SELECT_PS1_NONE 0x00
#define SI114X_PSLED12_SELECT_PS1_LED1 0x01
#define SI114X_PSLED12_SELECT_PS1_LED2 0x02
#define SI114X_PSLED12_SELECT_PS1_LED3 0x04
#define SI114X_PSLED12_SELECT_PS2_NONE 0x00
#define SI114X_PSLED12_SELECT_PS2_LED1 0x10
#define SI114X_PSLED12_SELECT_PS2_LED2 0x20
#define SI114X_PSLED12_SELECT_PS2_LED3 0x40
#define SI114X_PSLED3_SELECT_PS2_NONE 0x00
#define SI114X_PSLED3_SELECT_PS2_LED1 0x10
#define SI114X_PSLED3_SELECT_PS2_LED2 0x20
#define SI114X_PSLED3_SELECT_PS2_LED3 0x40
//ADC GAIN DIV
#define SI114X_ADC_GAIN_DIV1 0X00
#define SI114X_ADC_GAIN_DIV2 0X01
#define SI114X_ADC_GAIN_DIV4 0X02
#define SI114X_ADC_GAIN_DIV8 0X03
#define SI114X_ADC_GAIN_DIV16 0X04
#define SI114X_ADC_GAIN_DIV32 0X05
//LED CURRENT
#define SI114X_LED_CURRENT_5MA 0X01
#define SI114X_LED_CURRENT_11MA 0X02
#define SI114X_LED_CURRENT_22MA 0X03
#define SI114X_LED_CURRENT_45MA 0X04
//Recovery period the  ADC takes before making a PS measurement
#define SI114X_ADC_COUNTER_1ADCCLK 0X00
#define SI114X_ADC_COUNTER_7ADCCLK 0X01
#define SI114X_ADC_COUNTER_15ADCCLK 0X02
#define SI114X_ADC_COUNTER_31ADCCLK 0X03
#define SI114X_ADC_COUNTER_63ADCCLK 0X04
#define SI114X_ADC_COUNTER_127ADCCLK 0X05
#define SI114X_ADC_COUNTER_255ADCCLK 0X06
#define SI114X_ADC_COUNTER_511ADCCLK 0X07
//ADC MISC
#define SI114X_ADC_MISC_LOWRANGE 0X00
#define SI114X_ADC_MISC_HIGHRANGE 0X20
#define SI114X_ADC_MISC_ADC_NORMALPROXIMITY 0X00
#define SI114X_ADC_MISC_ADC_RAWADC 0X04
//INT OE
#define SI114X_INT_CFG_INTOE 0X01
//IRQ ENABLE
#define SI114X_IRQEN_ALS 0x01
#define SI114X_IRQEN_PS1 0x04
#define SI114X_IRQEN_PS2 0x08
#define SI114X_IRQEN_PS3 0x10

class GroveSI114X
{
public:
    GroveSI114X(int pinsda, int pinscl);

    bool Begin(void);
    void Reset(void);
    void DeInit(void);
    uint8_t  ReadParamData(uint8_t Reg);
    uint8_t  WriteParamData(uint8_t Reg,uint8_t Value);

    /**
     * Read visible light
     *
     * @param VL - unit: VL
     *
     * @return bool
     */
    bool read_visiblelight(float *VL);

    /**
     * Read IR Value
     *
     * @param IR - unit: IR
     *
     * @return bool
     */
    bool read_IR(float *IR);


    /**
     * Read current level of UV
     *
     * @param UV - unit: UV
     *
     * @return bool
     */
    bool read_UV(float *UV);

    /**
     * Test connection
     *
     * @param CX - unit: CX
     *
     * @return bool
     */
    bool read_CX(float *CX);

    char *get_last_error() { return error_desc; };

 private:
    I2C_T *i2c;
    void  WriteByte(uint8_t Reg, uint8_t Value);
    uint8_t cmdbuf[2];
    uint8_t  ReadByte(uint8_t Reg);
    uint16_t ReadHalfWord(uint8_t Reg);

    char *error_desc;
};

#endif

And file Grove_sunlight.cpp

/*
 * grove_sunlight.cpp
 * Copyright (c) 2015 seeed technology inc.
 * Website : www.seeed.cc
 * Author : Fuhua.Chen adapted by Airdissy for WioLink
 * Modified Time: August 2016
 *
 * The MIT License (MIT)
 *
 * 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 "suli2.h"
#include "grove_sunlight.h"

/*--------------------------------------------------------//
default init

 */


GroveSI114X::GroveSI114X(int pinsda, int pinscl)
{
    this->i2c = (I2C_T *)malloc(sizeof(I2C_T));
    suli_i2c_init(i2c, pinsda, pinscl);
    Begin();

}
void GroveSI114X::DeInit(void)
{  
    //ENABLE UV reading  
    //these reg must be set to the fixed value
    WriteByte(SI114X_UCOEFF0, 0x29);
    WriteByte(SI114X_UCOEFF1, 0x89);
    WriteByte(SI114X_UCOEFF2, 0x02);
    WriteByte(SI114X_UCOEFF3, 0x00);
    WriteParamData(SI114X_CHLIST, SI114X_CHLIST_ENUV |SI114X_CHLIST_ENALSIR | SI114X_CHLIST_ENALSVIS |SI114X_CHLIST_ENPS1);
    //
    //set LED1 CURRENT(22.4mA)(It is a normal value for many LED)
    //
    WriteParamData(SI114X_PS1_ADCMUX, SI114X_ADCMUX_LARGE_IR);
    WriteByte(SI114X_PS_LED21, SI114X_LED_CURRENT_22MA);
    WriteParamData(SI114X_PSLED12_SELECT, SI114X_PSLED12_SELECT_PS1_LED1); //
    //
    //PS ADC SETTING
    //
    WriteParamData(SI114X_PS_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
    WriteParamData(SI114X_PS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
    WriteParamData(SI114X_PS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE|SI114X_ADC_MISC_ADC_RAWADC); 
    //
    //VIS ADC SETTING
    //
    WriteParamData(SI114X_ALS_VIS_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
    WriteParamData(SI114X_ALS_VIS_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK); 
    WriteParamData(SI114X_ALS_VIS_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE);
    //
    //IR ADC SETTING
    //
    WriteParamData(SI114X_ALS_IR_ADC_GAIN, SI114X_ADC_GAIN_DIV1);
    WriteParamData(SI114X_ALS_IR_ADC_COUNTER, SI114X_ADC_COUNTER_511ADCCLK);
    WriteParamData(SI114X_ALS_IR_ADC_MISC, SI114X_ADC_MISC_HIGHRANGE);
    //
    //interrupt enable
    //
    WriteByte(SI114X_INT_CFG, SI114X_INT_CFG_INTOE);  
    WriteByte(SI114X_IRQ_ENABLE, SI114X_IRQEN_ALS);  
    //
    //AUTO RUN
    //
    WriteByte(SI114X_MEAS_RATE0, 0xFF);
    WriteByte(SI114X_COMMAND, SI114X_PSALS_AUTO);
}

/*--------------------------------------------------------//
 Init the si114x and begin to collect data  
 */

bool GroveSI114X::Begin(void)
{
    //
    //Init IIC  and reset si1145
    //
    if(ReadByte(SI114X_PART_ID)!=0X45)
    {
    return false;
    }
    Reset();
    //
    //INIT 
    //
    DeInit();
    return true;
}
/*--------------------------------------------------------//
reset the si114x 
inclue IRQ reg, command regs...

 */
void GroveSI114X::Reset(void)
{
    WriteByte(SI114X_MEAS_RATE0, 0);
    WriteByte(SI114X_MEAS_RATE1, 0);
    WriteByte(SI114X_IRQ_ENABLE, 0);
    WriteByte(SI114X_IRQ_MODE1, 0);
    WriteByte(SI114X_IRQ_MODE2, 0);
    WriteByte(SI114X_INT_CFG, 0);
    WriteByte(SI114X_IRQ_STATUS, 0xFF);
    WriteByte(SI114X_COMMAND, SI114X_RESET);
    delay(10);
    WriteByte(SI114X_HW_KEY, 0x17);
    delay(10);
}
/*--------------------------------------------------------//
write one byte into si114x's reg

 */
void GroveSI114X::WriteByte(uint8_t reg, uint8_t val)
{
    cmdbuf[0] = reg;
    cmdbuf[1] = val;
    suli_i2c_write(i2c, SI114X_ADDRESS, cmdbuf, 2);
}

/*--------------------------------------------------------//
read one byte data from si114x
 */
uint8_t GroveSI114X::ReadByte(uint8_t reg)
{
    uint8_t buffer[1];
    suli_i2c_read(this->i2c, SI114X_ADDRESS, buffer, 1);
}


/*--------------------------------------------------------//
read half word(2 bytes) data from si114x
 */
uint16_t GroveSI114X::ReadHalfWord(uint8_t reg)
{
    uint8_t buffer2[2];
    suli_i2c_read(this->i2c, SI114X_ADDRESS, buffer2, 2);
}


/*--------------------------------------------------------//
read param data

 */
uint8_t GroveSI114X::ReadParamData(uint8_t Reg)
{
    WriteByte(SI114X_COMMAND, Reg | SI114X_QUERY);
    return ReadByte(SI114X_RD);
}


/*--------------------------------------------------------//
writ param data
 */
uint8_t GroveSI114X::WriteParamData(uint8_t Reg,uint8_t Value)
{
    //write Value into PARAMWR reg first
    WriteByte(SI114X_WR, Value);
    WriteByte(SI114X_COMMAND, Reg | SI114X_SET);
    //SI114X writes value out to PARAM_RD,read and confirm its right
    return ReadByte(SI114X_RD);
}

/*--------------------------------------------------------//
Read Visible Value

 */
bool GroveSI114X::read_visiblelight(float *VL)
{
    *VL = ReadHalfWord(SI114X_ALS_VIS_DATA0);
    return true;
}
/*--------------------------------------------------------//
Read IR Value

 */
bool GroveSI114X::read_IR(float *IR)
{
    *IR = ReadHalfWord(SI114X_ALS_IR_DATA0);
    return true;    
} 

/*--------------------------------------------------------//
Read UV Value
this function is a int value ,but the real value must be div 100
 */

bool GroveSI114X::read_UV(float *UV)
{
    *UV = ReadHalfWord(SI114X_AUX_DATA0_UVINDEX0);
    return true;    
}

/*--------------------------------------------------------//
Test connection
 */

bool GroveSI114X::read_CX(float *CX)
{
    *CX = ReadByte(SI114X_PART_ID);
    return true;    
}


Hi @airdissy , I think the problem lies in the implementation of these two functions: ReadHalfWord and ReadByte. You should use the suli_i2c_read_reg function.

Hi KillingJacky,
Fine, I made several changes and now I could connect but it returns the same numbers for all data : 65535? I should have some errors on the definition of "buffer" and "buffer2" regarding the return ?

I declared :

    uint8_t readByte(uint8_t Reg);
    uint16_t readHalfWord(uint8_t Reg);
    uint8_t buffer[1];
    uint16_t buffer2[2];

Here are my changes on the two main function with read_reg

/*********************************************************************************************************
** Function name:           readByte
** Descriptions:            read one byte data from si114x
*********************************************************************************************************/
uint8_t GroveSI114X::readByte(uint8_t reg)
{
    suli_i2c_read_reg(this->i2c, i2cAddress, reg, buffer, 1);
    return buffer[0];
}

/*********************************************************************************************************
** Function name:           readHalfWord
** Descriptions:            read half word(2 bytes) data from si114x
*********************************************************************************************************/
uint16_t GroveSI114X::readHalfWord(uint8_t reg)
{
    suli_i2c_read_reg(this->i2c, i2cAddress, reg, buffer2, 2);
    return (buffer2[0] << 8) | buffer2[1];
}

Thanks a lot

Hi @airdissy , two possible problems I find out,

  1. uint8_t buffer2[2];
  2. return (buffer2[1] << 8) | buffer2[0];

But still can't ignore the possible failure in initialization of the sensor.

Hi,
I made the change but it remains the same.
The initialization of the sensor follow the original driver and use the function below :
/*********************************************************************************************************
** Function name: writeByte
** Descriptions: write one byte into si114x's reg
*********************************************************************************************************/
void GroveSI114X::writeByte(uint8_t reg, uint8_t val)
{
suli_i2c_write_reg(this->i2c, i2cAddress, reg, val, 1);
}
The initialization is made through the begin() function that call either reset() or deInit() function that calls writeByte function

`
GroveSI114X::GroveSI114X(int pinsda, int pinscl)
{
this->i2c = (I2C_T *)malloc(sizeof(I2C_T));
suli_i2c_init(this->i2c, pinsda, pinscl);
i2cAddress = SI114X_ADDRESS;
begin();

}
bool GroveSI114X::begin(void)
{
//
//Init IIC and reset si1145
//
if(readByte(SI114X_PART_ID)!=0X45)
{
return false;
}
reset();
//
//INIT
//
deInit();
return true;
}
`

by the way, I put the address since the beginning to 0X00 but I assume it's correct since I have some data answering.

#define SI114X_ADDRESS (0x00<<1)

Thanks,
Peter

@airdissy please email the source codes to me jacky.shaoxg@gmail.com I will help to debug.