All FRDM MCX A346 tutorials

TCS34725 RGB sensor with NXP FRDM MCX A346

Introduction

This article is in short form, because the production of the Adafruit TCS34725 RGB sensor has been discontinued. I don't want to spend too much time on legacy hardware, but I know there's still demand for information on how to integrate the TCS34725 RGB sensor in a FRDM MCX A346 project.

In a future article, I will discuss the I2C protocol, which the TCS34725 uses for communication, and its successor I3C. The FRDM MCX A346 has one instance of the I3C module which is I2C compatible.

The SDK currently uses the I2C terminology (master/slave) which will likely be updated in the future to the I3C terminology (controller/target).

The code is a blend of the Adafruit TCS34725 library and lpi2c_interrupt_b2b_transfer_master SDK example.

Prerequisites

  • MCUXpresso IDE installed
  • NXP FRDM MCX A346 board
  • TCS34725, 4 (Male-to-Female) jumper wires
  • Familiarity with using the Pins Tool
  • Adafruit TCS34725 datasheet (download link)

Configuring your project

Create a new C Project.

On the Configure the project page, give the project an appropriate name of your own choosing (i.e. "MCXA346_tcs34725_demo").

Still on the Configure the project page under Components, expand Drivers > Device > SDK Drivers > select these three drivers: i2c; inputmux; inputmux_connections.

Click Finish.

On the menu bar, click Config Tools > Pins.

Make sure you have your current project selected in the drop down menu in the Pins Tool.

Click Update Code.

For this project we will use pins P1_9 and P1_8, which the Pins Tool defaults to SCL and SDA in the functional group BOARD_InitI2CPins.

Code

Rename your C file holding the main() function appropriately (i.e. MCXA346_tcs34725_demo_main.c). Add a new header file to your source folder (i.e. tcs34725.h). Add a new C file to your source folder (i.e. tcs34725.c).

MCXA346_tcs34725_demo_main.c

#include "tcs34725.h"
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "fsl_debug_console.h"
#include "fsl_lpi2c.h"
#include "pin_mux.h"

int main(void)
{
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    //Initiate I2C pins
    BOARD_InitI2CPins();

#ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
    BOARD_InitDebugConsole();
#endif

    //Initiate I2C clock
    CLOCK_SetClockDiv(kCLOCK_DivLPI2C2, 1u);
    CLOCK_AttachClk(kFRO_LF_DIV_to_LPI2C2);

    lpi2c_master_config_t masterConfig;
    LPI2C_MasterGetDefaultConfig(&masterConfig);
    LPI2C_MasterInit(LPI2C2, &masterConfig, CLOCK_GetLpi2cClkFreq(2u));

    PRINTF("TCS34725 test\n");

    if (!tcs34725_init(LPI2C2)) {
        PRINTF("Init failed\n");
        while (1);
    }

    while (1) {
        uint16_t r, g, b, c;
        tcs34725_read_rgbc(LPI2C2, &r, &g, &b, &c);

        PRINTF("R=%u  G=%u  B=%u  C=%u\r\n", r, g, b, c);

        SDK_DelayAtLeastUs(500000, CLOCK_GetFreq(kCLOCK_CoreSysClk));
    }
}

tcs34725.h

#ifndef TCS34725_H
#define TCS34725_H

#include <stdint.h>
#include <stdbool.h>
#include "fsl_lpi2c.h"

// I2C adres
#define TCS34725_ADDRESS        (0x29)

// Command bit
#define TCS34725_COMMAND_BIT    (0x80)

// Registers
#define TCS34725_ENABLE         (0x00)
#define TCS34725_ATIME          (0x01)
#define TCS34725_CONTROL        (0x0F)

#define TCS34725_CDATAL         (0x14)
#define TCS34725_CDATAH         (0x15)
#define TCS34725_RDATAL         (0x16)
#define TCS34725_RDATAH         (0x17)
#define TCS34725_GDATAL         (0x18)
#define TCS34725_GDATAH         (0x19)
#define TCS34725_BDATAL         (0x1A)
#define TCS34725_BDATAH         (0x1B)

// Enable register bits
#define TCS34725_ENABLE_PON     (0x01)
#define TCS34725_ENABLE_AEN     (0x02)

// API
bool tcs34725_init(LPI2C_Type *base);
uint16_t tcs34725_read16(LPI2C_Type *base, uint8_t reg);
void tcs34725_read_rgbc(LPI2C_Type *base, uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c);

#endif

tcs34725.c

#include "tcs34725.h"
#include "fsl_lpi2c.h"
#include "fsl_debug_console.h"
#include "fsl_common.h"

status_t tcs34725_write8(LPI2C_Type *base, uint8_t reg, uint8_t value)
{
    uint8_t data[2];
    data[0] = TCS34725_COMMAND_BIT | reg;
    data[1] = value;

    lpi2c_master_transfer_t xfer = {0};
    xfer.slaveAddress = TCS34725_ADDRESS;
    xfer.direction = kLPI2C_Write;
    xfer.data = data;
    xfer.dataSize = 2;
    xfer.flags = kLPI2C_TransferDefaultFlag;

    return LPI2C_MasterTransferBlocking(base, &xfer);
}


uint16_t tcs34725_read16(LPI2C_Type *base, uint8_t reg)
{
    uint8_t cmd = TCS34725_COMMAND_BIT | reg;
    uint8_t buffer[2];

    lpi2c_master_transfer_t xfer = {0};

    // Write register address
    xfer.slaveAddress = TCS34725_ADDRESS;
    xfer.direction = kLPI2C_Write;
    xfer.data = &cmd;
    xfer.dataSize = 1;
    xfer.flags = kLPI2C_TransferDefaultFlag;
    LPI2C_MasterTransferBlocking(base, &xfer);

    // Read 2 bytes
    xfer.direction = kLPI2C_Read;
    xfer.data = buffer;
    xfer.dataSize = 2;
    LPI2C_MasterTransferBlocking(base, &xfer);

    return (buffer[1] << 8) | buffer[0];
}

bool tcs34725_init(LPI2C_Type *base)
{
    // Power ON
    if (tcs34725_write8(base, TCS34725_ENABLE, TCS34725_ENABLE_PON) != kStatus_Success)
        return false;

    SDK_DelayAtLeastUs(3000, CLOCK_GetFreq(kCLOCK_CoreSysClk));

    // Enable RGBC
    if (tcs34725_write8(base, TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN) != kStatus_Success)
        return false;

    /*
     * Integration time (default 2.4 ms), see data sheet
     * Integration Time = 2.4 ms * (256 - ATIME)
     * If third parameter is 0xFF, which is hex for 255, ATIME is set as 255 and integration time becomes 2.4 ms (2.4 ms * (256 - 255))
     * I set ATIME as 0x00, which hex for 0, so integration time becomes 614.4 ms
     * This is because my readings are quite low (I have a relatively dark environment)
     * Please adjust this value to match your own environment
     */
    tcs34725_write8(base, TCS34725_ATIME, 0x00);

    // Gain (1x)
    tcs34725_write8(base, TCS34725_CONTROL, 0x00);

    return true;
}

void tcs34725_read_rgbc(LPI2C_Type *base, uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c)
{
    *c = tcs34725_read16(base, TCS34725_CDATAL);
    *r = tcs34725_read16(base, TCS34725_RDATAL);
    *g = tcs34725_read16(base, TCS34725_GDATAL);
    *b = tcs34725_read16(base, TCS34725_BDATAL);
}
All FRDM MCX A346 tutorials