Skip to content

AS7331 returns same values each time #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
scottkildall opened this issue Apr 30, 2025 · 7 comments
Closed

AS7331 returns same values each time #12

scottkildall opened this issue Apr 30, 2025 · 7 comments

Comments

@scottkildall
Copy link

AS7331 Sparkfun Sensor and when I call the read sensors functions with the example sketches, I get the same return values each time.

UVA:2.66 UVB:2.95 UVC:1.30

It seems like this problem was reported on this thread but without resolution.

Serial Output:
AS7331 UV A/B/C Command (One-shot) mode Example.
Sensor began.
Set mode to command.
UVA:0.00 UVB:0.00 UVC:0.00
UVA:2.66 UVB:2.95 UVC:1.30
UVA:2.66 UVB:2.95 UVC:1.30
UVA:2.66 UVB:2.95 UVC:1.30
UVA:2.66 UVB:2.95 UVC:1.30
UVA:2.66 UVB:2.95 UVC:1.30
UVA:2.66 UVB:2.95 UVC:1.30

Note that I get exactly the same values returned as what they reported, and it seems like this happens in other posts as well.

I’ve tried this on four different AS7331 sensors that I just purchased, with very similar results — sometimes an initial different value, but is always comes back to these three settings: UVA:2.66 UVB:2.95 UVC:1.30

I purchased the two sets of sensors (2 each) in two different purchases, and two are the Mini Spectral Sensor, two are the regular one.

I’m running this on an ESP32 Lolin D32, and have tried two different ESP32s with the same result. Note: the same ESP32s can use the AS7265x Spectral Triad sensor just fine.

I’ve tried both these sketches with the same result

Example01_Basic_OneShot
Example02_CONT_Mode

Here’s my breadboarded setup. Note running interrupt to pin 15 and the software code works fine.

Libraries Used
esp32 by Espressif Systems
3.2.0

(note, I also tried 3.1.3)

SparkFun AAS7331
2.2.0

SparkFun Toolkit
1.0

I also tried it with the Arduino Uno, and the same results.

Wiring snapshot:

Image

@SFE-Brudnerd
Copy link
Member

Hi @scottkildall the values you're seeing are the default values when 0's are received from the I2C bus. I have a few questions to ask based on the photo. It's a bit difficult to tell but it does look like the pin connections are correct per the LOLIN D32 pinout diagram I found.

  • I do see that the power LED isn't lit, are you able to confirm you're getting power to the board?
  • Do you happen to have a logic analyzer handy? Can you confirm what's being sent across the I2C bus?
  • Have you verified the I2C address being sent aligns with the jumpers on the back of the board?
  • Have you tried adjusting the sensitivity of the sensor? Sunlight alone might not be enough to change it in the default range. This is a very highly configurable sensor, so there's a number of knobs to turn.

@scottkildall
Copy link
Author

I answer to your questions:
• do see that the power LED isn't lit, are you able to confirm you're getting power to the board?
Yes, power is coming into the board. LED is lit. I just took that photo when it was not plugged in.

• Do you happen to have a logic analyzer handy? Can you confirm what's being sent across the I2C bus?
I don't have one.

• Have you verified the I2C address being sent aligns with the jumpers on the back of the board?
Yes, it aligns to the default address: 0x74
If I try the secondary address, it won't initialize properly.

• Have you tried adjusting the sensitivity of the sensor? Sunlight alone might not be enough to change it in the default range.
Okay, I think this is it, if I do something like: myUVSensor.setGain(GAIN_1024);

then I start to see some drastic changes.

• This is a very highly configurable sensor, so there's a number of knobs to turn.
Is there anything else I should be aware of?

@SFE-Brudnerd
Copy link
Member

Due to the complexity of the sensor and not knowing your specific use case and scenario, I'd encourage you to read Chapter 7 of the datasheet and set the gain, conversion time, predivider, and clocks based on figures 27-32. The gain is probably the best variable to try first, but you may be able to get some more range by playing with the predivider and conversion time variables too. Glad you were able to get things working though!

@LouisStAmour
Copy link

Setting gain worked for me, in that at very high gain settings I started to see differences appearing in the numbers. But I noticed that there appeared to be a "floor" at each gain setting where it seemed to like certain values, and would only occasionally deviate from them. The values varied by what gain was set, for example. The default gain is 2.

The following readings were performed in an entirely dark room on a cloudy day that should be mostly devoid of UV (trace amounts present).

It might be interesting to document at each gain level what the sensor prints if the values it receives are zero, since it's not reporting exactly what it received from the sensor.

myUVSensor.setGain(GAIN_16);
UVA:0.33 UVB:0.37 UVC:0.16

myUVSensor.setGain(GAIN_32);
UVA:0.17 UVB:0.18 UVC:0.08

myUVSensor.setGain(GAIN_64);
UVA:0.08 UVB:0.09 UVC:0.04

