element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Path to Programmable 3
  • Challenges & Projects
  • Design Challenges
  • Path to Programmable 3
  • More
  • Cancel
Path to Programmable 3
Blog Path to Programmable III Training Blog #06: MiniZed Color Sensor Webserver - Final
  • Blog
  • Forum
  • Documents
  • Leaderboard
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Path to Programmable 3 to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: flyingbean
  • Date Created: 5 Sep 2023 2:23 AM Date Created
  • Views 1048 views
  • Likes 8 likes
  • Comments 4 comments
  • design challenge
  • Zynq XC7Z007S SoC
  • AMD XILINX
  • avnet
  • zynq
  • petalinux
  • fpga
  • Path to Programmable III
  • Path to Programmable 3
  • minized
Related
Recommended

Path to Programmable III Training Blog #06: MiniZed Color Sensor Webserver - Final

flyingbean
flyingbean
5 Sep 2023

Table of Contents

  • Introduction
  • Project Structure
  • MiniZed Color Sensor Webserver Demo
  • Conclusions
  • References

Introduction

A color sensor is a type of transducer that converts one form of energy into another form.  Digilent PMOD color module is used for the project, which is paired with a circuit through an analog to digital converter. Then a MiniZed single board computer can process the digital version of color for many different applications, such as Internet of Things (IoT) applications. A simple WiFi webserver will display the color codes from PMOD color module with color detected as the webserver background.

Project Structure

  1. Color sensor webserver top level structure

There are two systems in the project: IoT webserver and IoT Web browser as below.

image

Figure 1: MiniZed PMOD Color Sensor Webserver Concept Diagram

IoT webserver system includes:

        a. AMD/Xilin Zynq FPGA and Mutrata BCM 4343W WiFi module on MiniZed platform,

        b. PMOD color sensor and a PMOD switch module: color sensor and LED PWM dimming control.

IoT web browser system includes:

        a. A WiFi router

        b. An Ethernet connected Windows 10 PC.

     2. TCS34725 Color Sensor

The core part of Digilent PMOD color sensor is TCS34725, which is a light-to-digital converter. There are a 3X4 photodiode array, four ADCs, some data registers, a state machine and an I2C interface on TCS34725.  The 3X4 photodiode array is composed of red-filtered, green-filtered, blue-filtered, and clear(unfiltered) photodiodes. In addition, the photodiodes are coated with an IR-blocking filter. The four integrated ADCs simultaneously convert the amplified photodiode currents to a 16-bit digital value. Upon completion of a conversion cycle, the results are transferred to the data registers, which are double-buffered to ensure the integrity of the data. All of the internal timing, as well as the low-power wait state, is controlled by the state machine.

2-wire I2C communication with up to 400kHz is the interface between MiniZed and PMOD color sensor.

The principle of detecting color from a subject is based on reflectance property of a colored surface, as illustrated in Figure 2.

image

Figure 2: Basic Principle of Color Sensor

When applying a light source on a subject, the surface will reflect a specific spectrum while absorbing all the other spectra. The success of a color sensor by reflection depends on the detector, the illumination of the light and the subject.  The detailed information about the sensor structure and theory can be found from Ref[2].

    3. FPGA Hardware Design of MiniZed PMOD Color Sensor Webserver

Avnet Path to Programmable 3 provides a great framework for this project. I already provided some introductory blogs on the training and flows. Please check the links at the bottom of the report. The overview of the FPGA design diagram is presented at Figure 3.

image

Figure 3: MiniZed PMOD Color Sensor Webserver FPGA Diagram

AXI_IIC_1 is the interface between Zynq FPGA and PMOD color module on PMOD1. I add a PWM VDHL module into Zynq FPGA for LED dimming control. The reference design of PWM VHDL is from DigiKey TechForum(Ref[3]).  Digilent PMOD_SWT will be attached to PMOD2 for LED dimming control. Digilent PMOD color module has one dimmable LED for light source. There are 4 switchers on the PMOD_SWT module, so 4-bit resolution is configured for PWM duty cycle control.

