> For the complete documentation index, see [llms.txt](https://inacks.gitbook.io/inacks-is3720-i2c-dmx+rdm-receiver-ic/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://inacks.gitbook.io/inacks-is3720-i2c-dmx+rdm-receiver-ic/examples/raspberry-pi-example.md).

# Raspberry Pi Example

## Kappa3720: IS3720 Evaluation Board for Raspberry Pi

Visit our product page to place your order: [Kappa3720Ard](https://www.inacks.com/is3750)

<div><figure><img src="https://4031855160-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMR1I6AmpcBW5WamvgJ4O%2Fuploads%2FyyHTyuIxeg3tCerjMLLa%2FINACKS%20Kappa3720Rasp%20RDM%20Responder.jpg?alt=media&amp;token=f6859cf9-d5e1-4c62-b633-de7ea1c0eb06" alt=""><figcaption></figcaption></figure> <figure><img src="https://4031855160-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMR1I6AmpcBW5WamvgJ4O%2Fuploads%2FmXnIy7yep1ZQuppAFONO%2FINACKS%20Kappa3720Rasp%20RDM%20Responder%20Top.jpg?alt=media&amp;token=fbb99bc9-a4ef-4904-9f7e-2b6475e3f471" alt=""><figcaption></figcaption></figure></div>

```python
"""
Raspberry Pi Python port of the IS3720 I2C DMX/RDM interface example.

Dependencies:
    pip install smbus2 RPi.GPIO

Hardware:
    - I2C must be enabled on the RPi (sudo raspi-config → Interface Options → I2C)
    - LED PWM outputs use GPIO pins 12, 13, 19 (BCM) for R, G, B respectively.
      Adjust PIN_RED, PIN_GREEN, PIN_BLUE as needed for your wiring.
"""

import time
import smbus2
import RPi.GPIO as GPIO
from typing import List, Tuple, Optional

# ---------------------------------------------------------------------------
# IS3720 memory map (16-bit addresses)
# ---------------------------------------------------------------------------
IS3720_I2C_SLAVE_ADDRESS = 22
ADDRESS_CHIP_ID           = 513
ADDRESS_DMX_START_ADDRESS = 516
ADDRESS_DMX_FOOTPRINT     = 519
ADDRESS_UID               = 521
ADDRESS_CATEGORY          = 527
ADDRESS_MANUFACTURER_LBL  = 529
ADDRESS_MODEL_NUM         = 561
ADDRESS_MODEL_LBL         = 563
ADDRESS_SOFT_NUM          = 599
ADDRESS_SOFT_LBL          = 599
ADDRESS_RDM_ONLINE        = 631

# ---------------------------------------------------------------------------
# PWM GPIO pins for RGB LED (BCM numbering). Change to match your wiring.
# ---------------------------------------------------------------------------
PIN_RED   = 12
PIN_GREEN = 13
PIN_BLUE  = 19
PWM_FREQ  = 1000  # Hz

# ---------------------------------------------------------------------------
# I2C bus (bus 1 is the default on all modern Raspberry Pi models)
# ---------------------------------------------------------------------------
bus = smbus2.SMBus(1)


# ---------------------------------------------------------------------------
# I2C helpers
# ---------------------------------------------------------------------------

def write_registers(register_address, data):
    # type: (int, List[int]) -> None
    """
    Write one or more bytes to a given IS3720 register address.

    Args:
        register_address: 16-bit register address.
        data:             List of bytes to write.
    """
    high_byte = (register_address >> 8) & 0xFF
    low_byte  =  register_address       & 0xFF
    # smbus2 write_i2c_block_data sends [register_byte, data...]
    # We use the high byte as the "register" argument and prepend the low byte.
    bus.write_i2c_block_data(
        IS3720_I2C_SLAVE_ADDRESS,
        high_byte,
        [low_byte] + list(data)
    )


def read_registers(register_address, length):
    # type: (int, int) -> Tuple[bool, List[int]]
    """
    Read one or more bytes from a given IS3720 register address.

    Args:
        register_address: 16-bit register address.
        length:           Number of bytes to read.

    Returns:
        (error, buffer) — error is True if the read failed, False otherwise.
    """
    high_byte = (register_address >> 8) & 0xFF
    low_byte  =  register_address       & 0xFF
    try:
        # First write the target address (repeated-start / write-then-read).
        write_msg = smbus2.i2c_msg.write(IS3720_I2C_SLAVE_ADDRESS, [high_byte, low_byte])
        read_msg  = smbus2.i2c_msg.read(IS3720_I2C_SLAVE_ADDRESS, length)
        bus.i2c_rdwr(write_msg, read_msg)
        return False, list(read_msg)
    except OSError as exc:
        print("I2C read error: {}".format(exc))
        return True, []


# ---------------------------------------------------------------------------
# Setup
# ---------------------------------------------------------------------------

def setup():
    # type: () -> Tuple
    """Configure the IS3720 and initialise GPIO PWM outputs."""

    # --- GPIO / PWM setup ---------------------------------------------------
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(PIN_RED,   GPIO.OUT)
    GPIO.setup(PIN_GREEN, GPIO.OUT)
    GPIO.setup(PIN_BLUE,  GPIO.OUT)

    pwm_red   = GPIO.PWM(PIN_RED,   PWM_FREQ)
    pwm_green = GPIO.PWM(PIN_GREEN, PWM_FREQ)
    pwm_blue  = GPIO.PWM(PIN_BLUE,  PWM_FREQ)

    pwm_red.start(0)
    pwm_green.start(0)
    pwm_blue.start(0)

    print("Starting!")
    time.sleep(0.1)

    # --- Wait for IS3720 to respond -----------------------------------------
    while True:
        error, data = read_registers(ADDRESS_CHIP_ID, 1)
        if not error and data[0] == 152:
            print("IS3720 detected!")
            time.sleep(1)
            break
        else:
            print("IS3720 NOT detected.")
            time.sleep(0.2)

    # --- Disable RDM before configuration -----------------------------------
    write_registers(ADDRESS_RDM_ONLINE, [0])

    # --- DMX footprint (3 channels: R, G, B) --------------------------------
    write_registers(ADDRESS_DMX_FOOTPRINT, [0x00, 0x03])

    # --- Product category (lighting fixture = 0x0100) -----------------------
    write_registers(ADDRESS_CATEGORY, [0x01, 0x00])

    # --- Manufacturer label -------------------------------------------------
    write_registers(
        ADDRESS_MANUFACTURER_LBL,
        list("UNDERWATER LIGHTS COMPANY\x00".encode("ascii"))
    )

    # --- Model number (0x2000 = 8192 decimal, matches original example) -----
    # NOTE: The original sketch writes to ADDRESS_RDM_ONLINE here — that looks
    # like a copy-paste bug. Writing to ADDRESS_MODEL_NUM instead.
    write_registers(ADDRESS_MODEL_NUM, [0x20, 0x00])

    # --- Model label --------------------------------------------------------
    write_registers(
        ADDRESS_MODEL_LBL,
        list("Pool Light 2000\x00".encode("ascii"))
    )

    # --- Software version number (1.25 → 0x0125) ----------------------------
    write_registers(ADDRESS_SOFT_NUM, [0x01, 0x25])

    # --- Software label -----------------------------------------------------
    write_registers(
        ADDRESS_SOFT_LBL,
        list("Version 1.25\x00".encode("ascii"))
    )

    # --- UID (6 bytes) -------------------------------------------------------
    # NOTE: The original sketch writes to ADDRESS_SOFT_NUM here — that looks
    # like another copy-paste bug. Writing to ADDRESS_UID instead.
    write_registers(ADDRESS_UID, [0x7F, 0xF7, 0x01, 0x02, 0x03, 0x04])

    # --- Enable RDM ---------------------------------------------------------
    write_registers(ADDRESS_RDM_ONLINE, [0x01])

    return pwm_red, pwm_green, pwm_blue


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def analog_write(pwm, value):
    # type: (GPIO.PWM, int) -> None
    """
    Emulate Arduino analogWrite(pin, 0-255) using RPi PWM (0-100 % duty cycle).

    Args:
        pwm:   RPi.GPIO PWM object.
        value: 8-bit value (0–255).
    """
    duty = (1.0 - value / 255.0) * 100.0
    pwm.ChangeDutyCycle(duty)


# ---------------------------------------------------------------------------
# Main loop
# ---------------------------------------------------------------------------

def loop(pwm_red, pwm_green, pwm_blue):
    # type: (GPIO.PWM, GPIO.PWM, GPIO.PWM) -> None
    """Continuously read DMX data from the IS3720 and drive the RGB LEDs."""

    old_dmx_start_address = None

    while True:
        # --- Read DMX start address -----------------------------------------
        error, data = read_registers(ADDRESS_DMX_START_ADDRESS, 2)
        if not error:
            dmx_start_address = (data[0] << 8) | data[1]
            if dmx_start_address != old_dmx_start_address:
                old_dmx_start_address = dmx_start_address
                print("DMX Start Address changed to: {}".format(dmx_start_address))
                time.sleep(2)
        else:
            dmx_start_address = old_dmx_start_address or 1  # Fallback

        # --- Read 3 DMX channels (R, G, B) ----------------------------------
        error, dmx_data = read_registers(dmx_start_address, 3)
        if not error and len(dmx_data) == 3:
            analog_write(pwm_red,   dmx_data[0])
            analog_write(pwm_green, dmx_data[1])
            analog_write(pwm_blue,  dmx_data[2])

            print("\tCH1:\t{}\tCH2:\t{}\tCH3:\t{}".format(dmx_data[0], dmx_data[1], dmx_data[2]))


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    pwm_r, pwm_g, pwm_b = setup()
    try:
        loop(pwm_r, pwm_g, pwm_b)
    except KeyboardInterrupt:
        print("\nStopped by user.")
    finally:
        pwm_r.stop()
        pwm_g.stop()
        pwm_b.stop()
        GPIO.cleanup()
        bus.close()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://inacks.gitbook.io/inacks-is3720-i2c-dmx+rdm-receiver-ic/examples/raspberry-pi-example.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