myUVSensor.setGain(GAIN_128);
UVA:0.04 UVB:0.05 UVC:0.04 (occasionally this last value reads 0.02)

myUVSensor.setGain(GAIN_256);
UVA:0.04 UVB:0.05 UVC:0.03 (occassionally reading higher or lower by 0.02 for all values)

myUVSensor.setGain(GAIN_512);
UVA:0.03 UVB:0.03 UVC:0.03 (varies by up to 0.04 increases)

myUVSensor.setGain(GAIN_1024);
UVA:0.03 UVB:0.03 UVC:0.03 (varies by up to 0.03 increases occasionally, UVC decreases to 0.02 often)

myUVSensor.setGain(GAIN_2048);
UVA:0.03 UVB:0.03 UVC:0.03 (does not vary much, UVC decreases to 0.02 often)

If I'm understanding this correctly, because the values vary the most at a gain of 512x in my environment, that would mean that I should use 512x as the appropriate gain? Or alternatively, does this mean that UV values are low enough as to be undectectable and what I'm seeing are either sensor error, temperature fluctuations, ambient light changes and/or adjustments to the measurements received by the sensor?

Any feedback you might have on the different values at different gain levels would be appreciated. I have to admit, I expected that at some gain level I would see numbers greater than 0.0x, but perhaps I'm trying to measure UV levels that are just too low to detect at these timing intervals?

I wonder if it would make sense to try and run the sensor manually - what I mean is to somehow adjust the interval window during which it takes readings such that just like a camera can capture more data in a low light if the sensor is open longer, I could wait a longer time to capture fine details of UV in dark environments more consistently.'

That said, I'll experiment with the chip in varying amounts of sunlight once I've hooked up a battery to my arduino and wired up an OLED screen. I'm now wondering if I can also hook up a button to adjust the gain on the fly, as that might be useful, and a place to record values. I'm even thinking that if I buy more than one of these, I could maybe get values read at different gain levels simultaneously and compare them. But that assumes the sensor is objectively accurate, and it is likely that sensors can vary unit to unit, and measurements can vary by time (the measurements are unlikely to sync up unless I add logic for that, I presume I would need to use SYND mode) so that might not be useful.

Wait, I just realized that T(CONV) is configurable using setConversionTime().

Okay I was able to get all 0 readings for UVA, UVB and UVC by doing the following (after "Sensor began" but before prepareMeasurement):

    myUVSensor.setDigitalDividerEnabled(false);
    myUVSensor.setGain(GAIN_2048);
    myUVSensor.setConversionTime(TIME_16384MS);

Wait.... that's a bug. The digital divider exists to access higher bits of the register when conversion times are greater than 2^16. Since that works out to 65,000, does that mean the default 64 ms time does not need any digital divider, or am I misunderstanding the data sheet I'm reading for the first time?

    myUVSensor.setDigitalDividerEnabled(true);
    myUVSensor.setDigitalDividerRange(DIV_256);
    myUVSensor.setGain(GAIN_2048);
    myUVSensor.setConversionTime(TIME_16384MS);

The above also gave me zeros. Okay I figured it out, as gain increases, the numbers decrease in Table 7.4, likewise as time increases, the numbers decrease.

Okay... I'm a bit confused now, because I removed my above lines but I'm still getting zeros. I'll have to look into this later. I think the sun went down. Using the sun as a UV source is obviously not exact enough when indoors. :) I can't tell if I'm getting zeros because I broke something in the AS7331 by setting the above values, or if there just isn't enough UV to measure it now. It's weird that I can't get the defaults I was seeing earlier at different gain levels, but perhaps I was just reading different bits of a larger or smaller number, and when the number is 0, it returns 0 regardless. I might need to buy a UV light source for more accurate measurements.

For others like me using an Arduino UNO R4 with QWIIC, you also have to make the following adjustment to get it to use the Qwiic wire (Wire1) instead of the default (Wire):

    Serial.println("AS7331 UV A/B/C Command (One-shot) mode Example.");

    Wire1.begin();

    // Initialize sensor and run default setup.
    if (myUVSensor.begin(kDefaultAS7331Addr, Wire1) == false)

@scottkildall
Copy link
Author

Thanks @SFE-Brudnerd for the suggestions here and @LouisStAmour I'm not sure where to go with your explorations, but let us know.

For @SFE-Brudnerd: my use-case is that I want to get a better idea of what flowers look like with UV-reflected light. I'm not sure if this sensor will do this, but one idea is to reflect blacklight off of flowers (at night) to capture what kinds of UV reflectance they might have.

I may end up working with just sunlight data, for some of my explorations as well — I make music and soundscapes with sensors so there are a number of possibilities with this sensor.

Any advice on use-case scenario #1: getting the UV-reflectance from flowers, would be great. I've done similar investigations (successfully) with IR and some of the other SparkFun sensors.

@LouisStAmour
Copy link