The theory of PWM dimming control is well documented at Ref[3]. 50MHz clock is applied as the system clock of PWM VHDL module. 1Khz is configured frequency of PWM signal. The bit resolution defines the resolution of the pulse width. For 4-bit resolution PWM duty cycle control design here, the pulse width has resolution at 16. The finest possible pulse width adjustment is the period (i.e. 1/ pwm_freq) divided by 16. The parameter phases sets the number of outputs and their relation to one another. The number of PWM outputs means phases, and these outputs are 360°/phases out-of-phase with one another.

Figure 4 presents the VHDL module implemented at Vivado 2021 GUI diagram. Figure 5 shows how to configure the parameters for PWM VHDL module.

PWM_VHDL_module

Figure 4: PWM VHDL Module for Dimmable LED

PWM_module_config

Figure 5: PWM VHDL Module Configuration

 Final report for MiniZed FPGA hardware report:

{gallery}MiniZed_FPGA_HW_report

MiniZed_HW_Mem_mapMiniZed_HW_Mem_map

REPLACE THIS TEXT WITH YOUR IMAGE

MiniZed_PMOD_Color_Webser_FPGA_resource_report MiniZed_Webser_FPGA_resource_report

MiniZed_HW_TimingMiniZed_HW_Timing

      4. PMOD Color Sensor Linux APIs on MiniZed

Embedded Linux on Zynq FPGA is a very big task in the project, which is one of the top goals I joined this design challenge. After reviewing my design objectives and the constraints of each modules on MiniZed platform, I decided to carry over the Petalinux flow from Avnet MiniZed  Training Courses 2021.1 into the project because the WiFi module for IoT applications has to be implemented under Linux OS. I did not plan to use PYNQ framework on MiniZed this time.  So an updated Petalinux flow from Avnet framework needs is required.

I started to implement Digilent PMOD color module from Vitis 2021.1 standalone application on MiniZed platform. Then I ported Vitis 2021.1 standalone application into Petalinux color sensor driver, which worked well.  After I reviewed webserver training materials from Avnet MiniZed training Courses 2021.1, I realized that I did need either PYNQ or Python for both PMOD color sensor API and webserver design. However Avnet webserver design framework did not fit in my project very well, so I finally decided to design a webserver from a scratch for this project. It is my first time to develop a webserver/website for any projects.

      4.1 Digilent PMOD color sensor standalone API on MiniZed

Digilent provided a framework for many PMOD modules developed by them. A quick prototype bench testing under Vitis 2021.1 standalone API is very straightforward on MiniZed platform.

image

Figure 6 : Digilent PMOD Color Module Standalone FPGA Diagram

MiniZed prototype bench testing is ploted at Figure 7.

image

Figure 7: Digilent PMOD Color Module Standalone API Running on MiniZed

Notes for Digilent PMOD library: it is not a good path to integrate them into Xilinx Petalinux flow due to device tree development and driver compatibilities between Vitis standalone API and Xilinx Linux library.

     4.2 Digilent PMOD color sensor: Petalinux API

AMD/Xilinx does provide a lot of Linux drivers on Zynq FPGA platform. I did migrate Digilent PMOD color module standalone driver into Zynq Linux OS after taking the training class of Integrating Sensors on MiniZed with PetaLinux. Here is the snapshot of PMOD_color Linux API running on MiniZed Petalinux 2021.1.

Source codes of this part will be commited into my github repo. The Petalinux did let my PMOD color API run on MiniZed as Figure 8.

image

Figure 8: Digilent PMOD Color Module Petalinux API Running on MiniZed

      4.3 Using Python3 to develop Digilent PMOD color sensor API

Xilinx/AMD Petalinux 2021.1 provides a framework for Python3 application development. I configure the kernel with I2C SMBUS for Python3 development as Figure 9.

i2c_smbus_kernel_driver

Figure 9: Configure SMBUS for I2C at Petalinux Kernel

Ref[4] is a good reference to for Python 3 drivers of TCS34725, which targeted on Raspberry Pi platform. I am able to use TCS34725 Python driver from Ref[4] for MiniZed Petalinux tool chain with a little bit tinkering work.

from flask import Flask, render_template, request
from TCS34725 import TCS34725
import http.server
import socketserver
import logging
import cgi
import sys
import re
import subprocess
import time, struct
# Flask constructor
app = Flask(__name__)
 
sys.path.insert(1, '/usr/local/bin/gpio')
from gpio_common import gpio_map

PsButtonPortnumber  = gpio_map['PS_BUTTON'].gpio
PS_RedPortnumber    = gpio_map['PS_R'].gpio
PS_GreenPortnumber  = gpio_map['PS_G'].gpio
PL_RedPortnumber    = gpio_map['PL_R'].gpio
PL_GreenPortnumber  = gpio_map['PL_G'].gpio
EnableMicPortnumber = gpio_map['PL_MIC1'].gpio


Light=TCS34725(0X29, debug=False)
if(Light.TCS34725_init() == 1):
    print("TCS34725 initialization error!!")
else:
   print("TCS34725 initialization success!!")
       
try:
    Light=TCS34725(0X29, debug=False)
    if(Light.TCS34725_init() == 1):
        print("TCS34725 initialization error!!")
    else:
        print("TCS34725 initialization success!!")
    time.sleep(2)
    while True:   
        print ("\nProgram start")
        ID=Light.Read_ID()
        print("Read_ID: %x "%ID), 
        Light.Get_RGBData()
        print ("\nProgram get rgb data")
        print("R: %d "%Light.R), 
        print("G: %d "%Light.G), 
        print("B: %d "%Light.B), 
        Light.GetRGB888()       
        print("RGB888R: %d "%Light.RGB888_R), 
        print("RGB888G: %d "%Light.RGB888_G), 
        print("RGB888B: %d "%Light.RGB888_B), 
        print("RGB888C: %#x "%Light.C),
        #flyingbean
        #test_data=Light.RGB888_R,
         
        #print(type(test_data)), 
        #print("test_data: ",test_data[0]), 
        #print("test_data rounding: ",round(test_data[0])), 
        #test_data_hex= int((test_data[0])) ,
        #print(type(test_data_hex)), 
        #print("test_data rounding: %x",(test_data_hex[0])<<1), 
        
        #flyingbean
        reg_RGB888_R= Light.RGB888_R,
        Hex_RGB888_R= int(reg_RGB888_R[0]),
        reg_RGB888_G= Light.RGB888_G,
        Hex_RGB888_G= int(reg_RGB888_G[0]),
        reg_RGB888_B= Light.RGB888_B,
        Hex_RGB888_B= int(reg_RGB888_B[0]),
        print("Hex_RGB888_R : %#x"%Hex_RGB888_R), 
        print("Hex_RGB888_G : %#x"%Hex_RGB888_G), 
        print("Hex_RGB888_B : %#x"%Hex_RGB888_B), 
        
       # Light.GetRGB565()
        #print("RGB565: %#x "%Light.RG565),
        #print("RGB565 R: %d "%Light.RG565_R),
        #print("RGB565 G: %d "%Light.RG565_G),
        #print("RGB565 B: %d "%Light.RG565_B),
       #print("RGB888: %#x "%Light.RGB888),    
        print("LUX: %d "%Light.Get_Lux()),
        print("CT: %dK "%Light.Get_ColorTemp()),
        print("INT: %d "%Light.GetLux_Interrupt(0xff00, 0x00ff)),
        time.sleep(1);
       
except:
    #GPIO.cleanup()
    print ("\nProgram end")
    exit()

TCS34725 Python driver source code:

#!/usr/bin/python

import time
import math
import smbus
#import pygame
#import RPi.GPIO as GPIO


#GPIO 

LED     = 18
INT_PORT= 17

TCS34725_R_Coef     = 0.136 
TCS34725_G_Coef     = 1.000
TCS34725_B_Coef     = -0.444
TCS34725_GA         = 1.0
TCS34725_DF         = 310.0
TCS34725_CT_Coef    = 3810.0
TCS34725_CT_Offset  =1391.0

class TCS34725:
    Gain_t = 0
    IntegrationTime_t = 0

    TCS34725_CMD_BIT        = 0x80
    TCS34725_CMD_Read_Byte  = 0x00
    TCS34725_CMD_Read_Word  = 0x20
    TCS34725_CMD_Clear_INT  = 0x66 

    TCS34725_ENABLE         = 0x00
    TCS34725_ENABLE_AIEN    = 0x10    # RGBC Interrupt Enable  
    TCS34725_ENABLE_WEN     = 0x08     # Wait enable - Writing 1 activates the wait timer  
    TCS34725_ENABLE_AEN     = 0x02     # RGBC Enable - Writing 1 actives the ADC, 0 disables it  
    TCS34725_ENABLE_PON     = 0x01    # Power on - Writing 1 activates the internal oscillator, 0 disables it  
    TCS34725_ATIME          = 0x01    # Integration time  
    TCS34725_WTIME          = 0x03    # Wait time (if TCS34725_ENABLE_WEN is asserted)  
    TCS34725_WTIME_2_4MS    = 0xFF    # WLONG0 = 2.4ms   WLONG1 = 0.029s  
    TCS34725_WTIME_204MS    = 0xAB    # WLONG0 = 204ms   WLONG1 = 2.45s   
    TCS34725_WTIME_614MS    = 0x00    # WLONG0 = 614ms   WLONG1 = 7.4s    
    TCS34725_AILTL          = 0x04    # Clear channel lower interrupt threshold  
    TCS34725_AILTH          = 0x05
    TCS34725_AIHTL          = 0x06    # Clear channel upper interrupt threshold  
    TCS34725_AIHTH          = 0x07
    TCS34725_PERS           = 0x0C    # Persistence register - basic SW filtering mechanism for interrupts  
    TCS34725_PERS_NONE      = 0b0000  # Every RGBC cycle generates an interrupt                                 
    TCS34725_PERS_1_CYCLE   = 0b0001  # 1 clean channel value outside threshold range generates an interrupt    
    TCS34725_PERS_2_CYCLE   = 0b0010  # 2 clean channel values outside threshold range generates an interrupt   
    TCS34725_PERS_3_CYCLE   = 0b0011  # 3 clean channel values outside threshold range generates an interrupt   
    TCS34725_PERS_5_CYCLE   = 0b0100  # 5 clean channel values outside threshold range generates an interrupt   
    TCS34725_PERS_10_CYCLE  = 0b0101  # 10 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_15_CYCLE  = 0b0110  # 15 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_20_CYCLE  = 0b0111  # 20 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_25_CYCLE  = 0b1000  # 25 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_30_CYCLE  = 0b1001  # 30 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_35_CYCLE  = 0b1010  # 35 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_40_CYCLE  = 0b1011  # 40 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_45_CYCLE  = 0b1100  # 45 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_50_CYCLE  = 0b1101  # 50 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_55_CYCLE  = 0b1110  # 55 clean channel values outside threshold range generates an interrupt  
    TCS34725_PERS_60_CYCLE  = 0b1111  # 60 clean channel values outside threshold range generates an interrupt  
    TCS34725_CONFIG         = 0x0D
    TCS34725_CONFIG_WLONG   = 0x02    # Choose between short and long (12x) wait times via TCS34725_WTIME  
    TCS34725_CONTROL        = 0x0F    # Set the gain level for the sensor  
    TCS34725_ID             = 0x12    # 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727  
    TCS34725_STATUS         = 0x13
    TCS34725_STATUS_AINT    = 0x10    # RGBC Clean channel interrupt  
    TCS34725_STATUS_AVALID  = 0x01    # Indicates that the RGBC channels have completed an integration cycle  
    TCS34725_CDATAL         = 0x14    # Clear channel data  
    TCS34725_CDATAH         = 0x15
    TCS34725_RDATAL         = 0x16    # Red channel data  
    TCS34725_RDATAH         = 0x17
    TCS34725_GDATAL         = 0x18    # Green channel data  
    TCS34725_GDATAH         = 0x19
    TCS34725_BDATAL         = 0x1A    # Blue channel data  
    TCS34725_BDATAH         = 0x1B
    
    #Integration Time
    TCS34725_INTEGRATIONTIME_2_4MS  = 0xFF   #<  2.4ms - 1 cycle    - Max Count: 1024
    TCS34725_INTEGRATIONTIME_24MS   = 0xF6   #<  24ms  - 10 cycles  - Max Count: 10240
    TCS34725_INTEGRATIONTIME_50MS   = 0xEB   #<  50ms  - 20 cycles  - Max Count: 20480 
    TCS34725_INTEGRATIONTIME_101MS  = 0xD5   #<  101ms - 42 cycles  - Max Count: 43008
    TCS34725_INTEGRATIONTIME_154MS  = 0xC0   #<  154ms - 64 cycles  - Max Count: 65535
    TCS34725_INTEGRATIONTIME_700MS  = 0x00   #<  700ms - 256 cycles - Max Count: 65535
    
    #Gain
    TCS34725_GAIN_1X                = 0x00   #<  No gain  */
    TCS34725_GAIN_4X                = 0x01   #<  4x gain  */
    TCS34725_GAIN_16X               = 0x02   #<  16x gain */
    TCS34725_GAIN_60X               = 0x03   #<  60x gain */
    
    R = 0
    G = 0
    B = 0
    C = 0
    
    RGB888_R = 0
    RGB888_G = 0
    RGB888_B = 0
    RGB888 = 0
    
    RGB565 = 0

    def __init__(self, address=0x29, debug=False):
        self.i2c = smbus.SMBus(2)
        self.address = address
        self.debug = debug
        #Set GPIO mode
        #GPIO.setwarnings(False)
        #GPIO.setmode(GPIO.BCM)
        #GPIO.setup(LED, GPIO.OUT)
        #self.pwm = GPIO.PWM(18, 1000)
        #self.pwm.start(100)
        #GPIO.setup(INT_PORT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        if (self.debug):
          print("Reseting TSL2581")

    def Write_Byte(self, reg, value):
        "Writes an 8-bit value to the specified register/address"
        reg = reg | self.TCS34725_CMD_BIT;#Register addressing highest bit is set to 1
        self.i2c.write_byte_data(self.address, reg, value)
        if (self.debug):
          print("I2C: Write 0x%02X to register 0x%02X" % (value, reg))
          
    def Write_Word(self, reg, value):
        "Writes an 8-bit value to the specified register/address"
        reg = reg | self.TCS34725_CMD_BIT;
        self.i2c.write_word_data(self.address, reg, value)
        if (self.debug):
          print("I2C: Write 0x%02X to register 0x%02X" % (value, reg))
          
    def Read_Byte(self, reg):
        "Read an unsigned byte from the I2C device"
        reg = reg | self.TCS34725_CMD_BIT;
        result = self.i2c.read_byte_data(self.address, reg)
        if (self.debug):
          print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % (self.address, result & 0xFF, reg))
        return result
        
    def Read_Word(self, reg):
        "Read an unsigned byte from the I2C device"
        reg = reg | self.TCS34725_CMD_BIT;
        result = self.i2c.read_word_data(self.address, reg)
        if (self.debug):
          print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % (self.address, result & 0xFF, reg))
        return result
        
    def Set_Gain(self, gain):
        self.Write_Byte(self.TCS34725_CONTROL, gain);
        self.Gain_t = gain;

    def Set_Integration_Time(self, time):
        # Update the timing register 
        self.Write_Byte(self.TCS34725_ATIME, time)
        self.IntegrationTime_t = time;

    def Enable(self):
        self.Write_Byte(self.TCS34725_ENABLE, self.TCS34725_ENABLE_PON)
        time.sleep(0.01)
        self.Write_Byte(self.TCS34725_ENABLE, self.TCS34725_ENABLE_PON | self.TCS34725_ENABLE_AEN)
        time.sleep(0.01) 

    def Disable(self):
        #Turn the device off to save power 
        reg = Read_Byte(self.TCS34725_ENABLE);
        self.Write_Byte(self.TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN));
     
    def Interrupt_Enable(self):
        reg = self.Read_Byte(self.TCS34725_ENABLE)
        self.Write_Byte(self.TCS34725_ENABLE, reg | self.TCS34725_ENABLE_AIEN)

    def Interrupt_Disable(self):
        reg = self.Read_Byte(self.TCS34725_ENABLE)
        self.Write_Byte(self.TCS34725_ENABLE, reg & (~self.TCS34725_ENABLE_AIEN))

    def Set_Interrupt_Persistence_Reg(self, PER):
        if(PER < 0x10):
            self.Write_Byte(self.TCS34725_PERS, PER)
        else :
            self.Write_Byte(self.TCS34725_PERS, self.TCS34725_PERS_60_CYCLE)

    def Set_Interrupt_Threshold(self, Threshold_H,  Threshold_L):
        self.Write_Byte(self.TCS34725_AILTL, Threshold_L & 0xff)
        self.Write_Byte(self.TCS34725_AILTH, Threshold_L >> 8)
        self.Write_Byte(self.TCS34725_AIHTL, Threshold_H & 0xff)
        self.Write_Byte(self.TCS34725_AIHTH, Threshold_H >> 8)

    def Clear_Interrupt_Flag(self):
        self.Write_Byte(self.TCS34725_CMD_Clear_INT, 0x00);

    def TCS34725_init(self):
        ID = self.Read_Byte(self.TCS34725_ID)
        if(ID != 0x44 and ID != 0x4D):
            return 1
        self.Set_Integration_Time(self.TCS34725_INTEGRATIONTIME_154MS)
        self.Set_Gain(self.TCS34725_GAIN_60X)
        self.IntegrationTime_t = self.TCS34725_INTEGRATIONTIME_154MS
        self.Gain_t = self.TCS34725_GAIN_60X
        self.Enable()
        self.Interrupt_Enable()
        self.SetLight(40)
        return 0


    def GetLux_Interrupt(self, Threshold_H, Threshold_L):
        self.Set_Interrupt_Threshold(Threshold_H, Threshold_L);
     #   if(GPIO.input(INT_PORT) == GPIO.LOW):
      #      self.Clear_Interrupt_Flag();
      #      self.Set_Interrupt_Persistence_Reg(self.TCS34725_PERS_2_CYCLE);
      #      return 1;
        
        return 0;

    def Read_ID(self):
        return self.Read_Byte(self.TCS34725_ID)

    def Get_RGBData(self):
        self.C = self.Read_Word(self.TCS34725_CDATAL | self.TCS34725_CMD_Read_Word)
        self.R = self.Read_Word(self.TCS34725_RDATAL | self.TCS34725_CMD_Read_Word)
        self.G = self.Read_Word(self.TCS34725_GDATAL | self.TCS34725_CMD_Read_Word)
        self.B = self.Read_Word(self.TCS34725_BDATAL | self.TCS34725_CMD_Read_Word)
        time.sleep(0.1) 
        if(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_2_4MS):
            time.sleep(0.01)
        elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_24MS):
            time.sleep(0.04)
        elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_50MS):
            time.sleep(0.05)
        elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_101MS):
            time.sleep(0.1)
        elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_154MS):
            time.sleep(0.2)
        elif(self.IntegrationTime_t == self.TCS34725_INTEGRATIONTIME_700MS):
            time.sleep(0.7)  

    #Convert read data to RGB888 format
    def GetRGB888(self):
        i = 1
        if(self.R >= self.G and self.R >= self.B): 
            i = self.R / 255 + 1
        
        elif( self.G >= self.R and self.G >= self.B):
            i =  self.G / 255 + 1

        elif(  self.B >=  self.G and self.B >= self.R):
            i =  self.B / 255 + 1 

        if(i!=0):
            self.RGB888_R = self.R / i
            self.RGB888_G = self.G / i
            self.RGB888_B = self.B / i

        if(self.RGB888_R > 30):
            self.RGB888_R = self.RGB888_R - 30
        if(self.RGB888_G > 30):
            self.RGB888_G = self.RGB888_G - 30
        if(self.RGB888_B > 30):
            self.RGB888_B = self.RGB888_B - 30
        
        self.RGB888_R = self.RGB888_R * 255 / 225
        self.RGB888_G = self.RGB888_G * 255 / 225
        self.RGB888_B = self.RGB888_B * 255 / 225
        #flyingbean: will fix it later
        #print("RGB888R: %d "%self.RGB888_R), 
        #print("RGB888G: %d "%self.RGB888_G), 
        #print("RGB888B: %d "%self.RGB888_B), 
        #self.RGB888 = (self.RGB888_R<<16) | (self.RGB888_G<<8) |(self.RGB888_B)

    def GetRGB565(self):
        i = 1
        RGB565_R = 0
        RGB565_G = 0
        RGB565_B = 0

        if(self.R >= self.G and self.R >= self.B): 
            i = self.R / 255 + 1
        elif( self.G >= self.R and self.G >= self.B):
            i =  self.G / 255 + 1
        elif(  self.B >=  self.G and self.B >= self.R):
            i =  self.B / 255 + 1 

        if(i!=0):
            RGB565_R = self.R / i
            RGB565_G = self.G / i
            RGB565_B = self.B / i

        if(RGB565_R > 30):
            RGB565_R = RGB565_R - 30
        if(RGB565_G > 30):
            RGB565_G = RGB565_G - 30
        if(RGB565_B > 30):
            RGB565_B = RGB565_B - 30
        
        RGB565_R = RGB565_R * 255 / 225
        RGB565_G = RGB565_G * 255 / 225
        RGB565_B = RGB565_B * 255 / 225 
        self.RGB565_R = RGB565_R  
        self.RGB565_G = RGB565_G  
        self.RGB565_B = RGB565_B  
         #flyingbean: will fix it later
        #print("RGB565 R: %d "%self.RGB565_R) 
        #print("RGB565 G: %d "%self.RGB565_G)
        #print("RGB565 B: %d "%self.RGB565_B)        
        #flyingbean: will fix it later
        #self.RG565 = (((RGB565_R>>3) << 11) | ((RGB565_G>>2) << 5) | (RGB565_B>>3 ))&0xffff

    def Get_Lux(self):
        atime_ms = ((256 - self.IntegrationTime_t) * 2.4);
        if(self.R + self.G + self.B > self.C):
            ir =  (self.R + self.G + self.B - self.C) / 2 
        else:
            ir = 0
        r_comp = self.R - ir;
        g_comp = self.G - ir;
        b_comp = self.B - ir;
        Gain_temp = 1
        if(self.Gain_t == self.TCS34725_GAIN_1X):
            Gain_temp = 1
        elif(self.Gain_t == self.TCS34725_GAIN_4X):
            Gain_temp = 4
        elif(self.Gain_t == self.TCS34725_GAIN_16X):
            Gain_temp = 16
        elif(self.Gain_t == self.TCS34725_GAIN_60X):
            Gain_temp = 60
 
        cpl = (atime_ms * Gain_temp) / (TCS34725_GA * TCS34725_DF);
        lux = (TCS34725_R_Coef * (float)(r_comp) + TCS34725_G_Coef * \
            (float)(g_comp) +  TCS34725_B_Coef * (float)(b_comp)) / cpl;
        return lux;
        
    def Get_ColorTemp(self):
        ir=1.0
        if(self.R + self.G + self.B > self.C):
            ir =  (self.R + self.G + self.B - self.C - 1) / 2 
        else:
            ir = 0
        r_comp = self.R - ir;
        b_comp = self.B - ir;
        cct=TCS34725_CT_Coef * (float)(b_comp) / (float)(r_comp) + TCS34725_CT_Offset;
        return cct;

    def SetLight(self, value):
  #      self.pwm.start(value)
        return 0;

    
 


 

Here is the snapshot of PMOD color sensor up into running on MiniZed under Petalinux 2021.1 build.

PMOD_color_Python3

Figure 10: PMOD Color Sensor Python API Running On MiniZed

      5. MiniZed PMOD Color Sensor Webserver

Flask is a lightweight Python web framework, which is a useful tool for MiniZed platform. Another useful web development tool is Request framework.

For Flask/Request and other Python3 related packages, I configured rootfs package as below:

image

Figure 11: Petalinux RootFS Configuration for Webserver/Flask

How to configure Flask/Request? Ref[5] provides a good demonstration on MiniZed.

Here is the video record on MiniZed UART terminal for Petalinux and webserver API there.

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

The MiniZed WiFi FTP server is presented in Figure 12. You might find the webserver file system on MiniZed at the right side of the figure.

FileZilla_MiniZed_WiFi_FTP

Figure 12:  FileZilla FTP for MiniZed WiFi

Figure 13 presents the snapshot of homepage of the webserver. All the decimal/hex numbers(except Element14) are updated in the real time if I click the button on the same page, which is named as Get New Color. Color illumination and temperature are also measured and plot on the home page too. Color temperature number is much bigger than rest measured sensor data, so I decide to remove it from the bar chart to make the homepage look nicer.

image

Figure 13:  Homepage of  MiniZed Webserver

MiniZed Color Sensor Webserver Demo

After more than a month learning, I cannot remember how many iterations I have done to bring all the building blocks together and finally I am able to present you a working Petalinux project on MiniZed with my homegrown webserver.

Bench Testing Setup

Figure 14: Bench Testing Setup

MiniZed_PMOD

Figure 15: MiniZed PMOD Color Sensor/SWT

MiniZed color sensor webserver with LED dimming control is up into running. The detected color from PMOD sensor will be reproduced as the background color on the webserver. The webcam is able to present the color paper on the same screen of the webserver, so the reader can tell the project is working as expected or not.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

Conclusions

MiniZed is a powerful platform for sensor/IoT applications. The color sensor IoT platform I developed is able to detect color from random color-paper which were left from my previous Cricut projects. The accuracy of the sensor detection is approximately good enough for a demo project. I do need to add calibration features into the project. However, there are several factors that need to be invested before I can implement the calibration algorithm into the Python API. The first factor is the background light. As you can tell, the color detected and presented on the webpage can be different if the background light is changed on the same color paper.  The second factor is the reference color for the calibration. I found that the black/white colors are quite difficult to be defined as the reference color. I need to plan extra work to update the project to be more robust for color detection in the future.

Last also not least, the source codes for the project can be found at my Github:

https://github.com/flyingbean/MiniZed.git

Previous blogs for the training program:

Blog#05: Build MiniZed TTC HW Lab 9 from Scratch

Blog #04: Build a simple User API for Petalinux and Need Support for GPIO UIO API under Petalinux

Blog #03: Build Petalinux for Lab 7 and Boot Petalinux via JTAG

Blog #02: Learning AXI BRAM Controller

Blog #01: Planning MiniZed Avnet TTC Path

References

 

[1] Avnet MiniZed TTC Training Vitis 2021.1

[2] Design and Characterization of Automated Color Sensor System,  by Maher Assaad, Israel Yohannes, Amine Bermak, Dominique Ginhac, Fabrice, Meriaudeau, International Journal on Smart Sensing and Intelligent Systems, 2014

[3] PWM Generator (VHDL), https://forum.digikey.com/t/pwm-generator-vhdl/12652

[4] TCS34725 Color Sensor - Waveshare Wiki

[5] Custom Webserver on the MiniZed by Whitney Knitter, Custom Webserver on the MiniZed - Hackster.io

  • Sign in to reply

Top Comments

  • flyingbean
    flyingbean over 1 year ago in reply to javagoza +1
    Yeah. Petalinux project is really time-consuming. I did appreciate that Element14 did push my Petalinux skill to a different level now.
  • taifur
    taifur over 1 year ago

    Nice presentation.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • DAB
    DAB over 1 year ago

    Very good update.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • flyingbean
    flyingbean over 1 year ago in reply to javagoza

    Yeah. Petalinux project is really time-consuming. I did appreciate that Element14 did push my Petalinux skill to a different level now.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • javagoza
    javagoza over 1 year ago

    Hey flyingbean, great job on wrapping up that Petalinux project! Your hard work has really paid off, and I can tell you're feeling proud of what you've accomplished. Keep up the awesome work!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube