834 RGBW Color Processor

834 : RGBW Color Processor

Design render
  • Author: Enrico Sanino
  • Description: Color processor for RGBW LEDs, with generation of hue, tint and intensity based on a color index. Is also a direct SPI to 4 channels PWM converter.
  • GitHub repository
  • Clock: 66000000 Hz

How it works

Color generator for RGBW LEDs, with generation of hue, tint and intensity based on a color index. Is also a direct SPI to 4 PWM channels converter, making it flexible to any different kind of use. The system block diagram is as follow:

block diagram image

It is an SPI slave in Mode 0, with SPI protocol consisting of 8 byte long command, discriminated with a preamble sequence (see Protocol and Test for the description).

This payload is unpacked in different data: red, green, blue, white, bypass mode, intensity, color index. This data is then provided to the color wheel processor. If the bypass mode is activated, the RGBW info from the red, green, blue and white SPI bytes is directly provided as a PWM output in the respective channels.

If bypass mode is not active, only the white, intensity and color index are considered, from which the hue (RGB data) is generated based on the index, then a tint (hue + white) and then the intensity is applied, forming the final color. This is then applied to the PWM outpus to the respective channels.

When bypass mode is not active (color wheel mode), then there is a latency proportional to the "rotation" of the color wheel, i.e. lower the number lower the latency. This is the laterncy of the color wheel processing unit (CwPU), after which the desired complete color is output on the PWM channels.

Debug pins

A debug enable pin, when asserted, will output on the uio pins different internal signals of the CwPU while in operation. This is just to check the internal signals in case the tapeout goes wrong, and for curiosity purposes for fidelity against the gate level simulation.

PWM modulator

The PWM modulator has a period of t_pwm = t_clk_presc * 256, and a resolution of 1/256 steps. The t_clk_presc is the prescaled clock, t_clk_presc = t_clk * 2. Each update is synchronous to the period, hence any change in the duty cycle will happens to the next PWM period without generating artifacts.

Clock and reset maanger

The clock and reset manager will issue a precaled clock to the whole system by a factor of 2, except for the multiplicator, which has to run twice as fast w.r.t. the system. A toggle on the reset pin will reset the whole system at the next reset release. Meaning, to reset the system, the reset (active low) must go to LOW, then it must be deasserted to HIGH. By doing this, the clock must be always present (sync reset).

When reset is deasserted (HIGH), the manager will start and will keep the rest of the system in reset state for the next 128 t_clk cycles (main clock from the pin). This will guarantee that the whole system will be correctly initialized.

Therefore any SPI transaction can take place after at least 128 clock cycles after reset condition is deasserted, otherwise one SPI packed would be lost.

Color wheel processor

The logic datapath of the CwPU is shown below:

SCwPU datapath

The CwPU has all the data width of 8 bit, and the energy intensive color discrimination path is active when non in bypass mode only. When active will take the index. Starting from zero, increments the hue progression and compares against this index (i.e. rotates the color wheel) to process at run time with no LUT, the corresponding requested hue. During the rotation, the RGB internal values will also change, increasing and decreasing the hue components to sweep all the combinations to match the requested one. The final value will be used for the next step, which is the tint.

The next step is the sum of the white component, generating a tint, a white adjusted color. It will sum the white up to the maximum value, and the value is output to the intensity multiplier. Also the white is output to the multiplier. This is to not only output an RGB to emualate the white, but to increase the color rendering index (CRI) by allowing to use a single output that can be connected to a pure white generator/phosphor based white LED.

The multiplication for the intensity then takes place with a single multiplicator unit, hence the local control takes care of the data load and synchonization, with 2 clock cycles per operation. Since the multiplicator goes twice as fast, the CwPU has not additional wait states, resulting in 1 CwPU clock cycle delay. Also the white is multiplied. After this step, the output data of each component (R, G, B and W) are 16bit, but the 8 LSB are truncated, generating a final 24 bit color information and 8 bit white.