LouisStAmour commented May 5, 2025

I found a document from the sensor manufacturer which says:

Gain and integration time are the most important parameters to affect the counts or digits as sensor results. If these parameters are set to low, then the sensor measures noise; if they are too high, the sensor goes into saturation. Both of these conditions are wrong and will not give proper and acceptable sensor results.

Another document says:

The basics and principles of the ADC are listed in the datasheet [1]. Gain and TINT are the essential parameters (besides Shift) to influence the Counts as the sensor result. The counts correspond to a digital measure of the amount of light received by the sensor with the set gain and integration time. It is recommended to normalize the counts, with a gain of 1 and a 1ms integration time - to get the results independent of the parameter setup (= Basic_counts = RAW_Counts/(Gain*TINT)).

The integration time also determines the size of the counter. At 64 ms, 16-bit is reached, i.e. 65335 counts can be reached before digital saturation is reached (see Figure 23).

It continues:

A measurement aims to obtain optimal counts in which stable results with high accuracy can be achieved. The sensor should not measure noise or be in saturation. The integration time (TINT) is mostly predefined as a large part of the measurement time by the application time. With the gain, the higher value of the counts can also be adjusted. The first step in the measurement is to find optimal counts using the parameters for the application and their limits. This can be done manually step-by-step, or it can be optimized automatically by the GUI using auto-Gain and TINT.

The following figures (Figure 24 and Figure 25) show two examples for an optimized setup to get a maximum number of counts; the first is by using automatic settings and the second by manually setting parameters. The counts for the maximum should be at least 60% to 80% of the maximum achievable "Max Counts". If the results are only in the lower range of the counts (one or two digits), the gain or integration time must be increased. If saturation is indicated for the sensor, the gain or integration time must be reduced.

And then it cautions:

Before starting the measurements, check if the sensor complies with all the operating conditions and which disturbances may influence the measurements.

In particular, the angle of incidence of less than 10° deviation from the vertical must be observed, in order to perform the measurements with the specified filter functions. Otherwise, the results of the sensor measurements will be erroneous.

Avoid saturating the sensor and check the sensor settings (gain, integration time, and shifter) to ensure it works in an optimized working range close to FSR (Full Scale Range). Work with a dynamic sensor setting in case of strongly changed sensor inputs. If the setup variables change in the measurement series, the sensor results must be converted to a form independent of the sensor setup before calibration. Use “Basic-Counts” as an independent sensor result for the following corrections.

The following list includes some examples, which can affect the accuracy, more or less depending on the application:

● Basic noise (e.g. dark current - note, dark currents depend on temperatures)
● Gain error (none linearity)
● Temperature and ageing effects from LEDs
● Overcrossing inside the sensor system
● Ambient light

Such deviations and disturbances are measured within tests and can be corrected customer or application-specifically. This can be done using external software tools like MATLAB or Excel, with the GUI results from the protocol files, or using the correction function that was implemented in the GUI. These corrections are based on the AS7331 libraries, which use the files for corrections and calibrations (see chapter 8.3). If these files are prepared and used in combination with the GUI, then the sensor outputs can also be as application-specific units.

The GUI and hardware can be used to prepare the sensor and application calibration. The following chapter (chapter 9.3) gives an example of how to prepare the corrections and mapping; to measure a UV LED and map the sensor results into the application-specific unit for irradiation in W/sqm

Since I'm referencing it so much, I might as well link to this second document here: https://look.ams-osram.com/m/a0b32047fab3b020/original/AS7331_EVK_Logger_UG001037_3-00.pdf

Figures 26 and 27 on page 32 are quite interesting, because they start a section that highlights how a standard UV LED might be interpreted by the sensors based on spectrometer readings. Those two diagrams show the ideal readings, followed by the sensor counts detected by the sensor:

The LED irradiance in UVA/B/C measured by the spectrometer is more or less linear (Figure 28) and will be used as the target to map the sensor results into the unit W/sqm per filter response for UVA-UVC. Temperature deviations or other disruptions were not optimized and considered to explain this example. It should be done in the case of any device development, depending on the required series stability, repeatability, and accuracy. The sensor results were measured with the set of Gain = 2048 and TINT = 1024 ms under identical conditions. The results are shown in the following figures (Figure 29 to Figure 31).

This reliance on raw values and on adjusting the gain and integration time in realtime is something I've seen other projects rely on too:

https://github.com/michaelbaisch/uv_meter/blob/main/README.md for example apparently shows raw values and if the values look saturated or not detailed enough, you're expected to adjust the gain and/or time yourself. I have to admit, the latter project has me looking up prices on Flipper Zero boards, that is very cool and nicely integrated. (Edit: Never mind, the Flipper Zero is too expensive for what limited utility it has. I don't need a battery with a box that costs $200 when I can buy everything except the box for less than $100 or so.)

@scottkildall
Copy link
Author

closing this one out, since my report seems to have been addressed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants