This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:iot-open:practical:hardware:sut:stm32:emb9b_1 [2024/03/03 08:23] – [Prerequisites] ktokarz | en:iot-open:practical:hardware:sut:stm32:emb9b_1 [2024/05/02 12:02] (current) – created ktokarz | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== | + | ====== |
| - | This scenario presents how to handle | + | A colour sensor (TCS 34725) can detect |
| ===== Prerequisites ===== | ===== Prerequisites ===== | ||
| - | A good understanding of the PWM signal and duty cycle is necessary. We also use built-in timers | + | To implement this scenario, it is necessary to get familiar with at least one of the following scenarios first: |
| + | * [[en: | ||
| + | * [[en: | ||
| + | * [[en: | ||
| + | and obligatory: | ||
| + | * [[en: | ||
| + | To simplify TCS sensor use, we will use a dedicated library: | ||
| + | <code bash> | ||
| + | lib_deps = adafruit/ | ||
| + | </ | ||
| + | <note important> | ||
| ===== Suggested Readings and Knowledge Resources ===== | ===== Suggested Readings and Knowledge Resources ===== | ||
| * [[en: | * [[en: | ||
| - | * [[en: | + | * [[en: |
| - | * [[en: | + | |
| * [[en: | * [[en: | ||
| - | * [[en: | + | * [[en: |
| + | * [[en: | ||
| + | * [[https:// | ||
| ===== Hands-on Lab Scenario ===== | ===== Hands-on Lab Scenario ===== | ||
| ==== Task to be implemented ==== | ==== Task to be implemented ==== | ||
| - | Implement | + | Create |
| + | |||
| + | <note tip> | ||
| + | * simple: a dummy loop where you set RGB LED values, read from TCS and display on LCD, | ||
| + | * advanced: where the data is read and presented on the LCD in one or two asynchronous routines run by timers. | ||
| + | </ | ||
| ==== Start ==== | ==== Start ==== | ||
| - | The hardware timer library implements functions which allow us to control | + | Check if you can see the LCD and RGB LED in the camera view. |
| - | As the PWM duty cycle is expressed in percentages, | + | <note important> |
| ==== Steps ==== | ==== Steps ==== | ||
| - | To use PWM in STM32WB55, it is best to use a built-in hardware timer library. | + | In the steps below, we present only the part for reading from the TCS sensor. Control of RGB LED with PWM and handling LCD is presented |
| - | < | + | |
| - | #include < | + | |
| - | </ | + | |
| - | The hardware timer uses internal timer modules and allows us to define channels attached to the timer. We will use 1 channel per colour (R, G and B, so 3 in total). A PWM frequency is controlled with the timer to be shared for all 3 R, G and B channels. Channels control | + | |
| === Step 1 === | === Step 1 === | ||
| - | Include the library, and define PIN assignments to channels and PWM frequency (100Hz): | + | Included necessary libraries: |
| <code c> | <code c> | ||
| - | #include <HardwareTimer.h> | + | #include <Wire.h> |
| - | + | #include " | |
| - | // Pins definition for RGB LED | + | |
| - | #define LED_PWM_GREEN D3 //Arduino numbering D3, STM numbering PA_10 | + | |
| - | #define LED_PWM_BLUE | + | |
| - | #define LED_PWM_RED | + | |
| - | + | ||
| - | #define PWM_freq 100 | + | |
| </ | </ | ||
| - | GPIO pins controlling | ||
| === Step 2 === | === Step 2 === | ||
| - | Define | + | Declare and instantiate TCS controller class and related |
| <code c> | <code c> | ||
| - | // PWM variables definitions | + | static Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_300MS, |
| - | HardwareTimer *MyTimLED; //Hardware Timer for PWM | + | uint16_t r, g, b, c, colorTemp, lux; |
| - | uint32_t channelR, channelG, channelB; //RGB channels | + | static bool isTCSOk = false; |
| </ | </ | ||
| + | A word of explanation regarding the parameters: | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Refer to the Q&A section for the ranges. | ||
| - | Instantiate the timer object and initialise the 3 channels for PWM and make them dark (1% duty cycle): | + | === Step 3 === |
| + | Initialise the sensor (in '' | ||
| <code c> | <code c> | ||
| - | //Create Timer instance type based on the chosen LED pin (the same timer is used for all LEDs). | + | isTCSOk = tcs.begin(); |
| - | TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(LED_PWM_RED), | + | </code> |
| - | + | You communicate with the TCS sensor via the I2C interface. In standard and typical configurations there is no need to instantiate the '' | |
| - | //Define three separate channels for LEDs | + | |
| - | channelR = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(LED_PWM_RED), PinMap_PWM)); | + | |
| - | channelG = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(LED_PWM_GREEN), PinMap_PWM)); | + | |
| - | channelB = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(LED_PWM_BLUE), | + | |
| - | // Instantiate HardwareTimer object. Thanks to 'new' | + | === Step 4 === |
| - | MyTimLED = new HardwareTimer(Instance); | + | Besides reading raw values for channels R, G, B and C, the '' |
| - | // Configure and start PWM | + | To read, use the following code: |
| - | MyTimLED->setPWM(channelR,LED_PWM_RED,PWM_freq,1); /* 100 Hertz, 1% dutycycle. */ | + | <code c> |
| - | MyTimLED-> | + | if(isTCSOk) |
| - | MyTimLED-> | + | { |
| + | tcs.getRawData(&r, &g, &b, &c); | ||
| + | | ||
| + | lux = tcs.calculateLux(r, g, b); | ||
| + | } | ||
| </ | </ | ||
| + | R, G, and B reflect filtered values for Red, Green and Blue, respectively, | ||
| - | To modify the intensity of the chosen | + | ==== Result validation ==== |
| + | Driving R, G and B channels for RGB LED that lights | ||
| + | |||
| + | ===== FAQ ===== | ||
| + | **What is the range of the values for the integration time of the TCS sensor?**: | ||
| <code c> | <code c> | ||
| - | MyTimLED-> | + | #define TCS34725_INTEGRATIONTIME_2_4MS |
| + | (0xFF) /**< 2.4ms - 1 cycle - Max Count: 1024 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_24MS | ||
| + | | ||
| + | #define TCS34725_INTEGRATIONTIME_50MS | ||
| + | (0xEB) /**< 50.4ms - 21 cycles - Max Count: 21504 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_60MS | ||
| + | (0xE7) /**< 60.0ms - 25 cycles - Max Count: 25700 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_101MS | ||
| + | (0xD6) /**< 100.8ms - 42 cycles - Max Count: 43008 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_120MS | ||
| + | (0xCE) /**< 120.0ms - 50 cycles - Max Count: 51200 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_154MS | ||
| + | (0xC0) /**< 153.6ms - 64 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_180MS | ||
| + | (0xB5) /**< 180.0ms - 75 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_199MS | ||
| + | (0xAD) /**< 199.2ms - 83 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_240MS | ||
| + | (0x9C) /**< 240.0ms - 100 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_300MS | ||
| + | (0x83) /**< 300.0ms - 125 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_360MS | ||
| + | (0x6A) /**< 360.0ms - 150 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_401MS | ||
| + | (0x59) /**< 400.8ms - 167 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_420MS | ||
| + | (0x51) /**< 420.0ms - 175 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_480MS | ||
| + | (0x38) /**< 480.0ms - 200 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_499MS | ||
| + | (0x30) /**< 499.2ms - 208 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_540MS | ||
| + | (0x1F) /**< 540.0ms - 225 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_600MS | ||
| + | (0x06) /**< 600.0ms - 250 cycles - Max Count: 65535 */ | ||
| + | #define TCS34725_INTEGRATIONTIME_614MS | ||
| + | (0x00) /**< 614.4ms - 256 cycles - Max Count: 65535 */ | ||
| </ | </ | ||
| - | === Step 3 === | + | **What is the range of the values |
| - | Write a loop for each colour (R, G, then B) to light the colour from dark to max value. | + | |
| - | <note important> | + | |
| - | Mind to compose code to increase and decrease each colour. A hint is below (for channelR): | + | |
| <code c> | <code c> | ||
| - | // Increase brightness | + | typedef enum { |
| - | | + | |
| - | | + | |
| - | | + | |
| - | delay(20); | + | |
| - | } | + | } tcs34725Gain_t; |
| - | + | ||
| - | delay(100); | + | |
| - | + | ||
| - | // Decrease brightness | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | delay(20); // Delay for smooth transition | + | |
| - | } | + | |
| </ | </ | ||
| - | ==== Result validation ==== | ||
| - | You should be able to observe the pulsing colours of the RGB LED, increasing and decreasing brightness linearly. | ||
| - | ===== FAQ ===== | + | **C channel reading |
| - | **What is the maximum number of channels?**: the MCU we use here is STM32WB55 on the Nucleo board. The pins available are connected to timer 1 with three PWM channels | + | |
| - | \\ | + | |
| - | **What is the maximum bit resolution for PWM?**: Maximum resolution is 16 bits. Note that we can express the duty cycle in a variety of formats. In the presented example we expressed it in percentage so it varies between 1 and 100. It can be also expressed in ticks, Hertz, microseconds, | + | |
| - | \\ | + | |
| - | **What PWM frequency should I use?**: there is no straightforward answer to this question: assuming you observe LED remotely with a camera, even 50Hz would be enough. But it would give a severe flickering experience to the live user, on the other hand. In the example above, we propose 100Hz, but this MCU can easily handle higher frequencies. | + | |
| + | <WRAP noprint> | ||
| ===== Project information ===== | ===== Project information ===== | ||
| {{: | {{: | ||
| Line 120: | Line 155: | ||
| {{: | {{: | ||
| </ | </ | ||
| - | + | </ | |
| - | + | ||