├── .gitignore ├── library.properties ├── examples ├── smux_test │ └── smux_test.ino ├── gpio_example │ └── gpio_example.ino ├── led_test │ └── led_test.ino ├── gpio_input_example │ └── gpio_input_example.ino ├── flicker_detection │ └── flicker_detection.ino ├── plotter_example │ └── plotter_example.ino ├── read_all_channels │ └── read_all_channels.ino ├── get_channel │ └── get_channel.ino ├── basic_counts │ └── basic_counts.ino ├── spectral_interrupts │ └── spectral_interrupts.ino ├── reading_while_looping │ └── reading_while_looping.ino └── synd_mode │ └── synd_mode.ino ├── .github ├── workflows │ └── githubci.yml ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── license.txt ├── README.md ├── code-of-conduct.md ├── Adafruit_AS7341.h └── Adafruit_AS7341.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | html/ 2 | Doxyfile 3 | .vscode/ 4 | .idea/ 5 | *.hex 6 | *.elf 7 | *.log 8 | *.py 9 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit AS7341 2 | version=1.4.1 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Arduino library for the AS7341 sensors in the Adafruit shop 6 | paragraph=Arduino library for the AS7341 sensors in the Adafruit shop 7 | category=Sensors 8 | url=https://github.com/adafruit/Adafruit_AS7341 9 | architectures=* 10 | depends=Adafruit BusIO 11 | -------------------------------------------------------------------------------- /examples/smux_test/smux_test.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | Adafruit_AS7341 as7341; 4 | void setup() { 5 | // communication with the host computer serial monitor 6 | Serial.begin(115200); 7 | while (!Serial) { 8 | delay(1); 9 | } 10 | if (!as7341.begin()){ 11 | Serial.println("Could not find AS7341"); 12 | while (1) { delay(10); } 13 | } 14 | 15 | Serial.println("Setup Atime, ASTEP, Gain"); 16 | as7341.setATIME(100); 17 | as7341.setASTEP(999); 18 | as7341.setGain(AS7341_GAIN_256X); 19 | delay(1000); 20 | } 21 | 22 | void loop() { 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /examples/gpio_example/gpio_example.ino: -------------------------------------------------------------------------------- 1 | /* This example will use the GPIO pin to blink an led */ 2 | 3 | #include 4 | 5 | Adafruit_AS7341 as7341; 6 | 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | 11 | // Wait for communication with the host computer serial monitor 12 | while (!Serial) { 13 | delay(1); 14 | } 15 | 16 | if (!as7341.begin()){ 17 | Serial.println("Could not find AS7341"); 18 | while (1) { delay(10); } 19 | } 20 | // set the GPIO direction to output so we can set it high or low 21 | as7341.setGPIODirection(AS7341_GPIO_OUTPUT); 22 | } 23 | 24 | void loop() { 25 | Serial.println("Setting GPIO High"); 26 | as7341.setGPIOValue(true); 27 | delay(3000); 28 | Serial.println("Setting GPIO Low"); 29 | as7341.setGPIOValue(false); 30 | delay(500); 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/githubci.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Library CI 2 | 3 | on: [pull_request, push, repository_dispatch] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/setup-python@v4 11 | with: 12 | python-version: '3.x' 13 | - uses: actions/checkout@v3 14 | - uses: actions/checkout@v3 15 | with: 16 | repository: adafruit/ci-arduino 17 | path: ci 18 | 19 | - name: pre-install 20 | run: bash ci/actions_install.sh 21 | 22 | - name: test platforms 23 | run: python3 ci/build_platform.py main_platforms 24 | 25 | - name: clang 26 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . 27 | 28 | - name: doxygen 29 | env: 30 | GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} 31 | PRETTYNAME : "Adafruit AS7341 Library" 32 | run: bash ci/doxy_gen_and_deploy.sh 33 | -------------------------------------------------------------------------------- /examples/led_test/led_test.ino: -------------------------------------------------------------------------------- 1 | /* This example will set the onboard LED current to various values and blink 2 | the LED */ 3 | 4 | #include 5 | 6 | Adafruit_AS7341 as7341; 7 | 8 | 9 | void setup() { 10 | Serial.begin(115200); 11 | 12 | // Wait for communication with the host computer serial monitor 13 | while (!Serial) { 14 | delay(1); 15 | } 16 | 17 | if (!as7341.begin()){ 18 | Serial.println("Could not find AS7341"); 19 | while (1) { delay(10); } 20 | } 21 | } 22 | 23 | void loop() { 24 | Serial.println("4 mA LED blink"); 25 | as7341.setLEDCurrent(4); // 4mA 26 | as7341.enableLED(true); 27 | delay(100); 28 | as7341.enableLED(false); 29 | delay(500); 30 | 31 | Serial.println("100 mA LED blink"); 32 | as7341.setLEDCurrent(100); // 100mA 33 | as7341.enableLED(true); 34 | delay(100); 35 | as7341.enableLED(false); 36 | delay(500); 37 | } 38 | -------------------------------------------------------------------------------- /examples/gpio_input_example/gpio_input_example.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example uses the GPIO pin to read a digital 3 | * logic level from an external source and print the result. 4 | */ 5 | 6 | #include 7 | 8 | Adafruit_AS7341 as7341; 9 | 10 | 11 | void setup() { 12 | Serial.begin(115200); 13 | 14 | // Wait for communication with the host computer serial monitor 15 | while (!Serial) { 16 | delay(1); 17 | } 18 | 19 | if (!as7341.begin()){ 20 | Serial.println("Could not find AS7341"); 21 | while (1) { delay(10); } 22 | } 23 | // set the GPIO direction to input so we can read the input 24 | if (!as7341.setGPIODirection(AS7341_GPIO_INPUT)){ 25 | Serial.println("Could not set the GPIO direction to true to enable"); 26 | } 27 | } 28 | 29 | void loop() { 30 | bool gpio_value = as7341.getGPIOValue(); 31 | 32 | Serial.print("GPIO pin is "); 33 | if (gpio_value){ 34 | Serial.println("high"); 35 | } else { 36 | Serial.println("Low"); 37 | } 38 | delay(500); 39 | } 40 | -------------------------------------------------------------------------------- /examples/flicker_detection/flicker_detection.ino: -------------------------------------------------------------------------------- 1 | /* This example will check for light flicker effects. Household incandescent, 2 | fluorescent and LED lights may have flickering */ 3 | 4 | 5 | #include 6 | 7 | Adafruit_AS7341 as7341; 8 | 9 | 10 | void setup() { 11 | // Wait for communication with the host computer serial monitor 12 | Serial.begin(115200); 13 | 14 | while (!Serial) { 15 | delay(1); 16 | } 17 | 18 | if (!as7341.begin()){ 19 | Serial.println("Could not find AS7341"); 20 | while (1) { delay(10); } 21 | } 22 | 23 | as7341.setASTEP(999); 24 | as7341.setGain(AS7341_GAIN_256X); 25 | } 26 | 27 | void loop() { 28 | uint16_t flicker_freq = 0; 29 | 30 | flicker_freq = as7341.detectFlickerHz(); 31 | 32 | if (flicker_freq == 0) { 33 | Serial.println("No flicker detected"); 34 | } 35 | else if (flicker_freq == 1) { 36 | Serial.println("Flicker detected with unknown frequency"); 37 | } 38 | else { 39 | Serial.print("Flicker detected at "); 40 | Serial.print(flicker_freq); 41 | Serial.println(" Hz"); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /examples/plotter_example/plotter_example.ino: -------------------------------------------------------------------------------- 1 | /* This example will use the Arduino plotter to display a select number of wavelengths */ 2 | 3 | #include 4 | 5 | Adafruit_AS7341 as7341; 6 | 7 | 8 | 9 | void setup() { 10 | Serial.begin(115200); 11 | 12 | // Wait for communication with the host computer serial monitor 13 | while (!Serial) { 14 | delay(1); 15 | } 16 | 17 | if (!as7341.begin()){ 18 | Serial.println("Could not find AS7341"); 19 | while (1) { delay(10); } 20 | } 21 | 22 | as7341.setATIME(100); 23 | as7341.setASTEP(100); 24 | as7341.setGain(AS7341_GAIN_256X); 25 | } 26 | 27 | 28 | void loop() { 29 | uint16_t readings[12]; 30 | 31 | if (!as7341.readAllChannels(readings)){ 32 | Serial.println("Error reading all channels!"); 33 | return; 34 | } 35 | 36 | // These are 'out of order' so the colors match the default plotter 37 | // drawing colors :) 38 | // #1 blue 39 | Serial.print(readings[2]); // F3 Blue 40 | Serial.print(", "); 41 | // #2 red 42 | Serial.print(readings[8]); // F7 red 43 | Serial.print(", "); 44 | // #3 green 45 | Serial.print(readings[3]); // F4 green 46 | Serial.print(", "); 47 | // #4 orange 48 | Serial.print(readings[7]); // F6 orange 49 | Serial.print(", "); 50 | // #5 purple 51 | Serial.print(readings[0]); // F1 violet 52 | Serial.print(", "); 53 | Serial.println(); 54 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2019 Bryan Siepert for Adafruit Industries 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holders nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /examples/read_all_channels/read_all_channels.ino: -------------------------------------------------------------------------------- 1 | /* This example will read all channels from the AS7341 and print out reported values */ 2 | 3 | #include 4 | 5 | Adafruit_AS7341 as7341; 6 | 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | 11 | // Wait for communication with the host computer serial monitor 12 | while (!Serial) { 13 | delay(1); 14 | } 15 | 16 | if (!as7341.begin()){ 17 | Serial.println("Could not find AS7341"); 18 | while (1) { delay(10); } 19 | } 20 | 21 | as7341.setATIME(100); 22 | as7341.setASTEP(999); 23 | as7341.setGain(AS7341_GAIN_256X); 24 | } 25 | 26 | void loop() { 27 | uint16_t readings[12]; 28 | 29 | if (!as7341.readAllChannels(readings)){ 30 | Serial.println("Error reading all channels!"); 31 | return; 32 | } 33 | 34 | Serial.print("ADC0/F1 415nm : "); 35 | Serial.println(readings[0]); 36 | Serial.print("ADC1/F2 445nm : "); 37 | Serial.println(readings[1]); 38 | Serial.print("ADC2/F3 480nm : "); 39 | Serial.println(readings[2]); 40 | Serial.print("ADC3/F4 515nm : "); 41 | Serial.println(readings[3]); 42 | Serial.print("ADC0/F5 555nm : "); 43 | 44 | /* 45 | // we skip the first set of duplicate clear/NIR readings 46 | Serial.print("ADC4/Clear-"); 47 | Serial.println(readings[4]); 48 | Serial.print("ADC5/NIR-"); 49 | Serial.println(readings[5]); 50 | */ 51 | 52 | Serial.println(readings[6]); 53 | Serial.print("ADC1/F6 590nm : "); 54 | Serial.println(readings[7]); 55 | Serial.print("ADC2/F7 630nm : "); 56 | Serial.println(readings[8]); 57 | Serial.print("ADC3/F8 680nm : "); 58 | Serial.println(readings[9]); 59 | Serial.print("ADC4/Clear : "); 60 | Serial.println(readings[10]); 61 | Serial.print("ADC5/NIR : "); 62 | Serial.println(readings[11]); 63 | 64 | Serial.println(); 65 | } 66 | -------------------------------------------------------------------------------- /examples/get_channel/get_channel.ino: -------------------------------------------------------------------------------- 1 | /* This example will read all channels from the AS7341 and print out reported values */ 2 | 3 | #include 4 | 5 | Adafruit_AS7341 as7341; 6 | 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | 11 | // Wait for communication with the host computer serial monitor 12 | while (!Serial) { 13 | delay(1); 14 | } 15 | 16 | if (!as7341.begin()){ 17 | Serial.println("Could not find AS7341"); 18 | while (1) { delay(10); } 19 | } 20 | 21 | as7341.setATIME(100); 22 | as7341.setASTEP(999); 23 | as7341.setGain(AS7341_GAIN_256X); 24 | } 25 | 26 | void loop() { 27 | // Read all channels at the same time and store in as7341 object 28 | if (!as7341.readAllChannels()){ 29 | Serial.println("Error reading all channels!"); 30 | return; 31 | } 32 | 33 | // Print out the stored values for each channel 34 | Serial.print("F1 415nm : "); 35 | Serial.println(as7341.getChannel(AS7341_CHANNEL_415nm_F1)); 36 | Serial.print("F2 445nm : "); 37 | Serial.println(as7341.getChannel(AS7341_CHANNEL_445nm_F2)); 38 | Serial.print("F3 480nm : "); 39 | Serial.println(as7341.getChannel(AS7341_CHANNEL_480nm_F3)); 40 | Serial.print("F4 515nm : "); 41 | Serial.println(as7341.getChannel(AS7341_CHANNEL_515nm_F4)); 42 | Serial.print("F5 555nm : "); 43 | Serial.println(as7341.getChannel(AS7341_CHANNEL_555nm_F5)); 44 | Serial.print("F6 590nm : "); 45 | Serial.println(as7341.getChannel(AS7341_CHANNEL_590nm_F6)); 46 | Serial.print("F7 630nm : "); 47 | Serial.println(as7341.getChannel(AS7341_CHANNEL_630nm_F7)); 48 | Serial.print("F8 680nm : "); 49 | Serial.println(as7341.getChannel(AS7341_CHANNEL_680nm_F8)); 50 | 51 | Serial.print("Clear : "); 52 | Serial.println(as7341.getChannel(AS7341_CHANNEL_CLEAR)); 53 | 54 | Serial.print("Near IR : "); 55 | Serial.println(as7341.getChannel(AS7341_CHANNEL_NIR)); 56 | 57 | Serial.println(""); 58 | } -------------------------------------------------------------------------------- /examples/basic_counts/basic_counts.ino: -------------------------------------------------------------------------------- 1 | /** This example will read all channels from the AS7341. 2 | * The raw ADC values will then be converted to basic counts 3 | * according to the sensor's appliation note: 4 | * 5 | * https://ams.com/documents/20143/36005/AS7341_AN000633_1-00.pdf/fc552673-9800-8d60-372d-fc67cf075740 6 | * Section 3.1 7 | * 8 | * BasicCounts = RawSensorValue / ( Gain x IntegrationTime ) 9 | * 10 | * Finally, the converted values are printed out. 11 | */ 12 | #include 13 | 14 | Adafruit_AS7341 as7341; 15 | 16 | void setup() { 17 | Serial.begin(115200); 18 | 19 | // Wait for communication with the host computer serial monitor 20 | while (!Serial) { 21 | delay(1); 22 | } 23 | 24 | if (!as7341.begin()){ 25 | Serial.println("Could not find AS7341"); 26 | while (1) { delay(10); } 27 | } 28 | 29 | as7341.setATIME(100); 30 | as7341.setASTEP(999); 31 | as7341.setGain(AS7341_GAIN_256X); 32 | } 33 | 34 | void loop() { 35 | // put your main code here, to run repeatedly: 36 | uint16_t readings[12]; 37 | float counts[12]; 38 | 39 | if (!as7341.readAllChannels(readings)){ 40 | Serial.println("Error reading all channels!"); 41 | return; 42 | } 43 | 44 | for(uint8_t i = 0; i < 12; i++) { 45 | if(i == 4 || i == 5) continue; 46 | // we skip the first set of duplicate clear/NIR readings 47 | // (indices 4 and 5) 48 | counts[i] = as7341.toBasicCounts(readings[i]); 49 | } 50 | 51 | Serial.print("F1 415nm : "); 52 | Serial.println(counts[0]); 53 | Serial.print("F2 445nm : "); 54 | Serial.println(counts[1]); 55 | Serial.print("F3 480nm : "); 56 | Serial.println(counts[2]); 57 | Serial.print("F4 515nm : "); 58 | Serial.println(counts[3]); 59 | Serial.print("F5 555nm : "); 60 | // again, we skip the duplicates 61 | Serial.println(counts[6]); 62 | Serial.print("F6 590nm : "); 63 | Serial.println(counts[7]); 64 | Serial.print("F7 630nm : "); 65 | Serial.println(counts[8]); 66 | Serial.print("F8 680nm : "); 67 | Serial.println(counts[9]); 68 | Serial.print("Clear : "); 69 | Serial.println(counts[10]); 70 | Serial.print("NIR : "); 71 | Serial.println(counts[11]); 72 | 73 | Serial.println(); 74 | 75 | delay(500); 76 | } 77 | -------------------------------------------------------------------------------- /examples/spectral_interrupts/spectral_interrupts.ino: -------------------------------------------------------------------------------- 1 | /* This example will fire an interrupt when a color channel goes beyond a set limit */ 2 | 3 | #include 4 | 5 | Adafruit_AS7341 as7341; 6 | 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | 11 | // Wait for communication with the host computer serial monitor 12 | while (!Serial) { 13 | delay(1); 14 | } 15 | 16 | if (!as7341.begin()){ 17 | Serial.println("Could not find AS7341"); 18 | while (1) { delay(10); } 19 | } 20 | 21 | Serial.println("********** SETUP *************"); 22 | 23 | Serial.println("Disabling measurements"); 24 | as7341.enableSpectralMeasurement(false); 25 | 26 | // Setup gain and sampling time 27 | as7341.setATIME(100); 28 | as7341.setASTEP(999); 29 | as7341.setGain(AS7341_GAIN_32X); 30 | 31 | as7341.setLowThreshold(250); 32 | as7341.setHighThreshold(10000); 33 | Serial.print("Low threshold set to "); 34 | Serial.println(as7341.getLowThreshold()); 35 | Serial.print("High threshold set to "); 36 | Serial.println(as7341.getHighThreshold()); 37 | 38 | // How many cycles do we have to be outside thresh to 39 | // trigger an interrupt? If AS7341_INT_COUNT_ALL, every cycle 40 | as7341.setAPERS(AS7341_INT_COUNT_ALL); 41 | 42 | // Which channel to trigger on? 43 | as7341.setSpectralThresholdChannel(AS7341_ADC_CHANNEL_4); 44 | 45 | Serial.println("Enabling spectral interrupt"); 46 | as7341.enableSpectralInterrupt(true); 47 | Serial.println("Enabling spectral measurements"); 48 | as7341.enableSpectralMeasurement(true); 49 | Serial.println("*********************************"); 50 | 51 | delay(1000); 52 | } 53 | 54 | void loop() { 55 | // Function defined to read out channels with SMUX configration 1- F1-F4, Clear, NIR 56 | as7341.readAllChannels(); 57 | Serial.print("Clear : "); 58 | Serial.println(as7341.getChannel(AS7341_CHANNEL_CLEAR)); 59 | 60 | uint8_t int_status = as7341.getInterruptStatus(); 61 | if (int_status & 0x80) { 62 | Serial.println("Spectral interrupt"); 63 | } else { 64 | // No IRQ! 65 | return; 66 | } 67 | 68 | uint8_t int_source = as7341.spectralInterruptSource(); 69 | if (int_source & 0x10) { 70 | Serial.println("Thresh low interrupt"); 71 | } 72 | if (int_source & 0x20) { 73 | Serial.println("Thresh high interrupt"); 74 | } 75 | 76 | as7341.clearInterruptStatus(); 77 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adafruit AS7341 [![Build Status](https://github.com/adafruit/Adafruit_AS7341/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_AS7341/actions) 2 | 3 | This is the Adafruit AS7341 11-Channel Spectral Sensor for Arduino 4 | 5 | Tested and works great with the Adafruit AS7341 Breakout Board 6 | [](https://www.adafruit.com/products/4698) 7 | This chip uses I2C to communicate, 2 pins are required to interface 8 | 9 | Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! 10 | 11 | # Installation 12 | To install, use the Arduino Library Manager and search for "Adafruit AS7341" and install the library. 13 | 14 | # Dependencies 15 | * [Adafruit_BusIO](https://github.com/adafruit/Adafruit_BusIO) 16 | # Contributing 17 | 18 | Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/Adafruit_AS7341/blob/master/CODE_OF_CONDUCT.md>) 19 | before contributing to help this project stay welcoming. 20 | 21 | ## Documentation and doxygen 22 | Documentation is produced by doxygen. Contributions should include documentation for any new code added. 23 | 24 | Some examples of how to use doxygen can be found in these guide pages: 25 | 26 | https://learn.adafruit.com/the-well-automated-arduino-library/doxygen 27 | 28 | https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips 29 | 30 | ## Formatting and clang-format 31 | This library uses [`clang-format`](https://releases.llvm.org/download.html) to standardize the formatting of `.cpp` and `.h` files. 32 | Contributions should be formatted using `clang-format`: 33 | 34 | The `-i` flag will make the changes to the file. 35 | ```bash 36 | clang-format -i *.cpp *.h 37 | ``` 38 | If you prefer to make the changes yourself, running `clang-format` without the `-i` flag will print out a formatted version of the file. You can save this to a file and diff it against the original to see the changes. 39 | 40 | Note that the formatting output by `clang-format` is what the automated formatting checker will expect. Any diffs from this formatting will result in a failed build until they are addressed. **Using the `-i` flag is highly recommended.** 41 | 42 | ### clang-format resources 43 | * [Binary builds and source available on the LLVM downloads page](https://releases.llvm.org/download.html) 44 | * [Documentation and IDE integration](https://clang.llvm.org/docs/ClangFormat.html) 45 | 46 | ## About this Driver 47 | 48 | Written by Bryan Siepert for Adafruit Industries. 49 | BSD license, check license.txt for more information 50 | All text above must be included in any redistribution 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /examples/reading_while_looping/reading_while_looping.ino: -------------------------------------------------------------------------------- 1 | /* This example shows to to read all channels from the AS7341 and print out reported values, but allow loop() to run while waiting for the readings */ 2 | #include 3 | 4 | Adafruit_AS7341 as7341; 5 | //TwoWire myWire2(2); 6 | uint16_t readings[12]; 7 | 8 | void setup() 9 | { 10 | Serial.begin(115200); 11 | 12 | // Wait for communication with the host computer serial monitor 13 | while (!Serial) 14 | { 15 | Serial.println("Failed, looping forever"); 16 | delay(1000); 17 | } 18 | 19 | // myWire2.begin(); 20 | Wire.begin(); 21 | delay(20); 22 | 23 | // if (!as7341.begin(0x39, &myWire2)){ //Use TwoWire I2C port 24 | if (!as7341.begin()){ //Default address and I2C port 25 | Serial.println("Could not find AS7341"); 26 | while (1) { delay(10); } 27 | } 28 | 29 | as7341.setATIME(35); 30 | as7341.setASTEP(10000); //This combination of ATIME and ASTEP gives an integration time of about 1sec, so with two integrations, that's 2 seconds for a complete set of readings 31 | as7341.setGain(AS7341_GAIN_256X); 32 | 33 | as7341.startReading(); 34 | } 35 | 36 | void loop() 37 | { 38 | bool timeOutFlag = yourTimeOutCheck(); 39 | if(as7341.checkReadingProgress() || timeOutFlag ) 40 | { 41 | if(timeOutFlag) 42 | {} //Recover/restart/retc. 43 | 44 | Serial.println("\nAha, the reading we started a few cycles back is finished, here it is:"); 45 | //IMPORTANT: make sure readings is a uint16_t array of size 12, otherwise strange things may happen 46 | as7341.getAllChannels(readings); //Calling this any other time may give you old data 47 | printReadings(); 48 | 49 | Serial.println("\nLet's try a reading using readAllChannels (inbuilt delay), waiting..."); 50 | if (!as7341.readAllChannels(readings)) 51 | Serial.println("Error reading all channels!"); 52 | else 53 | printReadings(); 54 | Serial.println("Guess we'll start another reading right away but do some work in the meantime\n"); 55 | as7341.startReading(); 56 | } 57 | 58 | //Do some work in the loop 59 | Serial.println("Working hard"); 60 | delay(500); //Hardly working 61 | } 62 | 63 | bool yourTimeOutCheck() 64 | { 65 | //Fill this in to prevent the possibility of getting stuck forever if you missed the result, or whatever 66 | return false; 67 | } 68 | 69 | void printReadings() 70 | { 71 | Serial.print("ADC0/F1 415nm : "); 72 | Serial.println(readings[0]); 73 | Serial.print("ADC1/F2 445nm : "); 74 | Serial.println(readings[1]); 75 | Serial.print("ADC2/F3 480nm : "); 76 | Serial.println(readings[2]); 77 | Serial.print("ADC3/F4 515nm : "); 78 | Serial.println(readings[3]); 79 | Serial.print("ADC0/F5 555nm : "); 80 | 81 | /* 82 | // we skip the first set of duplicate clear/NIR readings 83 | Serial.print("ADC4/Clear-"); 84 | Serial.println(readings[4]); 85 | Serial.print("ADC5/NIR-"); 86 | Serial.println(readings[5]); 87 | */ 88 | 89 | Serial.println(readings[6]); 90 | Serial.print("ADC1/F6 590nm : "); 91 | Serial.println(readings[7]); 92 | Serial.print("ADC2/F7 630nm : "); 93 | Serial.println(readings[8]); 94 | Serial.print("ADC3/F8 680nm : "); 95 | Serial.println(readings[9]); 96 | Serial.print("ADC4/Clear : "); 97 | Serial.println(readings[10]); 98 | Serial.print("ADC5/NIR : "); 99 | Serial.println(readings[11]); 100 | } 101 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Adafruit Community Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and leaders pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level or type of 9 | experience, education, socio-economic status, nationality, personal appearance, 10 | race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | We are committed to providing a friendly, safe and welcoming environment for 15 | all. 16 | 17 | Examples of behavior that contributes to creating a positive environment 18 | include: 19 | 20 | * Be kind and courteous to others 21 | * Using welcoming and inclusive language 22 | * Being respectful of differing viewpoints and experiences 23 | * Collaborating with other community members 24 | * Gracefully accepting constructive criticism 25 | * Focusing on what is best for the community 26 | * Showing empathy towards other community members 27 | 28 | Examples of unacceptable behavior by participants include: 29 | 30 | * The use of sexualized language or imagery and sexual attention or advances 31 | * The use of inappropriate images, including in a community member's avatar 32 | * The use of inappropriate language, including in a community member's nickname 33 | * Any spamming, flaming, baiting or other attention-stealing behavior 34 | * Excessive or unwelcome helping; answering outside the scope of the question 35 | asked 36 | * Trolling, insulting/derogatory comments, and personal or political attacks 37 | * Public or private harassment 38 | * Publishing others' private information, such as a physical or electronic 39 | address, without explicit permission 40 | * Other conduct which could reasonably be considered inappropriate 41 | 42 | The goal of the standards and moderation guidelines outlined here is to build 43 | and maintain a respectful community. We ask that you don’t just aim to be 44 | "technically unimpeachable", but rather try to be your best self. 45 | 46 | We value many things beyond technical expertise, including collaboration and 47 | supporting others within our community. Providing a positive experience for 48 | other community members can have a much more significant impact than simply 49 | providing the correct answer. 50 | 51 | ## Our Responsibilities 52 | 53 | Project leaders are responsible for clarifying the standards of acceptable 54 | behavior and are expected to take appropriate and fair corrective action in 55 | response to any instances of unacceptable behavior. 56 | 57 | Project leaders have the right and responsibility to remove, edit, or 58 | reject messages, comments, commits, code, issues, and other contributions 59 | that are not aligned to this Code of Conduct, or to ban temporarily or 60 | permanently any community member for other behaviors that they deem 61 | inappropriate, threatening, offensive, or harmful. 62 | 63 | ## Moderation 64 | 65 | Instances of behaviors that violate the Adafruit Community Code of Conduct 66 | may be reported by any member of the community. Community members are 67 | encouraged to report these situations, including situations they witness 68 | involving other community members. 69 | 70 | You may report in the following ways: 71 | 72 | In any situation, you may send an email to . 73 | 74 | On the Adafruit Discord, you may send an open message from any channel 75 | to all Community Helpers by tagging @community helpers. You may also send an 76 | open message from any channel, or a direct message to @kattni#1507, 77 | @tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or 78 | @Andon#8175. 79 | 80 | Email and direct message reports will be kept confidential. 81 | 82 | In situations on Discord where the issue is particularly egregious, possibly 83 | illegal, requires immediate action, or violates the Discord terms of service, 84 | you should also report the message directly to Discord. 85 | 86 | These are the steps for upholding our community’s standards of conduct. 87 | 88 | 1. Any member of the community may report any situation that violates the 89 | Adafruit Community Code of Conduct. All reports will be reviewed and 90 | investigated. 91 | 2. If the behavior is an egregious violation, the community member who 92 | committed the violation may be banned immediately, without warning. 93 | 3. Otherwise, moderators will first respond to such behavior with a warning. 94 | 4. Moderators follow a soft "three strikes" policy - the community member may 95 | be given another chance, if they are receptive to the warning and change their 96 | behavior. 97 | 5. If the community member is unreceptive or unreasonable when warned by a 98 | moderator, or the warning goes unheeded, they may be banned for a first or 99 | second offense. Repeated offenses will result in the community member being 100 | banned. 101 | 102 | ## Scope 103 | 104 | This Code of Conduct and the enforcement policies listed above apply to all 105 | Adafruit Community venues. This includes but is not limited to any community 106 | spaces (both public and private), the entire Adafruit Discord server, and 107 | Adafruit GitHub repositories. Examples of Adafruit Community spaces include 108 | but are not limited to meet-ups, audio chats on the Adafruit Discord, or 109 | interaction at a conference. 110 | 111 | This Code of Conduct applies both within project spaces and in public spaces 112 | when an individual is representing the project or its community. As a community 113 | member, you are representing our community, and are expected to behave 114 | accordingly. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 119 | version 1.4, available at 120 | , 121 | and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). 122 | 123 | For other projects adopting the Adafruit Community Code of 124 | Conduct, please contact the maintainers of those projects for enforcement. 125 | If you wish to use this code of conduct for your own project, consider 126 | explicitly mentioning your moderation policy or making a copy with your 127 | own moderation policy so as to avoid confusion. 128 | -------------------------------------------------------------------------------- /Adafruit_AS7341.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_AS7341.h 3 | 4 | * @mainpage Adafruit AS7341 11-Channel Spectral Sensor 5 | * 6 | * @section intro_sec Introduction 7 | * 8 | * I2C Driver for the Library for the AS7341 11-Channel Spectral Sensor 9 | * 10 | * This is a library for the Adafruit AS7341 breakout: 11 | * https://www.adafruit.com/product/4698 12 | * 13 | * Adafruit invests time and resources providing this open source code, 14 | * please support Adafruit and open-source hardware by purchasing products from 15 | * Adafruit! 16 | * 17 | * @section dependencies Dependencies 18 | * This library depends on the Adafruit BusIO library 19 | * 20 | * @section author Author 21 | * 22 | * Bryan Siepert for Adafruit Industries 23 | * 24 | * @section license License 25 | * 26 | * BSD (see license.txt) 27 | * 28 | * @section HISTORY 29 | * 30 | * v1.0 - First release 31 | */ 32 | 33 | /* 34 | This library is adapted from an example with the following Copyright and 35 | Warranty: 36 | 37 | This is a Hello world example code written for the AS7241 XWing Spectral 38 | Sensor I2C interface with Arduino µC. The main idea is to get fimilar with the 39 | register configuration. This code helps to learn basic settings and procedure 40 | to read out raw values with different SMUX configuration. Also defined the 41 | procedure to set the default flicker detection for 100 and 120 Hz. 42 | 43 | Written by Sijo John @ ams AG, Application Support in October, 2018 44 | 45 | Development environment specifics: Arduino IDE 1.8.5 46 | 47 | This program is distributed in the hope that it will be useful, 48 | but WITHOUT ANY WARRANTY; without even the implied warranty of 49 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 50 | 51 | */ 52 | 53 | #ifndef _ADAFRUIT_AS7341_H 54 | #define _ADAFRUIT_AS7341_H 55 | 56 | #include "Arduino.h" 57 | #include 58 | #include 59 | #include 60 | #define AS7341_I2CADDR_DEFAULT 0x39 ///< AS7341 default i2c address 61 | #define AS7341_CHIP_ID 0x09 ///< AS7341 default device id from WHOAMI 62 | 63 | #define AS7341_WHOAMI 0x92 ///< Chip ID register 64 | 65 | #define AS7341_ASTATUS 0x60 ///< AS7341_ASTATUS (unused) 66 | #define AS7341_CH0_DATA_L_ 0x61 ///< AS7341_CH0_DATA_L (unused) 67 | #define AS7341_CH0_DATA_H_ 0x62 ///< AS7341_CH0_DATA_H (unused) 68 | #define AS7341_ITIME_L 0x63 ///< AS7341_ITIME_L (unused) 69 | #define AS7341_ITIME_M 0x64 ///< AS7341_ITIME_M (unused) 70 | #define AS7341_ITIME_H 0x65 ///< AS7341_ITIME_H (unused) 71 | #define AS7341_CONFIG 0x70 ///< Enables LED control and sets light sensing mode 72 | #define AS7341_STAT 0x71 ///< AS7341_STAT (unused) 73 | #define AS7341_EDGE 0x72 ///< AS7341_EDGE (unused) 74 | #define AS7341_GPIO 0x73 ///< Connects photo diode to GPIO or INT pins 75 | #define AS7341_LED 0x74 ///< LED Register; Enables and sets current limit 76 | #define AS7341_ENABLE \ 77 | 0x80 ///< Main enable register. Controls SMUX, Flicker Detection, Spectral 78 | ///< Measurements and Power 79 | #define AS7341_ATIME 0x81 ///< Sets ADC integration step count 80 | #define AS7341_WTIME 0x83 ///< AS7341_WTIME (unused) 81 | #define AS7341_SP_LOW_TH_L 0x84 ///< Spectral measurement Low Threshold low byte 82 | #define AS7341_SP_LOW_TH_H \ 83 | 0x85 ///< Spectral measurement Low Threshold high byte 84 | #define AS7341_SP_HIGH_TH_L \ 85 | 0x86 ///< Spectral measurement High Threshold low byte 86 | #define AS7341_SP_HIGH_TH_H \ 87 | 0x87 ///< Spectral measurement High Threshold low byte 88 | #define AS7341_AUXID 0x90 ///< AS7341_AUXID (unused) 89 | #define AS7341_REVID 0x91 ///< AS7341_REVID (unused) 90 | #define AS7341_ID 0x92 ///< AS7341_ID (unused) 91 | #define AS7341_STATUS \ 92 | 0x93 ///< Interrupt status registers. Indicates the occourance of an interrupt 93 | #define AS7341_ASTATUS_ 0x94 ///< AS7341_ASTATUS, same as 0x60 (unused) 94 | #define AS7341_CH0_DATA_L 0x95 ///< ADC Channel Data 95 | #define AS7341_CH0_DATA_H 0x96 ///< ADC Channel Data 96 | #define AS7341_CH1_DATA_L 0x97 ///< ADC Channel Data 97 | #define AS7341_CH1_DATA_H 0x98 ///< ADC Channel Data 98 | #define AS7341_CH2_DATA_L 0x99 ///< ADC Channel Data 99 | #define AS7341_CH2_DATA_H 0x9A ///< ADC Channel Data 100 | #define AS7341_CH3_DATA_L 0x9B ///< ADC Channel Data 101 | #define AS7341_CH3_DATA_H 0x9C ///< ADC Channel Data 102 | #define AS7341_CH4_DATA_L 0x9D ///< ADC Channel Data 103 | #define AS7341_CH4_DATA_H 0x9E ///< ADC Channel Data 104 | #define AS7341_CH5_DATA_L 0x9F ///< ADC Channel Data 105 | #define AS7341_CH5_DATA_H 0xA0 ///< ADC Channel Data 106 | #define AS7341_STATUS2 0xA3 ///< Measurement status flags; saturation, validity 107 | #define AS7341_STATUS3 \ 108 | 0xA4 ///< Spectral interrupt source, high or low threshold 109 | #define AS7341_STATUS5 0xA6 ///< AS7341_STATUS5 (unused) 110 | #define AS7341_STATUS6 0xA7 ///< AS7341_STATUS6 (unused) 111 | #define AS7341_CFG0 \ 112 | 0xA9 ///< Sets Low power mode, Register bank, and Trigger lengthening 113 | #define AS7341_CFG1 0xAA ///< Controls ADC Gain 114 | #define AS7341_CFG3 0xAC ///< AS7341_CFG3 (unused) 115 | #define AS7341_CFG6 0xAF ///< Used to configure Smux 116 | #define AS7341_CFG8 0xB1 ///< AS7341_CFG8 (unused) 117 | #define AS7341_CFG9 \ 118 | 0xB2 ///< Enables flicker detection and smux command completion system 119 | ///< interrupts 120 | #define AS7341_CFG10 0xB3 ///< AS7341_CFG10 (unused) 121 | #define AS7341_CFG12 \ 122 | 0xB5 ///< Spectral threshold channel for interrupts, persistence and auto-gain 123 | #define AS7341_PERS \ 124 | 0xBD ///< Number of measurement cycles outside thresholds to trigger an 125 | ///< interupt 126 | #define AS7341_GPIO2 \ 127 | 0xBE ///< GPIO Settings and status: polarity, direction, sets output, reads 128 | ///< input 129 | #define AS7341_ASTEP_L 0xCA ///< Integration step size ow byte 130 | #define AS7341_ASTEP_H 0xCB ///< Integration step size high byte 131 | #define AS7341_AGC_GAIN_MAX 0xCF ///< AS7341_AGC_GAIN_MAX (unused) 132 | #define AS7341_AZ_CONFIG 0xD6 ///< AS7341_AZ_CONFIG (unused) 133 | #define AS7341_FD_TIME1 0xD8 ///< Flicker detection integration time low byte 134 | #define AS7341_FD_TIME2 0xDA ///< Flicker detection gain and high nibble 135 | #define AS7341_FD_CFG0 0xD7 ///< AS7341_FD_CFG0 (unused) 136 | #define AS7341_FD_STATUS \ 137 | 0xDB ///< Flicker detection status; measurement valid, saturation, flicker 138 | ///< type 139 | #define AS7341_INTENAB 0xF9 ///< Enables individual interrupt types 140 | #define AS7341_CONTROL 0xFA ///< Auto-zero, fifo clear, clear SAI active 141 | #define AS7341_FIFO_MAP 0xFC ///< AS7341_FIFO_MAP (unused) 142 | #define AS7341_FIFO_LVL 0xFD ///< AS7341_FIFO_LVL (unused) 143 | #define AS7341_FDATA_L 0xFE ///< AS7341_FDATA_L (unused) 144 | #define AS7341_FDATA_H 0xFF ///< AS7341_FDATA_H (unused) 145 | 146 | #define AS7341_SPECTRAL_INT_HIGH_MSK \ 147 | 0b00100000 ///< bitmask to check for a high threshold interrupt 148 | #define AS7341_SPECTRAL_INT_LOW_MSK \ 149 | 0b00010000 ///< bitmask to check for a low threshold interrupt 150 | 151 | /** 152 | * @brief Allowable gain multipliers for `setGain` 153 | * 154 | */ 155 | typedef enum { 156 | AS7341_GAIN_0_5X, 157 | AS7341_GAIN_1X, 158 | AS7341_GAIN_2X, 159 | AS7341_GAIN_4X, 160 | AS7341_GAIN_8X, 161 | AS7341_GAIN_16X, 162 | AS7341_GAIN_32X, 163 | AS7341_GAIN_64X, 164 | AS7341_GAIN_128X, 165 | AS7341_GAIN_256X, 166 | AS7341_GAIN_512X, 167 | } as7341_gain_t; 168 | 169 | /** 170 | * @brief Available SMUX configuration commands 171 | * 172 | */ 173 | typedef enum { 174 | AS7341_SMUX_CMD_ROM_RESET, ///< ROM code initialization of SMUX 175 | AS7341_SMUX_CMD_READ, ///< Read SMUX configuration to RAM from SMUX chain 176 | AS7341_SMUX_CMD_WRITE, ///< Write SMUX configuration from RAM to SMUX chain 177 | } as7341_smux_cmd_t; 178 | /** 179 | * @brief ADC Channel specifiers for configuration 180 | * 181 | */ 182 | typedef enum { 183 | AS7341_ADC_CHANNEL_0, 184 | AS7341_ADC_CHANNEL_1, 185 | AS7341_ADC_CHANNEL_2, 186 | AS7341_ADC_CHANNEL_3, 187 | AS7341_ADC_CHANNEL_4, 188 | AS7341_ADC_CHANNEL_5, 189 | } as7341_adc_channel_t; 190 | /** 191 | * @brief Spectral Channel specifiers for configuration and reading 192 | * 193 | */ 194 | typedef enum { 195 | AS7341_CHANNEL_415nm_F1, 196 | AS7341_CHANNEL_445nm_F2, 197 | AS7341_CHANNEL_480nm_F3, 198 | AS7341_CHANNEL_515nm_F4, 199 | AS7341_CHANNEL_CLEAR_0, 200 | AS7341_CHANNEL_NIR_0, 201 | AS7341_CHANNEL_555nm_F5, 202 | AS7341_CHANNEL_590nm_F6, 203 | AS7341_CHANNEL_630nm_F7, 204 | AS7341_CHANNEL_680nm_F8, 205 | AS7341_CHANNEL_CLEAR, 206 | AS7341_CHANNEL_NIR, 207 | } as7341_color_channel_t; 208 | 209 | /** 210 | * @brief The number of measurement cycles with spectral data outside of a 211 | * threshold required to trigger an interrupt 212 | * 213 | */ 214 | typedef enum { 215 | AS7341_INT_COUNT_ALL, ///< 0 216 | AS7341_INT_COUNT_1, ///< 1 217 | AS7341_INT_COUNT_2, ///< 2 218 | AS7341_INT_COUNT_3, ///< 3 219 | AS7341_INT_COUNT_5, ///< 4 220 | AS7341_INT_COUNT_10, ///< 5 221 | AS7341_INT_COUNT_15, ///< 6 222 | AS7341_INT_COUNT_20, ///< 7 223 | AS7341_INT_COUNT_25, ///< 8 224 | AS7341_INT_COUNT_30, ///< 9 225 | AS7341_INT_COUNT_35, ///< 10 226 | AS7341_INT_COUNT_40, ///< 11 227 | AS7341_INT_COUNT_45, ///< 12 228 | AS7341_INT_COUNT_50, ///< 13 229 | AS7341_INT_COUNT_55, ///< 14 230 | AS7341_INT_COUNT_60, ///< 15 231 | } as7341_int_cycle_count_t; 232 | 233 | /** 234 | * @brief Pin directions to set how the GPIO pin is to be used 235 | * 236 | */ 237 | typedef enum { 238 | AS7341_GPIO_OUTPUT, ///< THhe GPIO pin is configured as an open drain output 239 | AS7341_GPIO_INPUT, ///< The GPIO Pin is set as a high-impedence input 240 | } as7341_gpio_dir_t; 241 | 242 | /** 243 | * @brief Wait states for async reading 244 | */ 245 | typedef enum { 246 | AS7341_WAITING_START, // 247 | AS7341_WAITING_LOW, // 248 | AS7341_WAITING_HIGH, // 249 | AS7341_WAITING_DONE, // 250 | } as7341_waiting_t; 251 | 252 | class Adafruit_AS7341; 253 | 254 | /*! 255 | * @brief Class that stores state and functions for interacting with 256 | * the AS7341 11-Channel Spectral Sensor 257 | */ 258 | class Adafruit_AS7341 { 259 | public: 260 | Adafruit_AS7341(); 261 | ~Adafruit_AS7341(); 262 | 263 | bool begin(uint8_t i2c_addr = AS7341_I2CADDR_DEFAULT, TwoWire *wire = &Wire, 264 | int32_t sensor_id = 0); 265 | 266 | bool setASTEP(uint16_t astep_value); 267 | bool setATIME(uint8_t atime_value); 268 | bool setGain(as7341_gain_t gain_value); 269 | 270 | uint16_t getASTEP(); 271 | uint8_t getATIME(); 272 | as7341_gain_t getGain(); 273 | 274 | long getTINT(); 275 | float toBasicCounts(uint16_t raw); 276 | 277 | bool readAllChannels(void); 278 | bool readAllChannels(uint16_t *readings_buffer); 279 | void delayForData(int waitTime = 0); 280 | uint16_t readChannel(as7341_adc_channel_t channel); 281 | uint16_t getChannel(as7341_color_channel_t channel); 282 | 283 | bool startReading(void); 284 | bool checkReadingProgress(); 285 | bool getAllChannels(uint16_t *readings_buffer); 286 | 287 | uint16_t detectFlickerHz(void); 288 | 289 | void setup_F1F4_Clear_NIR(void); 290 | void setup_F5F8_Clear_NIR(void); 291 | 292 | void powerEnable(bool enable_power); 293 | bool enableSpectralMeasurement(bool enable_measurement); 294 | 295 | bool setHighThreshold(uint16_t high_threshold); 296 | bool setLowThreshold(uint16_t low_threshold); 297 | 298 | uint16_t getHighThreshold(void); 299 | uint16_t getLowThreshold(void); 300 | 301 | bool enableSpectralInterrupt(bool enable_int); 302 | bool enableSystemInterrupt(bool enable_int); 303 | 304 | bool setAPERS(as7341_int_cycle_count_t cycle_count); 305 | bool setSpectralThresholdChannel(as7341_adc_channel_t channel); 306 | 307 | uint8_t getInterruptStatus(void); 308 | bool clearInterruptStatus(void); 309 | 310 | bool spectralInterruptTriggered(void); 311 | uint8_t spectralInterruptSource(void); 312 | bool spectralLowTriggered(void); 313 | bool spectralHighTriggered(void); 314 | 315 | bool enableLED(bool enable_led); 316 | bool setLEDCurrent(uint16_t led_current_ma); 317 | uint16_t getLEDCurrent(void); 318 | 319 | void disableAll(void); 320 | 321 | bool getIsDataReady(); 322 | bool setBank(bool low); // low true gives access to 0x60 to 0x74 323 | 324 | as7341_gpio_dir_t getGPIODirection(void); 325 | bool setGPIODirection(as7341_gpio_dir_t gpio_direction); 326 | bool getGPIOInverted(void); 327 | bool setGPIOInverted(bool gpio_inverted); 328 | bool getGPIOValue(void); 329 | bool setGPIOValue(bool); 330 | 331 | protected: 332 | virtual bool _init(int32_t sensor_id); 333 | uint8_t last_spectral_int_source = 334 | 0; ///< The value of the last reading of the spectral interrupt source 335 | ///< register 336 | 337 | Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface 338 | 339 | private: 340 | bool enableSMUX(void); 341 | bool enableFlickerDetection(bool enable_fd); 342 | void FDConfig(void); 343 | int8_t getFlickerDetectStatus(void); 344 | bool setSMUXCommand(as7341_smux_cmd_t command); 345 | void writeRegister(byte addr, byte val); 346 | void setSMUXLowChannels(bool f1_f4); 347 | uint16_t _channel_readings[12]; 348 | as7341_waiting_t _readingState; 349 | }; 350 | 351 | #endif 352 | -------------------------------------------------------------------------------- /examples/synd_mode/synd_mode.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | 4 | The AS7341 device features three modes to perform a spectral measurement. The 5 | integration mode (INT_MODE) can be configured in register 0x70 (CONFIG) 6 | 7 | This Script shows the implementation of SYND Mode INT_MODE = 0x03 8 | 9 | Spectral measurement is based on Integration with external start and stop sync 10 | signal Integration is controlled via rising/falling edge on pin GPIO and 11 | register EDGE. If the number of edges on pin GPIO is reached, integration time 12 | is stopped. Actual integration time can be read out in register “ITIME”. 13 | 14 | 15 | Written by Sijo John @ ams AG, Application Support in November, 2018 16 | Development environment specifics: Arduino IDE 1.8.5 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21 | */ 22 | 23 | #include 24 | // I2C device address - 0x39 25 | #define _i2cAddr (0x39) 26 | #define GPIO_OUT_PIN 5 27 | #define SYND_EDGES 10 28 | #define INT_PIN 6 29 | #define LOW_PULSE_DELAY 15 30 | void setup() { 31 | 32 | // Initiate the Wire library and join the I2C bus as a master or slave 33 | Wire.begin(); 34 | 35 | // communication with the host computer serial monitor 36 | Serial.begin(115200); 37 | while (!Serial) { 38 | delay(1); 39 | } 40 | digitalWrite(GPIO_OUT_PIN, HIGH); 41 | pinMode(GPIO_OUT_PIN, OUTPUT); 42 | } 43 | 44 | void loop() { 45 | 46 | // Function defined to read out channels with with SYND MODE and SMUX 47 | // configration 1 for pixels - F1-F4, Clear, NIR 48 | synD_Mode(); 49 | // Sets the Spectral Gain in CFG1 Register (0xAA) in [4:0] bit 50 | setGAIN(byte(0x08)); 51 | delay(100); 52 | } 53 | 54 | // 55 | // Function executes to read out channels with SYND MODE and SMUX configration 1 56 | // for pixels - F1-F4, Clear, NIR the integration time is defined by the number 57 | // of rising/falling edge between start and stop on pin GPIO Signal, which is 58 | // set to register EDGE (0x72) 59 | // 60 | void synD_Mode() { 61 | 62 | bool isEnabled = true; 63 | bool isDataReady = false; 64 | 65 | // Setting the PON bit in Enable register 0x80 66 | PON(); 67 | 68 | // Disable SP_EN bit in Enable register 0x80 69 | 70 | SpEn(false); 71 | 72 | // Write SMUX configuration from RAM to set SMUX chain registers (Write 0x10 73 | // to CFG6) 74 | SmuxConfigRAM(); 75 | 76 | // Write new configuration to all the 20 registers for reading channels from 77 | // F5-F8, Clear and NIR 78 | F1F4_Clear_NIR(); 79 | 80 | // Start SMUX command: Enable the SMUXEN bit (bit 4) in register ENABLE 81 | SMUXEN(); 82 | 83 | // Checking on the enabled SMUXEN bit whether back to zero- Poll the SMUXEN 84 | // bit -> if it is 0 SMUX command is started 85 | while (isEnabled) { 86 | isEnabled = getSmuxEnabled(); 87 | } 88 | 89 | // Enabling the gpio_in_en (Bit 2) and gpio_out(Bit 1) in GPIO register 0xBE 90 | GPIO_MODE(); 91 | 92 | // reg_bank bit(4) is set to '1' for setting the 0x00-0x7f regiater to 93 | // reg_bank register (0xA9) 94 | RegBankConfig(); 95 | 96 | // CONFIG (0x70) is used to set the INT_MODE (Bit 1:0) to SYND Mpde by writing 97 | // 0x03 98 | INT_MODE(0x03); 99 | 100 | // Number of falling SYNC-edges between start and stop integration in SynD 101 | // mode is set to register EDGE (0x72) 102 | 103 | Serial.print("syn SynEdge to "); 104 | Serial.println(SYND_EDGES); 105 | setSynEdge(SYND_EDGES); // 4 edges 106 | 107 | // writing back the Reg_bank priorty to RAM bank select 108 | writeRegister(byte(0xA9), byte(0x00)); 109 | 110 | SpEn(true); 111 | 112 | uint16_t low_pulse_count = 0; 113 | // Reading and Polling the the AVALID bit in Status 2 Register 0xA3 114 | while (!(isDataReady)) { 115 | 116 | isDataReady = getIsDataReady(); 117 | Serial.print("Pulsing low w/ delay "); 118 | Serial.println(LOW_PULSE_DELAY); 119 | digitalWrite(GPIO_OUT_PIN, LOW); 120 | delay(LOW_PULSE_DELAY); 121 | digitalWrite(GPIO_OUT_PIN, HIGH); 122 | low_pulse_count += 1; 123 | } 124 | Serial.println("Low pulses: "); 125 | Serial.println(low_pulse_count); 126 | // analog and digital saturation are read in Status2 127 | // Digital saturation - Indicates that the maximum counter value has been 128 | // reached. Maximum counter value depends on integration time set in the ATIME 129 | // register 130 | // Analog saturation - Indicates that the intensity of ambient light has 131 | // exceeded the maximum integration level for the spectral analog circuit 132 | Serial.print("Status2-"); 133 | readRegisterPrint(0xA3); 134 | 135 | // reg_bank bit(4) is set to '1' for setting the 0x00-0x7f regiater to 136 | // reg_bank register (0xA9) 137 | RegBankConfig(); 138 | 139 | // Read all the registers from 0x60 to 0x6F in SYND MODE 140 | readSynDRegisters(); 141 | } 142 | 143 | /*----- Register configuration -----*/ 144 | 145 | // 146 | // Setting the PON (Power on) bit on the chip (bit0 at register ENABLE 0x80) 147 | // Attention: This function clears only the PON bit in ENABLE register and keeps 148 | // the other bits 149 | void PON() { 150 | 151 | byte regVal = readRegister(byte(0x80)); 152 | //byte temp = regVal; 153 | regVal = regVal & 0xFE; 154 | regVal = regVal | 0x01; 155 | writeRegister(byte(0x80), byte(regVal)); 156 | } 157 | 158 | // 159 | // Setting the SP_EN (spectral measurement enabled) bit on the chip (bit 1 in 160 | // register ENABLE) Enabling (true) or 161 | // disabling (false) the SP_EN bit 162 | void SpEn(bool isEnable) { 163 | 164 | byte regVal = readRegister(byte(0x80)); 165 | byte temp = regVal; 166 | regVal = regVal & 0xFD; 167 | 168 | if (isEnable == true) { 169 | regVal = regVal | 0x02; 170 | } else { 171 | regVal = temp & 0xFD; 172 | } 173 | 174 | writeRegister(byte(0x80), byte(regVal)); 175 | } 176 | 177 | // 178 | // Write SMUX configration from RAM to set SMUX chain in CFG6 register 0xAF 179 | // 180 | void SmuxConfigRAM() { writeRegister(byte(0xAF), byte(0x10)); } 181 | 182 | // 183 | // Starting the SMUX command via enabling the SMUXEN bit (bit 4) in register 184 | // ENABLE 0x80 The SMUXEN bit gets cleared automatically as soon as SMUX 185 | // operation is finished 186 | void SMUXEN() { 187 | 188 | byte regVal = readRegister(byte(0x80)); 189 | //byte temp = regVal; 190 | regVal = regVal & 0xEF; 191 | regVal = regVal | 0x10; 192 | writeRegister(byte(0x80), byte(regVal)); 193 | } 194 | 195 | // 196 | // Reading and Polling the the SMUX Enable bit in Enable Register 0x80 197 | // The SMUXEN bit gets cleared automatically as soon as SMUX operation is 198 | // finished 199 | bool getSmuxEnabled() { 200 | 201 | bool isEnabled = false; 202 | byte regVal = readRegister(byte(0x80)); 203 | 204 | if ((regVal & 0x10) == 0x10) { 205 | return isEnabled = true; 206 | } 207 | 208 | else { 209 | return isEnabled = false; 210 | } 211 | } 212 | 213 | // 214 | // Reading and Polling the the AVALID bit in Status 2 Register 0xA3,if the 215 | // spectral measurement is ready or busy. True indicates that a cycle is 216 | // completed since the last readout of the Raw Data register 217 | bool getIsDataReady() { 218 | bool isDataReady = false; 219 | byte regVal = readRegister(byte(0xA3)); 220 | 221 | if ((regVal & 0x40) == 0x40) { 222 | 223 | return isDataReady = true; 224 | } 225 | 226 | else { 227 | return isDataReady = false; 228 | } 229 | } 230 | 231 | // 232 | // Enabling the gpio_in_en (Bit 2) and gpio_out(Bit 1) in GPIO register 0xBE 233 | // 234 | void GPIO_MODE() { 235 | 236 | byte regVal = readRegister(byte(0xBE)); 237 | //byte temp = regVal; 238 | regVal = regVal & 0x0B; 239 | regVal = regVal | 0x06; 240 | writeRegister(byte(0xBE), byte(regVal)); 241 | } 242 | 243 | // 244 | // CONFIG (0x70) is used to set the INT_MODE (Bit 1:0) SYNSis set by writing 245 | // 0x01 and SYND by writing 0x03 246 | // 247 | void INT_MODE(byte mode) { 248 | 249 | byte regVal = readRegister(byte(0x70)); 250 | // byte temp = regVal; 251 | regVal = regVal & 0xFC; 252 | regVal = regVal | mode; 253 | writeRegister(byte(0x70), byte(regVal)); 254 | } 255 | 256 | // 257 | // select which Register bank to address in registers 0x00-0x7f has priority 258 | // over ram_bank 259 | // reg_bank bit(4) is set to '1' for setting the 0x00-0x7f regiater to reg_bank 260 | // register. by default it is RAM register 261 | // 262 | void RegBankConfig() { 263 | 264 | byte regVal = readRegister(byte(0xA9)); 265 | // byte temp = regVal; 266 | regVal = regVal & 0xEF; 267 | regVal = regVal | 0x10; 268 | writeRegister(byte(0xA9), byte(regVal)); 269 | } 270 | 271 | /*----- Set Gain and integration time = iTime * 2.78µS -----*/ 272 | 273 | // 274 | // Sets the Spectral Gain in CFG1 Register (0xAA) in [4:0] bit 275 | // 276 | // param name = "value"> integer value from 0 to 10 written to AGAIN register 277 | // 0xAA 278 | void setGAIN(byte value) { writeRegister(byte(0xAA), value); } 279 | 280 | // 281 | // Number of falling SYNC-edges between start and stop integration in SynD mode 282 | // is set to register EDGE (0x72) integration time is determined by the 283 | // integration_time = (syn_edge+1) * sync period 284 | // 285 | void setSynEdge(byte value) { writeRegister(byte(0x72), value); } 286 | 287 | /*----- SMUX Configuration for F1,F2,F3,F4,CLEAR,NIR -----*/ 288 | 289 | // 290 | // Mapping the individual Photo diodes to dedicated ADCs using SMUX 291 | // Configuration for F1-F4,Clear,NIR 292 | // 293 | void F1F4_Clear_NIR() { 294 | // SMUX Config for F1,F2,F3,F4,NIR,Clear 295 | writeRegister(byte(0x00), byte(0x30)); // F3 left set to ADC2 296 | writeRegister(byte(0x01), byte(0x01)); // F1 left set to ADC0 297 | writeRegister(byte(0x02), byte(0x00)); // Reserved or disabled 298 | writeRegister(byte(0x03), byte(0x00)); // F8 left disabled 299 | writeRegister(byte(0x04), byte(0x00)); // F6 left disabled 300 | writeRegister( 301 | byte(0x05), 302 | byte(0x42)); // F4 left connected to ADC3/f2 left connected to ADC1 303 | writeRegister(byte(0x06), byte(0x00)); // F5 left disbled 304 | writeRegister(byte(0x07), byte(0x00)); // F7 left disbled 305 | writeRegister(byte(0x08), byte(0x50)); // CLEAR connected to ADC4 306 | writeRegister(byte(0x09), byte(0x00)); // F5 right disabled 307 | writeRegister(byte(0x0A), byte(0x00)); // F7 right disabled 308 | writeRegister(byte(0x0B), byte(0x00)); // Reserved or disabled 309 | writeRegister(byte(0x0C), byte(0x20)); // F2 right connected to ADC1 310 | writeRegister(byte(0x0D), byte(0x04)); // F4 right connected to ADC3 311 | writeRegister(byte(0x0E), byte(0x00)); // F6/F7 right disabled 312 | writeRegister(byte(0x0F), byte(0x30)); // F3 right connected to AD2 313 | writeRegister(byte(0x10), byte(0x01)); // F1 right connected to AD0 314 | writeRegister(byte(0x11), byte(0x50)); // CLEAR right connected to AD4 315 | writeRegister(byte(0x12), byte(0x00)); // Reserved or disabled 316 | writeRegister(byte(0x13), byte(0x06)); // NIR connected to ADC5 317 | } 318 | 319 | /*----- SMUX Configuration for F5,F6,F7,F8,CLEAR,NIR -----*/ 320 | 321 | // 322 | // Mapping the individual Photo diodes to dedicated ADCs using SMUX 323 | // Configuration for F5-F8,Clear,NIR 324 | // 325 | void F5F8_Clear_NIR() { 326 | // SMUX Config for F5,F6,F7,F8,NIR,Clear 327 | writeRegister(byte(0x00), byte(0x00)); // F3 left disable 328 | writeRegister(byte(0x01), byte(0x00)); // F1 left disable 329 | writeRegister(byte(0x02), byte(0x00)); // reserved/disable 330 | writeRegister(byte(0x03), byte(0x40)); // F8 left connected to ADC3 331 | writeRegister(byte(0x04), byte(0x02)); // F6 left connected to ADC1 332 | writeRegister(byte(0x05), byte(0x00)); // F4/ F2 disabled 333 | writeRegister(byte(0x06), byte(0x10)); // F5 left connected to ADC0 334 | writeRegister(byte(0x07), byte(0x03)); // F7 left connected to ADC2 335 | writeRegister(byte(0x08), byte(0x50)); // CLEAR Connected to ADC4 336 | writeRegister(byte(0x09), byte(0x10)); // F5 right connected to ADC0 337 | writeRegister(byte(0x0A), byte(0x03)); // F7 right connected to ADC2 338 | writeRegister(byte(0x0B), byte(0x00)); // Reserved or disabled 339 | writeRegister(byte(0x0C), byte(0x00)); // F2 right disabled 340 | writeRegister(byte(0x0D), byte(0x00)); // F4 right disabled 341 | writeRegister(byte(0x0E), 342 | byte(0x24)); // F7 connected to ADC2/ F6 connected to ADC1 343 | writeRegister(byte(0x0F), byte(0x00)); // F3 right disabled 344 | writeRegister(byte(0x10), byte(0x00)); // F1 right disabled 345 | writeRegister(byte(0x11), byte(0x50)); // CLEAR right connected to AD4 346 | writeRegister(byte(0x12), byte(0x00)); // Reserved or disabled 347 | writeRegister(byte(0x13), byte(0x06)); // NIR connected to ADC5 348 | } 349 | 350 | // 351 | // Read all the registers from 0x60 to 0x6F in SYND MODE 352 | // 353 | void readSynDRegisters() { 354 | 355 | uint8_t Astatus; 356 | uint16_t Channel0; 357 | uint32_t iTime; 358 | uint16_t Channel1; 359 | uint16_t Channel2; 360 | uint16_t Channel3; 361 | uint16_t Channel4; 362 | uint16_t Channel5; 363 | 364 | Wire.beginTransmission(_i2cAddr); 365 | Wire.write(0x60); 366 | Wire.endTransmission(false); 367 | 368 | Wire.requestFrom(_i2cAddr, 16, true); 369 | 370 | Astatus = Wire.read(); // Reading register 0x60 for Astatus 371 | Serial.print("Astatus-"); 372 | Serial.println(Astatus); 373 | 374 | Channel0 = Wire.read() | Wire.read() 375 | << 8; // reading register 0x61 XWING_ADATA0L & 376 | // 0x62 XWING_ADATA0H channel 0 data 377 | Serial.print("Channel0-"); 378 | Serial.println(Channel0); 379 | 380 | uint8_t iTimeL = Wire.read(); // register 0x63 XWING_ITIMEL 381 | uint16_t iTimeM = Wire.read(); // register 0x64 XWING_ITIMEM 382 | uint32_t iTimeH = Wire.read(); // register 0x65 XWING_ITIMEH 383 | iTime = (iTimeH << 16 | iTimeM << 8 | 384 | iTimeL); // iTime = ITIME_H(bit 23:16) ITIME_M(15:8) ITIME_L(7:0) 385 | Serial.print("\tiTime-"); 386 | Serial.println(iTime); 387 | 388 | float Tint = iTime * 2.78 * pow(10, -6); 389 | Serial.print("\tTint-"); 390 | Serial.println(Tint); 391 | 392 | Channel1 = Wire.read() | Wire.read() 393 | << 8; // reading register 0x66 XWING_ADATA1L & 394 | // 0x67 XWING_ADATA1H channel 1 data 395 | Serial.print("\tChannel1-"); 396 | Serial.println(Channel1); 397 | 398 | Channel2 = Wire.read() | Wire.read() 399 | << 8; // reading register 0x68 XWING_ADATA2L & 400 | // 0x69 XWING_ADATA2H channel 2 data 401 | Serial.print("\tChannel2-"); 402 | Serial.println(Channel2); 403 | 404 | Channel3 = Wire.read() | Wire.read() 405 | << 8; // reading register 0x6A XWING_ADATA3L & 406 | // 0x6B XWING_ADATA3H channel 3 data 407 | Serial.print("\tChannel3-"); 408 | Serial.println(Channel3); 409 | 410 | Channel4 = Wire.read() | Wire.read() 411 | << 8; // reading register 0x6C XWING_ADATA4L & 412 | // 0x6D XWING_ADATA4H channel 4 data 413 | Serial.print("\tChannel4-"); 414 | Serial.println(Channel4); 415 | 416 | Channel5 = Wire.read() | Wire.read() 417 | << 8; // reading register 0x6E XWING_ADATA5L & 418 | // 0x6F XWING_ADATA5H channel 5 data 419 | Serial.print("\tChannel5-"); 420 | Serial.println(Channel5); 421 | Serial.println(""); 422 | delay(500); 423 | } 424 | 425 | /* ----- Read/Write to i2c register ----- */ 426 | 427 | // 428 | // Read a single i2c register 429 | // 430 | // param name = "addr">Register address of the the register to be read 431 | // param name = "_i2cAddr">Device address 0x39 432 | 433 | byte readRegister(byte addr) { 434 | Wire.beginTransmission(_i2cAddr); 435 | Wire.write(addr); 436 | Wire.endTransmission(); 437 | 438 | Wire.requestFrom(_i2cAddr, 1); 439 | 440 | if (Wire.available()) { 441 | // Serial.println(Wire.read()); 442 | return (Wire.read()); 443 | } 444 | 445 | else { 446 | Serial.println("I2C Error"); 447 | return (0xFF); // Error 448 | } 449 | } 450 | 451 | // 452 | // Print out a single i2c register 453 | // 454 | // param name = "addr">Register address of the the register to be read 455 | // param name = "_i2cAddr">Device address 0x39 456 | 457 | void readRegisterPrint(byte addr) { 458 | Wire.beginTransmission(_i2cAddr); 459 | Wire.write(addr); 460 | Wire.endTransmission(); 461 | 462 | Wire.requestFrom(_i2cAddr, 1); 463 | 464 | if (Wire.available()) { 465 | Serial.println(Wire.read()); 466 | 467 | } 468 | 469 | else { 470 | Serial.println("I2C Error"); 471 | } 472 | } 473 | 474 | // 475 | // Read two consecutive i2c registers 476 | // 477 | // param name = "addr">First register address of two consecutive registers to be 478 | // read param name = "_i2cAddr">Device address 0x39 479 | 480 | uint16_t readTwoRegister1(byte addr) { 481 | uint8_t readingL; 482 | uint16_t readingH; 483 | uint16_t reading = 0; 484 | Wire.beginTransmission(_i2cAddr); 485 | Wire.write(addr); 486 | Wire.endTransmission(); 487 | 488 | Wire.requestFrom(_i2cAddr, 2); 489 | 490 | if (2 <= Wire.available()) { 491 | readingL = Wire.read(); 492 | readingH = Wire.read(); 493 | readingH = readingH << 8; 494 | reading = (readingH | readingL); 495 | return (reading); 496 | } else { 497 | Serial.println("I2C Error"); 498 | return (0xFFFF); // Error 499 | } 500 | } 501 | 502 | // 503 | // Write a value to a single i2c register 504 | // 505 | // param name = "addr">Register address of the the register to the value to be 506 | // written param name = "val">The value written to the Register param name = 507 | // "_i2cAddr">Device address 0x39 508 | 509 | void writeRegister(byte addr, byte val) { 510 | Wire.beginTransmission(_i2cAddr); 511 | Wire.write(addr); 512 | Wire.write(val); 513 | Wire.endTransmission(); 514 | } 515 | -------------------------------------------------------------------------------- /Adafruit_AS7341.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_AS7341.cpp 3 | * 4 | * I2C Driver for the Library for the AS7341 11-Channel Spectral Sensor 5 | * 6 | * This is a library for the Adafruit AS7341 breakout: 7 | * https://www.adafruit.com/product/4698 8 | * 9 | * Adafruit invests time and resources providing this open source code, 10 | * please support Adafruit and open-source hardware by purchasing products from 11 | * Adafruit! 12 | * 13 | * Copyright 2020 Bryan Siepert for Adafruit Industries 14 | * 15 | * BSD (see license.txt) 16 | */ 17 | 18 | #include "Arduino.h" 19 | #include 20 | 21 | #include "Adafruit_AS7341.h" 22 | 23 | /** 24 | * @brief Construct a new Adafruit_AS7341::Adafruit_AS7341 object 25 | * 26 | */ 27 | Adafruit_AS7341::Adafruit_AS7341(void) {} 28 | 29 | /** 30 | * @brief Destroy the Adafruit_AS7341::Adafruit_AS7341 object 31 | * 32 | */ 33 | Adafruit_AS7341::~Adafruit_AS7341(void) { 34 | // if (temp_sensor) 35 | // delete temp_sensor; 36 | // if (pressure_sensor) 37 | // delete pressure_sensor; 38 | } 39 | 40 | /*! 41 | * @brief Sets up the hardware and initializes I2C 42 | * @param i2c_address 43 | * The I2C address to be used. 44 | * @param wire 45 | * The Wire object to be used for I2C connections. 46 | * @param sensor_id 47 | * The unique ID to differentiate the sensors from others 48 | * @return True if initialization was successful, otherwise false. 49 | */ 50 | bool Adafruit_AS7341::begin(uint8_t i2c_address, TwoWire *wire, 51 | int32_t sensor_id) { 52 | if (i2c_dev) { 53 | delete i2c_dev; // remove old interface 54 | } 55 | 56 | i2c_dev = new Adafruit_I2CDevice(i2c_address, wire); 57 | 58 | if (!i2c_dev->begin()) { 59 | return false; 60 | } 61 | 62 | return _init(sensor_id); 63 | } 64 | 65 | /*! @brief Initializer for post i2c/spi init 66 | * @param sensor_id Optional unique ID for the sensor set 67 | * @returns True if chip identified and initialized 68 | */ 69 | bool Adafruit_AS7341::_init(int32_t sensor_id) { 70 | 71 | // silence compiler warning - variable may be used in the future 72 | (void)sensor_id; 73 | 74 | Adafruit_BusIO_Register chip_id = 75 | Adafruit_BusIO_Register(i2c_dev, AS7341_WHOAMI); 76 | 77 | // make sure we're talking to the right chip 78 | if ((chip_id.read() & 0xFC) != (AS7341_CHIP_ID << 2)) { 79 | return false; 80 | } 81 | 82 | powerEnable(true); 83 | return true; 84 | } 85 | 86 | /********************* EXAMPLE EXTRACTS **************/ 87 | // maybe return a typedef enum 88 | /** 89 | * @brief Returns the flicker detection status 90 | * 91 | * @return int8_t 92 | */ 93 | int8_t Adafruit_AS7341::getFlickerDetectStatus(void) { 94 | Adafruit_BusIO_Register flicker_val = 95 | Adafruit_BusIO_Register(i2c_dev, AS7341_FD_STATUS); 96 | return (int8_t)flicker_val.read(); 97 | } 98 | 99 | /** 100 | * @brief Returns the ADC data for a given channel 101 | * 102 | * @param channel The ADC channel to read 103 | * @return uint16_t The measured data for the currently configured sensor 104 | */ 105 | uint16_t Adafruit_AS7341::readChannel(as7341_adc_channel_t channel) { 106 | // each channel has two bytes, so offset by two for each next channel 107 | Adafruit_BusIO_Register channel_data_reg = Adafruit_BusIO_Register( 108 | i2c_dev, (AS7341_CH0_DATA_L + 2 * channel), 2, LSBFIRST); 109 | 110 | return channel_data_reg.read(); 111 | } 112 | 113 | /** 114 | * @brief Returns the reading data for the specified color channel 115 | * 116 | * call `readAllChannels` before reading to update the stored readings 117 | * 118 | * @param channel The color sensor channel to read 119 | * @return uint16_t The measured data for the selected sensor channel 120 | */ 121 | uint16_t Adafruit_AS7341::getChannel(as7341_color_channel_t channel) { 122 | return _channel_readings[channel]; 123 | } 124 | 125 | /** 126 | * @brief fills the provided buffer with the current measurements for Spectral 127 | * channels F1-8, Clear and NIR 128 | * 129 | * @param readings_buffer Pointer to a buffer of length 10 or more to fill with 130 | * sensor data 131 | * @return true: success false: failure 132 | */ 133 | bool Adafruit_AS7341::readAllChannels(uint16_t *readings_buffer) { 134 | 135 | setSMUXLowChannels(true); // Configure SMUX to read low channels 136 | enableSpectralMeasurement(true); // Start integration 137 | delayForData(0); // I'll wait for you for all time 138 | 139 | Adafruit_BusIO_Register channel_data_reg = 140 | Adafruit_BusIO_Register(i2c_dev, AS7341_CH0_DATA_L, 2); 141 | 142 | bool low_success = channel_data_reg.read((uint8_t *)readings_buffer, 12); 143 | 144 | setSMUXLowChannels(false); // Configure SMUX to read high channels 145 | enableSpectralMeasurement(true); // Start integration 146 | delayForData(0); // I'll wait for you for all time 147 | 148 | return low_success && 149 | channel_data_reg.read((uint8_t *)&readings_buffer[6], 12); 150 | } 151 | 152 | /** 153 | * @brief starts the process of getting readings from all channels without using 154 | * delays 155 | * 156 | * @return true: success false: failure (a bit arbitrary) 157 | */ 158 | bool Adafruit_AS7341::startReading(void) { 159 | _readingState = AS7341_WAITING_START; // Start the measurement please 160 | checkReadingProgress(); // Call the check function to start it 161 | return true; 162 | } 163 | 164 | /** 165 | * @brief runs the process of getting readings from all channels without using 166 | * delays. Should be called regularly (ie. in loop()) Need to call 167 | * startReading() to initialise the process Need to call getAllChannels() to 168 | * transfer the data into an external buffer 169 | * 170 | * @return true: reading is complete false: reading is incomplete (or failed) 171 | */ 172 | bool Adafruit_AS7341::checkReadingProgress() { 173 | if (_readingState == AS7341_WAITING_START) { 174 | setSMUXLowChannels(true); // Configure SMUX to read low channels 175 | enableSpectralMeasurement(true); // Start integration 176 | _readingState = AS7341_WAITING_LOW; 177 | return false; 178 | } 179 | 180 | if (!getIsDataReady() || _readingState == AS7341_WAITING_DONE) 181 | return false; 182 | 183 | if (_readingState == 184 | AS7341_WAITING_LOW) // Check of getIsDataRead() is already done 185 | { 186 | Adafruit_BusIO_Register channel_data_reg = 187 | Adafruit_BusIO_Register(i2c_dev, AS7341_CH0_DATA_L, 2); 188 | 189 | // bool low_success = channel_data_reg.read((uint8_t *)_channel_readings, 190 | // 12); 191 | channel_data_reg.read((uint8_t *)_channel_readings, 12); 192 | 193 | setSMUXLowChannels(false); // Configure SMUX to read high channels 194 | enableSpectralMeasurement(true); // Start integration 195 | _readingState = AS7341_WAITING_HIGH; 196 | return false; 197 | } 198 | 199 | if (_readingState == 200 | AS7341_WAITING_HIGH) // Check of getIsDataRead() is already done 201 | { 202 | _readingState = AS7341_WAITING_DONE; 203 | Adafruit_BusIO_Register channel_data_reg = 204 | Adafruit_BusIO_Register(i2c_dev, AS7341_CH0_DATA_L, 2); 205 | // return low_success && //low_success is lost since it 206 | // was last call 207 | channel_data_reg.read((uint8_t *)&_channel_readings[6], 12); 208 | return true; 209 | } 210 | 211 | return false; 212 | } 213 | 214 | /** 215 | * @brief transfer all the values from the private result buffer into one 216 | * nominated 217 | * 218 | * @param readings_buffer Pointer to a buffer of length 12 (THERE IS NO ERROR 219 | * CHECKING, YE BE WARNED!) 220 | * 221 | * @return true: success false: failure 222 | */ 223 | bool Adafruit_AS7341::getAllChannels(uint16_t *readings_buffer) { 224 | for (int i = 0; i < 12; i++) 225 | readings_buffer[i] = _channel_readings[i]; 226 | return true; 227 | } 228 | 229 | /** 230 | * @brief Delay while waiting for data, with option to time out and recover 231 | * 232 | * @param waitTime the maximum amount of time to wait 233 | * @return none 234 | */ 235 | void Adafruit_AS7341::delayForData(int waitTime) { 236 | if (waitTime == 0) // Wait forever 237 | { 238 | while (!getIsDataReady()) { 239 | delay(1); 240 | } 241 | return; 242 | } 243 | if (waitTime > 0) // Wait for that many milliseconds 244 | { 245 | uint32_t elapsedMillis = 0; 246 | while (!getIsDataReady() && elapsedMillis < (uint32_t)waitTime) { 247 | delay(1); 248 | elapsedMillis++; 249 | } 250 | return; 251 | } 252 | if (waitTime < 0) { 253 | // For future use? 254 | return; 255 | } 256 | } 257 | 258 | /** 259 | * @brief Take readings for F1-8, Clear and NIR and store them in a buffer 260 | * 261 | * @return true: success false: failure 262 | */ 263 | bool Adafruit_AS7341::readAllChannels(void) { 264 | return readAllChannels(_channel_readings); 265 | } 266 | 267 | void Adafruit_AS7341::setSMUXLowChannels(bool f1_f4) { 268 | enableSpectralMeasurement(false); 269 | setSMUXCommand(AS7341_SMUX_CMD_WRITE); 270 | if (f1_f4) { 271 | setup_F1F4_Clear_NIR(); 272 | } else { 273 | setup_F5F8_Clear_NIR(); 274 | } 275 | enableSMUX(); 276 | } 277 | 278 | /** 279 | * @brief Sets the power state of the sensor 280 | * 281 | * @param enable_power true: on false: off 282 | */ 283 | void Adafruit_AS7341::powerEnable(bool enable_power) { 284 | Adafruit_BusIO_Register enable_reg = 285 | Adafruit_BusIO_Register(i2c_dev, AS7341_ENABLE); 286 | Adafruit_BusIO_RegisterBits pon_en = 287 | Adafruit_BusIO_RegisterBits(&enable_reg, 1, 0); 288 | pon_en.write(enable_power); 289 | } 290 | 291 | /** 292 | * @brief Disable Spectral reading, flicker detection, and power 293 | * 294 | * */ 295 | void Adafruit_AS7341::disableAll(void) { 296 | Adafruit_BusIO_Register enable_reg = 297 | Adafruit_BusIO_Register(i2c_dev, AS7341_ENABLE); 298 | 299 | enable_reg.write(0); 300 | } 301 | 302 | /** 303 | * @brief Enables measurement of spectral data 304 | * 305 | * @param enable_measurement true: enabled false: disabled 306 | * @return true: success false: failure 307 | */ 308 | bool Adafruit_AS7341::enableSpectralMeasurement(bool enable_measurement) { 309 | 310 | Adafruit_BusIO_Register enable_reg = 311 | Adafruit_BusIO_Register(i2c_dev, AS7341_ENABLE); 312 | 313 | Adafruit_BusIO_RegisterBits spec_enable_bit = 314 | Adafruit_BusIO_RegisterBits(&enable_reg, 1, 1); 315 | return spec_enable_bit.write(enable_measurement); 316 | } 317 | 318 | bool Adafruit_AS7341::enableSMUX(void) { 319 | 320 | Adafruit_BusIO_Register enable_reg = 321 | Adafruit_BusIO_Register(i2c_dev, AS7341_ENABLE); 322 | Adafruit_BusIO_RegisterBits smux_enable_bit = 323 | Adafruit_BusIO_RegisterBits(&enable_reg, 1, 4); 324 | bool success = smux_enable_bit.write(true); 325 | 326 | int timeOut = 1000; // Arbitrary value, but if it takes 1000 milliseconds then 327 | // something is wrong 328 | int count = 0; 329 | while (smux_enable_bit.read() && count < timeOut) { 330 | delay(1); 331 | count++; 332 | } 333 | if (count >= timeOut) 334 | return false; 335 | else 336 | return success; 337 | } 338 | 339 | bool Adafruit_AS7341::enableFlickerDetection(bool enable_fd) { 340 | 341 | Adafruit_BusIO_Register enable_reg = 342 | Adafruit_BusIO_Register(i2c_dev, AS7341_ENABLE); 343 | Adafruit_BusIO_RegisterBits fd_enable_bit = 344 | Adafruit_BusIO_RegisterBits(&enable_reg, 1, 6); 345 | return fd_enable_bit.write(enable_fd); 346 | } 347 | 348 | /** 349 | * @brief Get the GPIO pin direction setting 350 | * 351 | * @return `AS7341_OUTPUT` or `AS7341_INPUT` 352 | */ 353 | as7341_gpio_dir_t Adafruit_AS7341::getGPIODirection(void) { 354 | Adafruit_BusIO_Register gpio2_reg = 355 | Adafruit_BusIO_Register(i2c_dev, AS7341_GPIO2); 356 | Adafruit_BusIO_RegisterBits gpio_input_enable = 357 | Adafruit_BusIO_RegisterBits(&gpio2_reg, 1, 2); 358 | 359 | return (as7341_gpio_dir_t)gpio_input_enable.read(); 360 | } 361 | 362 | /** 363 | * @brief Set the GPIO pin to be used as an input or output 364 | * 365 | * @param gpio_direction The IO direction to set 366 | * @return true: success false: failure 367 | */ 368 | bool Adafruit_AS7341::setGPIODirection(as7341_gpio_dir_t gpio_direction) { 369 | Adafruit_BusIO_Register gpio2_reg = 370 | Adafruit_BusIO_Register(i2c_dev, AS7341_GPIO2); 371 | Adafruit_BusIO_RegisterBits gpio_input_enable = 372 | Adafruit_BusIO_RegisterBits(&gpio2_reg, 1, 2); 373 | 374 | return gpio_input_enable.write(gpio_direction); 375 | } 376 | 377 | /** 378 | * @brief Get the output inversion setting for the GPIO pin 379 | * 380 | * @return true: GPIO output inverted false: GPIO output normal 381 | */ 382 | bool Adafruit_AS7341::getGPIOInverted(void) { 383 | Adafruit_BusIO_Register gpio2_reg = 384 | Adafruit_BusIO_Register(i2c_dev, AS7341_GPIO2); 385 | Adafruit_BusIO_RegisterBits gpio_output_inverted_bit = 386 | Adafruit_BusIO_RegisterBits(&gpio2_reg, 1, 3); 387 | 388 | return gpio_output_inverted_bit.read(); 389 | } 390 | 391 | /** 392 | * @brief Invert the logic of then GPIO pin when used as an output 393 | * 394 | * @param gpio_inverted **When true** setting the gpio value to **true will 395 | * connect** the GPIO pin to ground. When set to **false**, setting the GPIO pin 396 | * value to **true will disconnect** the GPIO pin from ground 397 | * @return true: success false: failure 398 | */ 399 | bool Adafruit_AS7341::setGPIOInverted(bool gpio_inverted) { 400 | Adafruit_BusIO_Register gpio2_reg = 401 | Adafruit_BusIO_Register(i2c_dev, AS7341_GPIO2); 402 | Adafruit_BusIO_RegisterBits gpio_output_inverted_bit = 403 | Adafruit_BusIO_RegisterBits(&gpio2_reg, 1, 3); 404 | 405 | return gpio_output_inverted_bit.write(gpio_inverted); 406 | } 407 | 408 | /** 409 | * @brief Read the digital level of the GPIO pin, high or low 410 | * 411 | * @return true: GPIO pin level is high false: GPIO pin level is low 412 | */ 413 | bool Adafruit_AS7341::getGPIOValue(void) { 414 | Adafruit_BusIO_Register gpio2_reg = 415 | Adafruit_BusIO_Register(i2c_dev, AS7341_GPIO2); 416 | Adafruit_BusIO_RegisterBits gpio_input_value_bit = 417 | Adafruit_BusIO_RegisterBits(&gpio2_reg, 1, 0); 418 | 419 | return gpio_input_value_bit.read(); 420 | } 421 | 422 | /** 423 | * @brief Set the digital level of the GPIO pin, high or low 424 | * 425 | * @param gpio_high The GPIO level to set. Set to true to disconnect the pin 426 | * from ground. Set to false to connect the gpio pin to ground. This can be used 427 | * to connect the cathode of an LED to ground to turn it on. 428 | * @return true: success false: failure 429 | */ 430 | bool Adafruit_AS7341::setGPIOValue(bool gpio_high) { 431 | Adafruit_BusIO_Register gpio2_reg = 432 | Adafruit_BusIO_Register(i2c_dev, AS7341_GPIO2); 433 | Adafruit_BusIO_RegisterBits gpio_output_value_bit = 434 | Adafruit_BusIO_RegisterBits(&gpio2_reg, 1, 1); 435 | 436 | return gpio_output_value_bit.write(gpio_high); 437 | } 438 | 439 | bool Adafruit_AS7341::setSMUXCommand(as7341_smux_cmd_t command) { 440 | Adafruit_BusIO_Register cfg6_reg = 441 | Adafruit_BusIO_Register(i2c_dev, AS7341_CFG6); 442 | Adafruit_BusIO_RegisterBits smux_command_bits = 443 | Adafruit_BusIO_RegisterBits(&cfg6_reg, 2, 3); 444 | 445 | return smux_command_bits.write(command); 446 | } 447 | 448 | /** 449 | * @brief Enable control of an attached LED on the LDR pin 450 | * 451 | * @param enable_led true: LED enabled false: LED disabled 452 | * @return true: success false: failure 453 | */ 454 | bool Adafruit_AS7341::enableLED(bool enable_led) { 455 | Adafruit_BusIO_Register config_reg = 456 | Adafruit_BusIO_Register(i2c_dev, AS7341_CONFIG); 457 | // Enables control of the LED via the LDR pin 458 | // 1=control enabled 0 = control disabled 459 | Adafruit_BusIO_RegisterBits led_sel_bit = 460 | Adafruit_BusIO_RegisterBits(&config_reg, 1, 3); 461 | 462 | Adafruit_BusIO_Register led_reg = 463 | Adafruit_BusIO_Register(i2c_dev, AS7341_LED); 464 | // turns the LED on or off 465 | Adafruit_BusIO_RegisterBits led_act_bit = 466 | Adafruit_BusIO_RegisterBits(&led_reg, 1, 7); 467 | 468 | setBank(true); // Access 0x60-0x74 469 | bool result = led_sel_bit.write(enable_led) && led_act_bit.write(enable_led); 470 | setBank(false); // Access registers 0x80 and above (default) 471 | return result; 472 | } 473 | 474 | /** 475 | * @brief Set the current limit for the LED 476 | * 477 | * @param led_current_ma the value to set in milliamps. With a minimum of 4. Any 478 | * amount under 4 will be rounded up to 4 479 | * 480 | * Range is 4mA to 258mA 481 | * @return true: success false: failure 482 | */ 483 | bool Adafruit_AS7341::setLEDCurrent(uint16_t led_current_ma) { 484 | // check within permissible range 485 | if (led_current_ma > 258) { 486 | return false; 487 | } 488 | if (led_current_ma < 4) { 489 | led_current_ma = 4; 490 | } 491 | setBank(true); // Access 0x60 0x74 492 | 493 | Adafruit_BusIO_Register led_reg = 494 | Adafruit_BusIO_Register(i2c_dev, AS7341_LED); 495 | 496 | // true = led on , false = off 497 | Adafruit_BusIO_RegisterBits led_current_bits = 498 | Adafruit_BusIO_RegisterBits(&led_reg, 7, 0); 499 | 500 | bool result = led_current_bits.write((uint8_t)((led_current_ma - 4) / 2)); 501 | setBank(false); // Access registers 0x80 and above (default) 502 | return result; 503 | } 504 | 505 | /** 506 | * @brief Get the current limit for the LED 507 | * 508 | * Range is 4mA to 258mA 509 | * @return current limit in mA 510 | */ 511 | uint16_t Adafruit_AS7341::getLEDCurrent(void) { 512 | uint16_t led_current_ma; 513 | uint32_t led_raw; 514 | 515 | setBank(true); // Access 0x60 0x74 516 | 517 | Adafruit_BusIO_Register led_reg = 518 | Adafruit_BusIO_Register(i2c_dev, AS7341_LED); 519 | 520 | Adafruit_BusIO_RegisterBits led_current_bits = 521 | Adafruit_BusIO_RegisterBits(&led_reg, 7, 0); 522 | 523 | led_raw = led_current_bits.read(); 524 | 525 | led_current_ma = (uint16_t)(led_raw * 2) + 4; 526 | setBank(false); // Access registers 0x80 and above (default) 527 | return led_current_ma; 528 | } 529 | 530 | /** 531 | * @brief Sets the active register bank 532 | * 533 | * The AS7341 uses banks to organize the register making it nescessary to set 534 | * the correct bank to access a register. 535 | * 536 | 537 | * @param low **true**: 538 | * **false**: Set the current bank to allow access to registers with addresses 539 | of `0x80` and above 540 | * @return true: success false: failure 541 | */ 542 | bool Adafruit_AS7341::setBank(bool low) { 543 | Adafruit_BusIO_Register cfg0_reg = 544 | Adafruit_BusIO_Register(i2c_dev, AS7341_CFG0); 545 | // register map says shift 3, 0xA9 description says shift 4 with 3 being 546 | // reserved 547 | Adafruit_BusIO_RegisterBits bank_bit = 548 | Adafruit_BusIO_RegisterBits(&cfg0_reg, 1, 4); 549 | 550 | return bank_bit.write(low); 551 | } 552 | 553 | /** 554 | * @brief Sets the threshold below which spectral measurements will trigger 555 | * interrupts when the APERS count is reached 556 | * 557 | * @param low_threshold the new threshold 558 | * @return true: success false: failure 559 | */ 560 | bool Adafruit_AS7341::setLowThreshold(uint16_t low_threshold) { 561 | Adafruit_BusIO_Register sp_low_threshold_reg = 562 | Adafruit_BusIO_Register(i2c_dev, AS7341_SP_LOW_TH_L, 2, LSBFIRST); 563 | return sp_low_threshold_reg.write(low_threshold); 564 | } 565 | 566 | /** 567 | * @brief Returns the current low thighreshold for spectral measurements 568 | * 569 | * @return int16_t The current low threshold 570 | */ 571 | uint16_t Adafruit_AS7341::getLowThreshold(void) { 572 | Adafruit_BusIO_Register sp_low_threshold_reg = 573 | Adafruit_BusIO_Register(i2c_dev, AS7341_SP_LOW_TH_L, 2, LSBFIRST); 574 | return sp_low_threshold_reg.read(); 575 | } 576 | 577 | /** 578 | * @brief Sets the threshold above which spectral measurements will trigger 579 | * interrupts when the APERS count is reached 580 | * 581 | * @param high_threshold 582 | * @return true: success false: failure 583 | */ 584 | bool Adafruit_AS7341::setHighThreshold(uint16_t high_threshold) { 585 | Adafruit_BusIO_Register sp_high_threshold_reg = 586 | Adafruit_BusIO_Register(i2c_dev, AS7341_SP_HIGH_TH_L, 2, LSBFIRST); 587 | return sp_high_threshold_reg.write(high_threshold); 588 | } 589 | 590 | /** 591 | * @brief Returns the current high thighreshold for spectral measurements 592 | * 593 | * @return int16_t The current high threshold 594 | */ 595 | uint16_t Adafruit_AS7341::getHighThreshold(void) { 596 | Adafruit_BusIO_Register sp_high_threshold_reg = 597 | Adafruit_BusIO_Register(i2c_dev, AS7341_SP_HIGH_TH_L, 2, LSBFIRST); 598 | return sp_high_threshold_reg.read(); 599 | } 600 | 601 | /** 602 | * @brief Enable Interrupts based on spectral measurements 603 | * 604 | * @param enable_int true: enable false: disable 605 | * @return true: success false: falure 606 | */ 607 | bool Adafruit_AS7341::enableSpectralInterrupt(bool enable_int) { 608 | Adafruit_BusIO_Register int_enable_reg = 609 | Adafruit_BusIO_Register(i2c_dev, AS7341_INTENAB); 610 | Adafruit_BusIO_RegisterBits sp_int_bit = 611 | Adafruit_BusIO_RegisterBits(&int_enable_reg, 1, 3); 612 | return sp_int_bit.write(enable_int); 613 | } 614 | 615 | /** 616 | * @brief Enabled system interrupts 617 | * 618 | * @param enable_int Set to true to enable system interrupts 619 | * @return true: success false: failure 620 | */ 621 | bool Adafruit_AS7341::enableSystemInterrupt(bool enable_int) { 622 | Adafruit_BusIO_Register int_enable_reg = 623 | Adafruit_BusIO_Register(i2c_dev, AS7341_INTENAB); 624 | Adafruit_BusIO_RegisterBits sien_int_bit = 625 | Adafruit_BusIO_RegisterBits(&int_enable_reg, 1, 0); 626 | return sien_int_bit.write(enable_int); 627 | } 628 | 629 | // Spectral Interrupt Persistence. 630 | // Defines a filter for the number of consecutive 631 | // occurrences that spectral data must remain outside 632 | // the threshold range between SP_TH_L and 633 | // SP_TH_H before an interrupt is generated. The 634 | // spectral data channel used for the persistence filter 635 | // is set by SP_TH_CHANNEL. Any sample that is 636 | // inside the threshold range resets the counter to 0. 637 | 638 | /** 639 | * @brief Sets the number of times an interrupt threshold must be exceeded 640 | * before an interrupt is triggered 641 | * 642 | * @param cycle_count The number of cycles to trigger an interrupt 643 | * @return true: success false: failure 644 | */ 645 | bool Adafruit_AS7341::setAPERS(as7341_int_cycle_count_t cycle_count) { 646 | Adafruit_BusIO_Register pers_reg = 647 | Adafruit_BusIO_Register(i2c_dev, AS7341_PERS); 648 | Adafruit_BusIO_RegisterBits apers_bits = 649 | Adafruit_BusIO_RegisterBits(&pers_reg, 4, 0); 650 | return apers_bits.write(cycle_count); 651 | } 652 | 653 | /** 654 | * @brief Set the ADC channel to use for spectral thresholds including 655 | * interrupts, automatic gain control, and persistance settings 656 | * 657 | * @param channel The channel to use for spectral thresholds. Must be a 658 | * as7341_adc_channel_t **except for** `AS7341_ADC_CHANNEL_5` 659 | * @return true: success false: failure 660 | */ 661 | bool Adafruit_AS7341::setSpectralThresholdChannel( 662 | as7341_adc_channel_t channel) { 663 | if (channel == AS7341_ADC_CHANNEL_5) { 664 | return false; 665 | } 666 | Adafruit_BusIO_Register cfg_12_reg = 667 | Adafruit_BusIO_Register(i2c_dev, AS7341_CFG12); 668 | Adafruit_BusIO_RegisterBits spectral_threshold_ch_bits = 669 | Adafruit_BusIO_RegisterBits(&cfg_12_reg, 3, 0); 670 | return spectral_threshold_ch_bits.write(channel); 671 | } 672 | 673 | /** 674 | * @brief Returns the current value of the Interupt status register 675 | * 676 | * @return uint8_t 677 | */ 678 | uint8_t Adafruit_AS7341::getInterruptStatus(void) { 679 | Adafruit_BusIO_Register int_status_reg = 680 | Adafruit_BusIO_Register(i2c_dev, AS7341_STATUS); 681 | return (uint8_t)int_status_reg.read(); 682 | } 683 | 684 | /** 685 | * @brief Returns the status of the spectral measurement threshold interrupts 686 | * 687 | * @return true: interrupt triggered false: interrupt not triggered 688 | */ 689 | bool Adafruit_AS7341::spectralInterruptTriggered(void) { 690 | Adafruit_BusIO_Register int_status_reg = 691 | Adafruit_BusIO_Register(i2c_dev, AS7341_STATUS); 692 | Adafruit_BusIO_RegisterBits aint_bit = 693 | Adafruit_BusIO_RegisterBits(&int_status_reg, 1, 3); 694 | 695 | return aint_bit.read(); 696 | } 697 | 698 | /** 699 | * @brief Clear the interrupt status register 700 | * 701 | * @return true: success false: failure 702 | */ 703 | bool Adafruit_AS7341::clearInterruptStatus(void) { 704 | Adafruit_BusIO_Register int_status_reg = 705 | Adafruit_BusIO_Register(i2c_dev, AS7341_STATUS); 706 | 707 | return int_status_reg.write(0xFF); 708 | } 709 | 710 | /** 711 | * @brief The current state of the spectral measurement interrupt status 712 | * register 713 | * 714 | * @return uint8_t The current status register 715 | */ 716 | uint8_t Adafruit_AS7341::spectralInterruptSource(void) { 717 | Adafruit_BusIO_Register status3_reg = 718 | Adafruit_BusIO_Register(i2c_dev, AS7341_STATUS3); 719 | 720 | uint8_t spectral_int_source = status3_reg.read(); 721 | last_spectral_int_source = spectral_int_source; 722 | return spectral_int_source; 723 | } 724 | 725 | /** 726 | * @brief The status of the low threshold interrupt 727 | * 728 | * @return true: low interrupt triggered false: interrupt not triggered 729 | */ 730 | bool Adafruit_AS7341::spectralLowTriggered(void) { 731 | return (last_spectral_int_source & AS7341_SPECTRAL_INT_LOW_MSK) > 0; 732 | } 733 | 734 | /** 735 | * @brief The status of the high threshold interrupt 736 | * 737 | * @return true: high interrupt triggered false: interrupt not triggered 738 | */ 739 | bool Adafruit_AS7341::spectralHighTriggered(void) { 740 | return (last_spectral_int_source & AS7341_SPECTRAL_INT_HIGH_MSK) > 0; 741 | } 742 | 743 | /** 744 | * @brief 745 | * 746 | * @return true: success false: failure 747 | */ 748 | bool Adafruit_AS7341::getIsDataReady() { 749 | Adafruit_BusIO_Register status2_reg = 750 | Adafruit_BusIO_Register(i2c_dev, AS7341_STATUS2); 751 | Adafruit_BusIO_RegisterBits avalid_bit = 752 | Adafruit_BusIO_RegisterBits(&status2_reg, 1, 6); 753 | 754 | return avalid_bit.read(); 755 | } 756 | 757 | /** 758 | * @brief Configure SMUX for sensors F1-4, Clear and NIR 759 | * 760 | */ 761 | void Adafruit_AS7341::setup_F1F4_Clear_NIR() { 762 | // SMUX Config for F1,F2,F3,F4,NIR,Clear 763 | writeRegister(byte(0x00), byte(0x30)); // F3 left set to ADC2 764 | writeRegister(byte(0x01), byte(0x01)); // F1 left set to ADC0 765 | writeRegister(byte(0x02), byte(0x00)); // Reserved or disabled 766 | writeRegister(byte(0x03), byte(0x00)); // F8 left disabled 767 | writeRegister(byte(0x04), byte(0x00)); // F6 left disabled 768 | writeRegister( 769 | byte(0x05), 770 | byte(0x42)); // F4 left connected to ADC3/f2 left connected to ADC1 771 | writeRegister(byte(0x06), byte(0x00)); // F5 left disbled 772 | writeRegister(byte(0x07), byte(0x00)); // F7 left disbled 773 | writeRegister(byte(0x08), byte(0x50)); // CLEAR connected to ADC4 774 | writeRegister(byte(0x09), byte(0x00)); // F5 right disabled 775 | writeRegister(byte(0x0A), byte(0x00)); // F7 right disabled 776 | writeRegister(byte(0x0B), byte(0x00)); // Reserved or disabled 777 | writeRegister(byte(0x0C), byte(0x20)); // F2 right connected to ADC1 778 | writeRegister(byte(0x0D), byte(0x04)); // F4 right connected to ADC3 779 | writeRegister(byte(0x0E), byte(0x00)); // F6/F8 right disabled 780 | writeRegister(byte(0x0F), byte(0x30)); // F3 right connected to AD2 781 | writeRegister(byte(0x10), byte(0x01)); // F1 right connected to AD0 782 | writeRegister(byte(0x11), byte(0x50)); // CLEAR right connected to AD4 783 | writeRegister(byte(0x12), byte(0x00)); // Reserved or disabled 784 | writeRegister(byte(0x13), byte(0x06)); // NIR connected to ADC5 785 | } 786 | 787 | /** 788 | * @brief Configure SMUX for sensors F5-8, Clear and NIR 789 | * 790 | */ 791 | void Adafruit_AS7341::setup_F5F8_Clear_NIR() { 792 | // SMUX Config for F5,F6,F7,F8,NIR,Clear 793 | writeRegister(byte(0x00), byte(0x00)); // F3 left disable 794 | writeRegister(byte(0x01), byte(0x00)); // F1 left disable 795 | writeRegister(byte(0x02), byte(0x00)); // reserved/disable 796 | writeRegister(byte(0x03), byte(0x40)); // F8 left connected to ADC3 797 | writeRegister(byte(0x04), byte(0x02)); // F6 left connected to ADC1 798 | writeRegister(byte(0x05), byte(0x00)); // F4/ F2 disabled 799 | writeRegister(byte(0x06), byte(0x10)); // F5 left connected to ADC0 800 | writeRegister(byte(0x07), byte(0x03)); // F7 left connected to ADC2 801 | writeRegister(byte(0x08), byte(0x50)); // CLEAR Connected to ADC4 802 | writeRegister(byte(0x09), byte(0x10)); // F5 right connected to ADC0 803 | writeRegister(byte(0x0A), byte(0x03)); // F7 right connected to ADC2 804 | writeRegister(byte(0x0B), byte(0x00)); // Reserved or disabled 805 | writeRegister(byte(0x0C), byte(0x00)); // F2 right disabled 806 | writeRegister(byte(0x0D), byte(0x00)); // F4 right disabled 807 | writeRegister( 808 | byte(0x0E), 809 | byte(0x24)); // F8 right connected to ADC2/ F6 right connected to ADC1 810 | writeRegister(byte(0x0F), byte(0x00)); // F3 right disabled 811 | writeRegister(byte(0x10), byte(0x00)); // F1 right disabled 812 | writeRegister(byte(0x11), byte(0x50)); // CLEAR right connected to AD4 813 | writeRegister(byte(0x12), byte(0x00)); // Reserved or disabled 814 | writeRegister(byte(0x13), byte(0x06)); // NIR connected to ADC5 815 | } 816 | 817 | /** 818 | * @brief Configure SMUX for flicker detection 819 | * 820 | */ 821 | void Adafruit_AS7341::FDConfig() { 822 | // SMUX Config for Flicker- register (0x13)left set to ADC6 for flicker 823 | // detection 824 | writeRegister(byte(0x00), byte(0x00)); // disabled 825 | writeRegister(byte(0x01), byte(0x00)); // disabled 826 | writeRegister(byte(0x02), byte(0x00)); // reserved/disabled 827 | writeRegister(byte(0x03), byte(0x00)); // disabled 828 | writeRegister(byte(0x04), byte(0x00)); // disabled 829 | writeRegister(byte(0x05), byte(0x00)); // disabled 830 | writeRegister(byte(0x06), byte(0x00)); // disabled 831 | writeRegister(byte(0x07), byte(0x00)); // disabled 832 | writeRegister(byte(0x08), byte(0x00)); // disabled 833 | writeRegister(byte(0x09), byte(0x00)); // disabled 834 | writeRegister(byte(0x0A), byte(0x00)); // disabled 835 | writeRegister(byte(0x0B), byte(0x00)); // Reserved or disabled 836 | writeRegister(byte(0x0C), byte(0x00)); // disabled 837 | writeRegister(byte(0x0D), byte(0x00)); // disabled 838 | writeRegister(byte(0x0E), byte(0x00)); // disabled 839 | writeRegister(byte(0x0F), byte(0x00)); // disabled 840 | writeRegister(byte(0x10), byte(0x00)); // disabled 841 | writeRegister(byte(0x11), byte(0x00)); // disabled 842 | writeRegister(byte(0x12), byte(0x00)); // Reserved or disabled 843 | writeRegister(byte(0x13), 844 | byte(0x60)); // Flicker connected to ADC5 to left of 0x13 845 | } 846 | 847 | // TODO; check for valid values 848 | /** 849 | * @brief Sets the integration time step count 850 | * 851 | * Total integration time will be `(ATIME + 1) * (ASTEP + 1) * 2.78µS` 852 | * 853 | * @param atime_value The integration time step count 854 | * @return true: success false: failure 855 | */ 856 | bool Adafruit_AS7341::setATIME(uint8_t atime_value) { 857 | Adafruit_BusIO_Register atime_reg = 858 | Adafruit_BusIO_Register(i2c_dev, AS7341_ATIME); 859 | return atime_reg.write(atime_value); 860 | } 861 | 862 | /** 863 | * @brief Returns the integration time step count 864 | * 865 | * Total integration time will be `(ATIME + 1) * (ASTEP + 1) * 2.78µS` 866 | * 867 | * @return uint8_t The current integration time step count 868 | */ 869 | uint8_t Adafruit_AS7341::getATIME() { 870 | Adafruit_BusIO_Register atime_reg = 871 | Adafruit_BusIO_Register(i2c_dev, AS7341_ATIME); 872 | return atime_reg.read(); 873 | } 874 | 875 | /** 876 | * @brief Sets the integration time step size 877 | * 878 | * @param astep_value Integration time step size in 2.78 microsecon increments 879 | * Step size is `(astep_value+1) * 2.78 uS` 880 | * @return true: success false: failure 881 | */ 882 | bool Adafruit_AS7341::setASTEP(uint16_t astep_value) { 883 | Adafruit_BusIO_Register astep_reg = 884 | Adafruit_BusIO_Register(i2c_dev, AS7341_ASTEP_L, 2, LSBFIRST); 885 | return astep_reg.write(astep_value); 886 | } 887 | 888 | /** 889 | * @brief Returns the integration time step size 890 | * 891 | * Step size is `(astep_value+1) * 2.78 uS` 892 | * 893 | * @return uint16_t The current integration time step size 894 | */ 895 | uint16_t Adafruit_AS7341::getASTEP() { 896 | Adafruit_BusIO_Register astep_reg = 897 | Adafruit_BusIO_Register(i2c_dev, AS7341_ASTEP_L, 2, LSBFIRST); 898 | return astep_reg.read(); 899 | } 900 | 901 | /** 902 | * @brief Sets the ADC gain multiplier 903 | * 904 | * @param gain_value The gain amount. must be an `as7341_gain_t` 905 | * @return true: success false: failure 906 | */ 907 | bool Adafruit_AS7341::setGain(as7341_gain_t gain_value) { 908 | Adafruit_BusIO_Register cfg1_reg = 909 | Adafruit_BusIO_Register(i2c_dev, AS7341_CFG1); 910 | return cfg1_reg.write(gain_value); 911 | // AGAIN bitfield is only[0:4] but the rest is empty 912 | } 913 | 914 | /** 915 | * @brief Returns the ADC gain multiplier 916 | * 917 | * @return as7341_gain_t The current ADC gain multiplier 918 | */ 919 | as7341_gain_t Adafruit_AS7341::getGain() { 920 | Adafruit_BusIO_Register cfg1_reg = 921 | Adafruit_BusIO_Register(i2c_dev, AS7341_CFG1); 922 | return (as7341_gain_t)cfg1_reg.read(); 923 | } 924 | 925 | /** 926 | * @brief Returns the integration time 927 | * 928 | * The integration time is `(ATIME + 1) * (ASTEP + 1) * 2.78µS` 929 | * 930 | * @return long The current integration time in ms 931 | */ 932 | long Adafruit_AS7341::getTINT() { 933 | long astep = getASTEP(); 934 | long atime = getATIME(); 935 | 936 | return (atime + 1) * (astep + 1) * 2.78 / 1000; 937 | } 938 | 939 | /** 940 | * @brief Converts raw ADC values to basic counts 941 | * 942 | * The basic counts are `RAW/(GAIN * TINT)` 943 | * 944 | * @param raw The raw ADC values to convert 945 | * 946 | * @return float The basic counts 947 | */ 948 | float Adafruit_AS7341::toBasicCounts(uint16_t raw) { 949 | float gain_val = 0; 950 | as7341_gain_t gain = getGain(); 951 | switch (gain) { 952 | case AS7341_GAIN_0_5X: 953 | gain_val = 0.5; 954 | break; 955 | case AS7341_GAIN_1X: 956 | gain_val = 1; 957 | break; 958 | case AS7341_GAIN_2X: 959 | gain_val = 2; 960 | break; 961 | case AS7341_GAIN_4X: 962 | gain_val = 4; 963 | break; 964 | case AS7341_GAIN_8X: 965 | gain_val = 8; 966 | break; 967 | case AS7341_GAIN_16X: 968 | gain_val = 16; 969 | break; 970 | case AS7341_GAIN_32X: 971 | gain_val = 32; 972 | break; 973 | case AS7341_GAIN_64X: 974 | gain_val = 64; 975 | break; 976 | case AS7341_GAIN_128X: 977 | gain_val = 128; 978 | break; 979 | case AS7341_GAIN_256X: 980 | gain_val = 256; 981 | break; 982 | case AS7341_GAIN_512X: 983 | gain_val = 512; 984 | break; 985 | } 986 | return raw / (gain_val * (getATIME() + 1) * (getASTEP() + 1) * 2.78 / 1000); 987 | } 988 | 989 | /** 990 | * @brief Detect a flickering light 991 | * @return The frequency of a detected flicker or 1 if a flicker of 992 | * unknown frequency is detected 993 | */ 994 | uint16_t Adafruit_AS7341::detectFlickerHz(void) { 995 | // bool isEnabled = true; 996 | // bool isFdmeasReady = false; 997 | 998 | // disable everything; Flicker detect, smux, wait, spectral, power 999 | disableAll(); 1000 | // re-enable power 1001 | powerEnable(true); 1002 | 1003 | // Write SMUX configuration from RAM to set SMUX chain registers (Write 0x10 1004 | // to CFG6) 1005 | setSMUXCommand(AS7341_SMUX_CMD_WRITE); 1006 | 1007 | // Write new configuration to all the 20 registers for detecting Flicker 1008 | FDConfig(); 1009 | 1010 | // Start SMUX command 1011 | enableSMUX(); 1012 | 1013 | // Enable SP_EN bit 1014 | enableSpectralMeasurement(true); 1015 | 1016 | // Enable flicker detection bit 1017 | writeRegister(byte(AS7341_ENABLE), byte(0x41)); 1018 | delay(500); // SF 2020-08-12 Does this really need to be so long? 1019 | uint16_t flicker_status = getFlickerDetectStatus(); 1020 | enableFlickerDetection(false); 1021 | switch (flicker_status) { 1022 | case 44: 1023 | return 1; 1024 | case 45: 1025 | return 100; 1026 | case 46: 1027 | return 120; 1028 | default: 1029 | return 0; 1030 | } 1031 | } 1032 | 1033 | /** 1034 | * @brief Write a byte to the given register 1035 | * 1036 | * @param addr Register address 1037 | * @param val The value to set the register to 1038 | */ 1039 | void Adafruit_AS7341::writeRegister(byte addr, byte val) { 1040 | Adafruit_BusIO_Register reg = Adafruit_BusIO_Register(i2c_dev, addr); 1041 | reg.write(val); 1042 | } 1043 | --------------------------------------------------------------------------------