I have bought VL6180X proximity sensor on breakout (Aliexpress) originally designed for use with arduino. I have tried it use with Raspberry Pi and STM32 (on STM32F429 discovery board). Sensor is in room environment which my mobile phone reports as about 1000 lux. Sensor could be used in ranging mode and ambient light sensor (ALS) mode. In ranging mode it works good in range of 2cm to 18cm (which is OK) but when used in ALS mode it reports all time zero. I modified STM library to report raw value received from sensor before any recalculations to lux and value from the sensor is all time zero or some number near to zero (like 1, 2, or 3). I have tried to modify SYSALS__INTERMEASUREMENT_PERIOD, SYSALS__INTEGRATION_PERIOD and SYSALS__ANALOGUE_GAIN to different values but result from sensor was still very low value (about 10). When i tried to light sensor with xenon light of my phone in original settings value was about 70 (0 lux after recalculation) and after modification of registers it was about 90 (1 lux after recalculation).

Have you any idea what I am doing wrong? Why are the values soo low?

This is my code. There are functions to configure and control UART (could be ignored), then configuration of I2C bus to the sensor (probably could be ignored), function for configure external interrupt on STM (could be ignored) and then main and EXTI3_IRQHandler which handles application logic. There are commented my register improvements and ranging test.

#include "stm32f4xx.h"

#include "vl6180x_api.h"
#include <string.h>
#include <stdlib.h>

void UART_Init() {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

    GPIO_InitTypeDef gpio;
    gpio.GPIO_Mode = GPIO_Mode_AF;
    gpio.GPIO_OType = GPIO_OType_PP;
    gpio.GPIO_Pin = GPIO_Pin_6;
    gpio.GPIO_PuPd = GPIO_PuPd_UP;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
    GPIO_Init(GPIOC, &gpio);

    USART_InitTypeDef uart;
    uart.USART_BaudRate = 115200;
    uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    uart.USART_Mode = USART_Mode_Tx;
    uart.USART_Parity = USART_Parity_No;
    uart.USART_StopBits = USART_StopBits_1;
    uart.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART6, &uart);

void UART_SendByte(char byte) {
    while (!USART_GetFlagStatus(USART6, USART_FLAG_TXE))
    USART_SendData(USART6, byte);

void UART_SendString(char* string) {
    for (int i = 0; i < strlen(string); i++) {

void VL6180x_I2CInit() {
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef gpio;
    gpio.GPIO_Mode = GPIO_Mode_AF;
    gpio.GPIO_OType = GPIO_OType_OD;
    gpio.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio.GPIO_Speed = GPIO_Speed_25MHz;

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2);

    GPIO_Init(GPIOB, &gpio);

    I2C_InitTypeDef i2c;
    i2c.I2C_Mode = I2C_Mode_I2C;
    i2c.I2C_Ack = I2C_Ack_Disable;
    i2c.I2C_AcknowledgedAddress = 0x00;
    i2c.I2C_DutyCycle = I2C_DutyCycle_2;
    i2c.I2C_ClockSpeed = 400000;
    I2C_Init(I2C2, &i2c);


    I2C_Cmd(I2C2, ENABLE);

    while (I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) {
        I2C_GenerateSTOP(I2C2, ENABLE);
        I2C_SoftwareResetCmd(I2C2, ENABLE);
        I2C_SoftwareResetCmd(I2C2, DISABLE);


int VL6180x_I2CWrite(VL6180xDev_t addr, uint8_t *buff, uint8_t len) {
    int status = 0;
    I2C_GenerateSTART(I2C2, ENABLE);
    while (!I2C_GetITStatus(I2C2, I2C_IT_SB)) {

    I2C_Send7bitAddress(I2C2, addr << 1, I2C_Direction_Transmitter);
    while (!I2C_GetITStatus(I2C2, I2C_IT_ADDR)) {
    uint32_t sr2 = I2C2->SR2;

    int lenInt = len;
    while (lenInt--) {
        while (!I2C_GetITStatus(I2C2, I2C_IT_TXE)) {
        I2C_SendData(I2C2, *(buff++));

    while (!I2C_GetITStatus(I2C2, I2C_IT_BTF)) {
    I2C_GenerateSTOP(I2C2, ENABLE);

    return status;

void DISP_ExecLoopBody() {
    for (int i = 0; i < 100000; i++) {

void VL6180x_Failed(char* message) {
    while (1) {

int VL6180x_I2CRead(VL6180xDev_t addr, uint8_t *buff, uint8_t len) {
    I2C_GenerateSTART(I2C2, ENABLE);
    I2C_ITConfig(I2C2, I2C_IT_SB, ENABLE);
    I2C_ITConfig(I2C2, I2C_IT_ADDR, ENABLE);
    I2C_ITConfig(I2C2, I2C_IT_RXNE, ENABLE);
    I2C_ITConfig(I2C2, I2C_IT_BTF, ENABLE);

    while (!I2C_GetITStatus(I2C2, I2C_IT_SB)) {
    I2C_Send7bitAddress(I2C2, addr << 1, I2C_Direction_Receiver);

    while (!I2C_GetITStatus(I2C2, I2C_IT_ADDR)) {
    uint32_t sr2 = I2C2->SR2;

    I2C_AcknowledgeConfig(I2C2, ENABLE);
    int intLen = len;
    while (intLen--) {
        while (!I2C_GetITStatus(I2C2, I2C_IT_RXNE)) {

        *(buff++) = I2C_ReceiveData(I2C2);
        if (intLen == 0) {
            I2C_AcknowledgeConfig(I2C2, DISABLE);

    while (!I2C_GetITStatus(I2C2, I2C_IT_RXNE)) {
    uint32_t dr = I2C2->DR;
    I2C_GenerateSTOP(I2C2, ENABLE);

    return 0;

void EXTI_PC3_init() {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    GPIO_InitTypeDef gpio;
    gpio.GPIO_Mode = GPIO_Mode_IN;
    gpio.GPIO_OType = GPIO_OType_PP;
    gpio.GPIO_Pin = GPIO_Pin_3;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, &gpio);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource3);

    EXTI_InitTypeDef exti;
    exti.EXTI_Line = EXTI_Line3;
    exti.EXTI_LineCmd = ENABLE;
    exti.EXTI_Mode = EXTI_Mode_Interrupt;
    exti.EXTI_Trigger = EXTI_Trigger_Rising;

    NVIC_InitTypeDef nvic;
    nvic.NVIC_IRQChannel = EXTI3_IRQn;
    nvic.NVIC_IRQChannelCmd = ENABLE;
    nvic.NVIC_IRQChannelPreemptionPriority = 0;
    nvic.NVIC_IRQChannelSubPriority = 0;

VL6180xDev_t myDev = 0x29;

int main(void) {


    for (int i = 0; i < 1000000; i++) {

    uint8_t devId;
    VL6180x_RdByte(myDev, 0x0000, &devId);

    uint32_t deviceVer;
    VL6180x_RdDWord(myDev, 0x0001, &deviceVer);
    uint32_t model_rev_maj = (deviceVer & 0xFF000000) >> 24;
    uint32_t model_rev_min = (deviceVer & 0x00FF0000) >> 16;
    uint32_t module_rev_maj = (deviceVer & 0x0000FF00) >> 8;
    uint32_t module_rev_min = (deviceVer & 0x000000FF) >> 0;

    uint32_t id;
    VL6180x_RdDWord(myDev, 0x0006, &id);
    uint32_t y = (id & 0xF0000000) >> 28;
    uint32_t m = (id & 0x0F000000) >> 24;
    uint32_t d = (id & 0x00F80000) >> 19;
    uint32_t p = (id & 0x00070000) >> 16;
    uint32_t s = (id & 0x0000FFF);

    //VL6180x_FilterSetState(myDev, 0);

    VL6180x_AlsSetIntegrationPeriod(myDev, 80);
    VL6180x_AlsSetInterMeasurementPeriod(myDev, 10);
    VL6180x_AlsSetAnalogueGain(myDev, 7);

    VL6180x_AlsConfigInterrupt(myDev, CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY);
    VL6180x_AlsSetSystemMode(myDev, MODE_START_STOP | MODE_CONTINUOUS);

    while (1) {}

    /*while (1) {
        VL6180x_RangeData_t Range;
        VL6180x_RangePollMeasurement(myDev, &Range);

         char buff[10];
         itoa(Range.range_mm, buff, 10);
         int len = strlen(buff);
         buff[len] = '\r';
         buff[len + 1] = '\n';
         buff[len + 2] = '\0';


void EXTI3_IRQHandler() {
    if (EXTI_GetITStatus(EXTI_Line3)) {
        uint16_t Als = 0;
        lux_t lux;

        VL6180x_RdWord(myDev, RESULT_ALS_VAL, &Als);
        VL6180x_AlsGetLux(myDev, &lux);


        char buff[100];
        sprintf(buff, "RAW_ALS: %d\tLUX: %d\r\n", Als, lux);

Changing the gain or other settings will have no effect on the number coming out of the AlsGetlux() function. Why? because you are gaining it up in the hardware, then dividing out the gain in the int VL6180X::VL6180x_AlsGetLux(VL6180xDev_t dev, lux_t *pLux) function.

 status = VL6180x_RdWord(dev, RESULT_ALS_VAL, &RawAls);
        if (!status) {
            /* wer are yet here at no fix point */
            IntPeriod = VL6180xDevDataGet(dev, IntegrationPeriod);
            AlsScaler = VL6180xDevDataGet(dev, AlsScaler);
            IntPeriod++; /* what stored is real time  ms -1 and it can be 0 for or 0 or 1ms */
            luxValue = (uint32_t)RawAls * LuxResxIntIme; /* max # 16+8bits + 6bit (0.56*100)  */
            luxValue /= IntPeriod;                         /* max # 16+8bits + 6bit 16+8+1 to 9 bit */
            /* between  29 - 21 bit */
            AlsAnGain = VL6180xDevDataGet(dev, AlsGainCode);
            GainFix = AlsGainLookUp[AlsAnGain];
            luxValue = luxValue / (AlsScaler * GainFix);
            *pLux = luxValue;

If you have ALSensor*5=register register/5=lux
or ALSensor*20=register register/20=lux is the same thing. So gain will not change the end value, but it will change the register value, so look at that.

You can see this in table 16 of the datasheet, make sure you adjust for the cover glass.

enter image description here

If your getting the same value out of the register I'd be worried.

enter image description here

The last thing is measure the int pin and the SDA ans SCL with an oscilloscope or something to make sure the integration time is really happening correctly.

  • \$\begingroup\$ I know that gain does not affect LUX output value but affects ALS output value. When gain is 40 sensor returns 1 - 3 ALS. I have measured by logic analyzer that Integration period works properly. Value grow as integration and intermeasurement period grows. When i set all to maximum i get every 2,5 seconds ALS value around 10 which is still so low i think. \$\endgroup\$ – Misaz Sep 20 '18 at 13:44
  • \$\begingroup\$ Do you have glass or the bare sensor? \$\endgroup\$ – Voltage Spike Sep 24 '18 at 16:23
  • \$\begingroup\$ I have no glass on it. \$\endgroup\$ – Misaz Sep 24 '18 at 18:06
  • \$\begingroup\$ Another thing that might cause the sensor readings to be different is spectral differences between your source and detector. One test you could do is take it out in daylight at noon and put the detector's surface 'normal' to the sun. You should get ~100k lux. with glass. Without glass it would rail out. If you don't, the detector could be broken. I'll see if I can spot anything else with the way you have set the detector up \$\endgroup\$ – Voltage Spike Sep 25 '18 at 15:26
  • \$\begingroup\$ You are also not calling ALSgetmeasurment github.com/stm32duino/VL6180X/…\ \$\endgroup\$ – Voltage Spike Sep 25 '18 at 15:33

I have bought the new one sensor and it is working good. Soo I think that my first sensor was broken.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.