This data is used by the 4 channel PWM modulator.

When in bypass mode, the CwPU will only replicate the same RGBW info in input to the PWM modulator input in one clock cycle.

SPI protocol

SPI is Mode 0 as shown in this timing diagram, highlighting the preable and first byte transfer:

SPI transaction image, bit detail

While a whole packet must be compliant with the following diagram:

SPI transaction image, whole packet structure

Which contains:

  1. preamble: 0x55
  2. intensity: 0x00 - 0xFF
  3. color index: 0x00 - 0xFF
  4. red: 0x00 - 0xFF
  5. green: 0x00 - 0xFF
  6. blue: 0x00 - 0xFF
  7. white: 0x00 - 0xFF
  8. bypass mode: 0xA4 for the color generation, 0x21 bypass

Note that in between each byte is mandatory to toggle the CS signal, since in reality a full transaction is interpreted as a 8 individual single byte transactions. Therefore, if the bus gets corrupted, sending any data without preamble with more than 8 bytes, will ensure a clean bus state ready to be synchronized again. Otherwise a reset is an alternative.

How to test

This is normally tested with a micropython script to be interpreted directly from the REPL interface of the TT08 demoboard (see https://tinytapeout.com/guides/get-started-demoboard/). To test the design simply setup the demoboard, and run the script in the test folder. It means it can be simply copy/pasted into the REPL terminal.

To see an output, is suggested to wire some LEDs to the output of the demoboard being careful to not overload the output pins. If you don't know what you are doing, then is better to get like 4x of these for the 4 LEDs tindie.com/products/aleadesigns or any other LED controller that won't load more than 4mA on the TT08 chip output pads (see pad spec here).

A custom PMOD will come soon to ease the LED test.

With the RP2040 no input wiring is needed, and the output will be:

uo_out[0] -> Red LED

uo_out[1] -> Green LED

uo_out[2] -> BLue LED

uo_out[3] -> White LED

What to expect on the outputs

Given the HUE ternary (r,g,b) processed from the index by the CwPU, the final color is RGBW = ((r,g,b)+w)intensity, having a PWM signal per each color channel.

So the white and intensity have a direct impact regardless the hue generated.

The output "color equation" with bypass is RGBW = spi(red, green, blue, white) with NO intensity, NO automatic white. In this mode, the data provided via SPI is the data taken by the PWM modulator as is.

External hardware

While we're working at a PMOD right now, the external hardware are 4 LEDs, one per each color, connected to the outputs. Be aware that the outputs cannot take more than 4mA!!! So a dedicated circuit is needed (but will be provided soon). Stay tuned.

To control the design, no external controller is needed since it uses the internal RP2040 of the demoboard, see the documentation here of the test and the REPL script here. Alternatively, a custom firmware and another dedicated python script is provided with the relative STM32 based project, briefly documented here.

IO

#InputOutputBidirectional
0red_pwmtest_out_0
1green_pwmtest_out_1
2blue_pwmtest_out_2
3test_pinwhite_pwmtest_out_3
4cs_ntest_out_4
5scktest_out_5
6mositest_out_6
7clk_div_entest_out_7

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (TinyTapeout 8 Factory Test) tt_um_oscillating_bones (Oscillating Bones) tt_um_urish_charge_pump (Dickson Charge Pump) tt_um_bgr_agolmanesh (Bandgap Reference) tt_um_tnt_diff_rx (TT08 Differential Receiver test) tt_um_rejunity_vga_logo (VGA Tiny Logo (1 tile)) tt_um_tommythorn_maxbw (Asynchronous Multiplier) tt_um_mattvenn_r2r_dac_3v3 (Analog 8 bit 3.3v R2R DAC) tt_um_urish_simon (Simon Says memory game) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_mattvenn_rgb_mixer (RGB Mixer demo5) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_find_the_damn_issue (Find The Damn Issue) tt_um_brandonramos_VGA_Pong_with_NES_Controllers (VGA Pong with NES Controllers) tt_um_kb2ghz_xalu (4-bit minicomputer ALU) tt_um_rebeccargb_intercal_alu (INTERCAL ALU) tt_um_a1k0n_demo (Demo by a1k0n) tt_um_rburt16_bias_generator (Bias Generator) tt_um_zec_square1 ("SQUARE-1": VGA/audio demo) tt_um_jmack2201 (Sprite Bouncer with Looping Background Options) tt_um_ran_DanielZhu (Dice) tt_um_gfg_development_tinymandelbrot (TinyMandelbrot) tt_um_LnL_SoC (Lab and Lectures SoC) tt_um_htfab_pi_snake (Pi Snake) tt_um_tt08_aicd_playground (AICD Playground) tt_um_toivoh_demo (Sequential Shadows [TT08 demo competition]) tt_um_quarren42_demoscene_top (asic design is my passion) tt_um_crispy_vga (Crispy VGA) tt_um_MichaelBell_canon (TT08 Pachelbel's Canon demo) tt_um_shuangyu_top (Calculator) tt_um_wokwi_407306064811090945 (DDR throughput and flop aperature test) tt_um_08_sws (Sine Wave Synthesizer) tt_um_favoritohjs_scroller (VGA Scroller) tt_um_tt08_wirecube (Wirecube) tt_um_vga_glyph_mode (Glyph Mode) tt_um_a1k0n_vgadonut (VGA donut) tt_um_roy1707018 (RO) tt_um_analog_factory_test (TT08 Analog Factory Test) tt_um_sign_addsub (CMOS design of 4-bit Signed Adder Subtractor) tt_um_tinytapeout_logo_screensaver (VGA Screensaver with Tiny Tapeout Logo) tt_um_patater_demokit (Patater Demo Kit Waggling Rainbow on a Chip) tt_um_algofoogle_tt08_vga_fun (TT08 VGA FUN!) tt_um_simon_cipher (simon_cipher) tt_um_thexeno_rgbw_controller (Color Controller) tt_um_demosiine_sda (DemoSiine) tt_um_bytex64_munch (Munch) tt_um_alexjaeger_ringoscillator (5MHz Ring Oscillator) tt_um_cfib_demo (cfib Demoscene Entry) tt_um_wokwi_407852791999030273 (Simple 8 Bit ALU) tt_um_Richard28277 (4-bit ALU) tt_um_betz_morse_keyer (Morse Code Keyer) tt_um_nvious_graphics (nVious Graphics) tt_um_tiny_pll (Tiny PLL) tt_um_ezchips_calc (8-Bit Calculator) tt_um_hack_cpu (HACK CPU) tt_um_noritsuna_Vctrl_LC_oscillator (Voltage Controlled LC-Oscillator) tt_um_ring_divider (Divided Ring Oscillator) tt_um_2048_vga_game (2048 sliding tile puzzle game (VGA)) tt_um_morningjava_r2r_from_matt (Bucket Brigade) tt_um_ephrenm_tsal (TSAL_TT) tt_um_kapilan_alarm (Alarm Clock) tt_um_stochastic_addmultiply_CL123abc (Stochastic Multiplier, Adder and Self-Multiplier) tt_um_wokwi_407760296956596225 (tt08-octal-alu) tt_um_dlfloatmac (DL float MAC) tt_um_wakki_0123_Raw_Transistors (Raw_Transistors) tt_um_faramire_rotary_ring_wrapper (Rotary Encoder WS2812B Control) tt_um_devstdin_LDO_OSC (LDO BG IREF OSC) tt_um_frequency_counter (Frequency Counter SSD1306 OLED) tt_um_rom_test (TT08 SKY130 ROM 'YOLO' Test) tt_um_i2c_peripheral_stevej (i2c peripherals: leading zero count and fnv-1a hash) tt_um_yuri_panchul_schoolriscv_cpu_with_fibonacci_program (schoolRISCV CPU with Fibonacci program) tt_um_yuri_panchul_adder_with_flow_control (Adder with Flow Control) tt_um_brailliance (Brailliance) tt_um_nyan (nyan) tt_um_MichaelBell_mandelbrot (VGA Mandelbrot) tt_um_ssp_opamp (2-stage Opamp Designs) tt_um_fountaincoder_top_ad (pulse_add) tt_um_edwintorok (Rounding error) tt_um_mac (MAC) tt_um_dpmu (DPMU) tt_um_JAC_EE_segdecode (7 Segment Decode) tt_um_wokwi_408118380088342529 (Traffic-light-sequence) tt_um_shiftreg_test (TT08 SKY130 Shift Register 'YOLO' Test) tt_um_yuri_panchul_sea_battle_vga_game (Sea Battle) tt_um_benpayne_ps2_decoder (PS2 Decoder) tt_um_meriac_play_tune (Super Mario Tune on A Piezo Speaker) tt_um_comm_ic_bhavuk (Comm_IC) tt_um_daosvik_aesinvsbox (AES Inverse S-box) tt_um_wokwi_408216451206371329 (Logic Test) tt_um_micro_tiles_container (Micro tile container) tt_um_cattuto_sr_latch (TT08 - experiments with latch-based shift registers) tt_um_rejunity_vga_test01 (VGA Drop (audio/visual demo)) tt_um_silice (Warp) tt_um_wokwi_408231820749720577 (Abacus Lock) tt_um_jayjaywong12 (mulmul) tt_um_emmyxu_obstacle_detection (Obstacle Detection) tt_um_neural_navigators (Neural Net ASIC) tt_um_a1k0n_nyancat (VGA Nyan Cat) tt_um_rebeccargb_styler (Styler) tt_um_resfuzzy (resfuzzy) tt_um_cejmu (CEJMU Beers and Adders) tt_um_16_mic_beamformer_arghunter (16 Mic Beamformer) tt_um_pdm_pitch_filter_arghunter (PDM Pitch Filter) tt_um_pdm_correlator_arghunter (PDM Correlator) tt_um_ddc_arghunter (DDC) tt_um_i2s_to_pwm_arghunter (I2S to PWM ) tt_um_georgboecherer_vco (Analog Voltage Controlled Oscillator) tt_um_supermic_arghunter (Supermic ) tt_um_dmtd_arghunter (DMTD ) tt_um_htfab_bouncy_capsule (Bouncy Capsule) tt_um_samuelm_pwm_generator (PWM generator) tt_um_mattvenn_analog_ring_osc (Ring Oscillators) tt_um_toivoh_demo_deluxe (Sequential Shadows Deluxe [TT08 demo competition]) tt_um_vga_clock (VGA clock) tt_um_z2a_rgb_mixer (RGB Mixer demo) tt_um_faramire_stopwatch (Simple Stopwatch) tt_um_micro_tiles_container_group2 (Micro tile container (group 2)) tt_um_johshoff_metaballs (Metaballs) tt_um_top (Flame demo) tt_um_NicklausThompson_SkyKing (SkyKing Demo) tt_um_Electom_cla_4bits (4-bit CLA) tt_um_vga_cbtest (Generate VGA output for Color Blindness Test) tt_um_zoom_zoom (Zoom Zoom) tt_um_dpmunit (DPM_Unit) tt_um_clock_divider_arghunter (Clock Divider ) tt_um_dlmiles_poc_fskmodem_hdlctrx (FSK Modem +HDLC +UART (PoC)) tt_um_emilian_muxpga (TinyFPGA resubmit for TT08) tt_um_pyamnihc_dummy_counter (Dummy Counter) tt_um_whynot (Why not?) tt_um_sudana_ota5t_1 (5-T OTA) tt_um_dlmiles_tt08_poc_uart (UART) tt_um_dendraws_donut (donut) tt_um_wokwi_408237988946759681 (Counter) tt_um_tmkong_rgb_mixer (RGB Mixer) Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available