DLPLCRC410EVM: DLP Discovery 4100 Development Platform - Display Anomaly Issue Report

Part Number: DLPLCRC410EVM
Other Parts Discussed in Thread: DLP650LNIR

Tool/software:

Basic Information
Device Model: DLP Discovery 4100 Development Platform (including DLPLCRC410EVM controller board)
DMD Model: DLP650LNIR (program identifies DMDtype=7)
Firmware Version: Attempting to load D4100_GUI_FPGA.bin (file size: 1,569,584 bytes)
Software Environment: Windows 11 system, using custom C++ program (developed based on D4100_usb.dll API)
Problem Description
The program log indicates "Pattern sent to DMD" after execution, but no image is displayed on the physical DMD screen. Specific phenomena are as follows:
The program can recognize the device normally (detects 1 device) and correctly identifies the DMD type as DLP650LNIR (DMDtype=7) during the first run;
The FPGA firmware loading step returns failure (program_FPGA function returns 0), but the test display step log shows "100% progress" and "Pattern sent to DMD";
Physical observation: No image is displayed on the DMD screen (black screen) with no white pattern shown;
Additional phenomenon: During FPGA firmware loading, the D2 indicator on the development board turns red (abnormal loading status).

Operation Steps

Power on the development board and connect it to the computer via USB (corresponding drivers installed);
Run the custom program (code logic based on D4100_usb.dll API), which automatically executes the following processes:
Locate and load D4100_usb.dll;
Locate the D4100_GUI_FPGA.bin firmware file;
Detect devices (returns 1 device);
Read device status (FPGA version=11272739.13, DMDtype=7);
Call program_FPGA function to load firmware (returns 0, failed);
Call LoadData and LoadControl functions to send full-white pattern (log shows success).

Requested Support
Why does the program_FPGA function return 0 (loading failed)? Is it related to firmware version or hardware compatibility?
The log shows "pattern sent successfully" but no actual image is displayed. Could this be related to functional limitations caused by failed FPGA loading?
Provide valid FPGA firmware version and loading guidance for DLP650LNIR to resolve the display anomaly.
Please assist in analyzing the above issues and provide solutions.

Looking forward to your support, THX!

  • // DLP Auto Path Control Program C++
    #pragma comment(linker, "/SUBSYSTEM:CONSOLE")

    #include <windows.h>
    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>

    #pragma comment(lib, "kernel32.lib")

    // Define DLL function pointer types
    typedef short (*GetNumDevFunc)();
    typedef int (*ProgramFPGAFunc)(unsigned char*, long, short);
    typedef unsigned int (*GetFPGARevFunc)(short);
    typedef short (*GetDMDTYPEFunc)(short);
    typedef short (*LoadControlFunc)(short);
    typedef int (*LoadDataFunc)(unsigned char*, unsigned int, short, short);
    typedef short (*ClearFifosFunc)(short);

    void AllocateConsole() {
    if (GetConsoleWindow() == NULL) {
    AllocConsole();
    }
    freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
    freopen_s((FILE**)stderr, "CONOUT$", "w", stderr);
    freopen_s((FILE**)stdin, "CONIN$", "r", stdin);
    SetConsoleTitleA("DLP Auto Path Control Program");
    }

    // Get the directory where the program is located
    std::string GetExecutableDirectory() {
    char exePath[MAX_PATH];
    GetModuleFileNameA(NULL, exePath, MAX_PATH);

    std::string path(exePath);
    size_t lastSlash = path.find_last_of("\\/");
    if (lastSlash != std::string::npos) {
    return path.substr(0, lastSlash);
    }
    return "";
    }

    // Set working directory to the program's directory
    bool SetWorkingDirectoryToExecutable() {
    std::string exeDir = GetExecutableDirectory();
    if (!exeDir.empty()) {
    if (SetCurrentDirectoryA(exeDir.c_str())) {
    std::cout << "Working directory set to: " << exeDir << std::endl;
    return true;
    }
    }
    return false;
    }

    // Check if a file exists
    bool FileExists(const std::string& filePath) {
    DWORD dwAttrib = GetFileAttributesA(filePath.c_str());
    return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
    }

    // Search for a file in multiple possible locations
    std::string FindFile(const std::string& fileName) {
    std::vector<std::string> searchPaths = {
    ".", // Current directory
    ".\\Debug", // Debug subdirectory
    ".\\Release", // Release subdirectory
    "..\\Debug", // Parent directory's Debug
    "..\\Release", // Parent directory's Release
    "..\\..\\" + fileName // Project root directory
    };

    for (const auto& path : searchPaths) {
    std::string fullPath = path + "\\" + fileName;
    if (FileExists(fullPath)) {
    std::cout << "Found file: " << fullPath << std::endl;
    return fullPath;
    }
    }

    // If not found in preset paths, check the file name directly
    if (FileExists(fileName)) {
    return fileName;
    }

    return "";
    }

    class SmartDLPController {
    private:
    HMODULE dllHandle;
    short deviceNumber;
    bool isConnected;
    bool fpgaLoaded;
    std::string dllPath;
    std::string fpgaPath;

    // Function pointers for DLL functions
    GetNumDevFunc GetNumDev;
    ProgramFPGAFunc program_FPGA;
    GetFPGARevFunc GetFPGARev;
    GetDMDTYPEFunc GetDMDTYPE;
    LoadControlFunc LoadControl;
    LoadDataFunc LoadData;
    ClearFifosFunc ClearFifos;

    public:
    SmartDLPController() : dllHandle(nullptr), deviceNumber(0), isConnected(false), fpgaLoaded(false) {
    GetNumDev = nullptr;
    program_FPGA = nullptr;
    GetFPGARev = nullptr;
    GetDMDTYPE = nullptr;
    LoadControl = nullptr;
    LoadData = nullptr;
    ClearFifos = nullptr;
    }

    ~SmartDLPController() {
    if (dllHandle) {
    FreeLibrary(dllHandle);
    }
    }

    bool Initialize() {
    std::cout << "========================================" << std::endl;
    std::cout << " Smart DLP Controller Initialization" << std::endl;
    std::cout << "========================================" << std::endl;

    // Set working directory
    SetWorkingDirectoryToExecutable();

    // Step 1: Search for DLL file
    std::cout << "\n1. Searching for DLL file..." << std::endl;
    dllPath = FindFile("D4100_usb.dll");
    if (dllPath.empty()) {
    std::cerr << "Error: Failed to find D4100_usb.dll" << std::endl;
    return false;
    }

    // Step 2: Search for FPGA firmware file
    std::cout << "\n2. Searching for FPGA firmware file..." << std::endl;
    fpgaPath = FindFile("D4100_GUI_FPGA.bin");
    if (fpgaPath.empty()) {
    std::cout << "Warning: Failed to find D4100_GUI_FPGA.bin" << std::endl;
    std::cout << "Will attempt to run without firmware..." << std::endl;
    }

    // Step 3: Load DLL
    std::cout << "\n3. Loading DLL..." << std::endl;
    dllHandle = LoadLibraryA(dllPath.c_str());
    if (!dllHandle) {
    std::cerr << "DLL loading failed, Error Code: " << GetLastError() << std::endl;
    return false;
    }

    // Get function pointers from DLL
    GetNumDev = (GetNumDevFunc)GetProcAddress(dllHandle, "GetNumDev");
    program_FPGA = (ProgramFPGAFunc)GetProcAddress(dllHandle, "program_FPGA");
    GetFPGARev = (GetFPGARevFunc)GetProcAddress(dllHandle, "GetFPGARev");
    GetDMDTYPE = (GetDMDTYPEFunc)GetProcAddress(dllHandle, "GetDMDTYPE");
    LoadControl = (LoadControlFunc)GetProcAddress(dllHandle, "LoadControl");
    LoadData = (LoadDataFunc)GetProcAddress(dllHandle, "LoadData");
    ClearFifos = (ClearFifosFunc)GetProcAddress(dllHandle, "ClearFifos");

    if (!GetNumDev) {
    std::cerr << "Failed to get critical functions" << std::endl;
    return false;
    }

    std::cout << "[OK] DLL loaded successfully" << std::endl;
    return true;
    }

    bool DetectDevice() {
    std::cout << "\n4. Detecting devices..." << std::endl;
    short numDevices = GetNumDev();
    std::cout << "Number of detected devices: " << numDevices << std::endl;

    if (numDevices > 0) {
    deviceNumber = 0;
    isConnected = true;
    return true;
    }
    return false;
    }

    void ShowCurrentStatus() {
    std::cout << "\n5. Current device status..." << std::endl;

    if (GetFPGARev) {
    unsigned int fpgaRev = GetFPGARev(deviceNumber);
    std::cout << "FPGA firmware version: " << (fpgaRev >> 8) << "." << (fpgaRev & 0xFF) << std::endl;
    }

    if (GetDMDTYPE) {
    short dmdType = GetDMDTYPE(deviceNumber);
    std::cout << "DMD type code: " << dmdType;
    switch (dmdType) {
    case 7:
    std::cout << " (DLP650LNIR - Correctly identified!)";
    break;
    case 15:
    std::cout << " (Unrecognized - FPGA firmware required)";
    break;
    default:
    std::cout << " (Other types)";
    break;
    }
    std::cout << std::endl;
    }
    }

    bool LoadFPGA() {
    if (fpgaPath.empty()) {
    std::cout << "\n6. Skip FPGA loading (firmware file not found)" << std::endl;
    return false;
    }

    if (!program_FPGA) {
    std::cout << "\n6. Skip FPGA loading (program_FPGA function unavailable)" << std::endl;
    return false;
    }

    std::cout << "\n6. Loading FPGA firmware..." << std::endl;
    std::cout << "Firmware file: " << fpgaPath << std::endl;

    std::ifstream file(fpgaPath, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
    std::cerr << "Failed to open firmware file" << std::endl;
    return false;
    }

    std::streamsize fileSize = file.tellg();
    file.seekg(0, std::ios::beg);
    long size = static_cast<long>(fileSize);
    std::vector<unsigned char> buffer(size);

    if (!file.read(reinterpret_cast<char*>(buffer.data()), fileSize)) {
    std::cerr << "Failed to read firmware file" << std::endl;
    return false;
    }
    file.close();

    std::cout << "Starting FPGA programming (" << size << " bytes)..." << std::endl;
    std::cout << "Note: D2 indicator will light up, this is normal" << std::endl;

    int result = program_FPGA(buffer.data(), size, deviceNumber);

    if (result == 1) {
    std::cout << "[OK] FPGA firmware loaded successfully!" << std::endl;
    fpgaLoaded = true;

    std::cout << "Waiting for FPGA configuration to complete..." << std::endl;
    for (int i = 5; i > 0; i--) {
    std::cout << "Countdown: " << i << " seconds\r" << std::flush;
    Sleep(1000);
    }
    std::cout << std::endl;
    return true;
    }
    else {
    std::cerr << "[ERROR] FPGA firmware loading failed, Return Value: " << result << std::endl;
    return false;
    }
    }

    bool TestDisplay() {
    std::cout << "\n7. Testing pattern display..." << std::endl;

    if (!LoadData || !LoadControl) {
    std::cerr << "Display functions unavailable" << std::endl;
    return false;
    }

    // Clear buffer
    if (ClearFifos) {
    ClearFifos(deviceNumber);
    }

    // Create a simple test pattern (full white)
    const int width = 1280;
    const int height = 400;
    const int totalBytes = (width * height) / 8;
    std::vector<unsigned char> pattern(totalBytes, 0xFF); // Full white pattern

    std::cout << "Sending full-white pattern to DMD..." << std::endl;

    // Send data in batches
    const int maxBytesPerLoad = (500 * width) / 8;
    short dmdType = 7;

    for (int offset = 0; offset < totalBytes; offset += maxBytesPerLoad) {
    int bytesToLoad = ((offset + maxBytesPerLoad) > totalBytes) ?
    (totalBytes - offset) : maxBytesPerLoad;

    unsigned char* dataPtr = pattern.data() + offset;
    int result = LoadData(dataPtr, bytesToLoad, dmdType, deviceNumber);

    if (result != 1) {
    std::cerr << "Data loading failed, Offset: " << offset << std::endl;
    return false;
    }

    int progress = ((offset + bytesToLoad) * 100) / totalBytes;
    std::cout << "Progress: " << progress << "%\r" << std::flush;
    }

    std::cout << std::endl;

    // Execute display command
    int controlResult = LoadControl(deviceNumber);
    if (controlResult == 1) {
    std::cout << "[SUCCESS] Pattern sent to DMD!" << std::endl;
    std::cout << "Please check if your DLP device displays the full-white pattern" << std::endl;
    return true;
    }
    else {
    std::cerr << "[ERROR] Display command failed" << std::endl;
    return false;
    }
    }
    };

    int main() {
    AllocateConsole();

    SmartDLPController controller;

    // Initialize controller
    if (!controller.Initialize()) {
    std::cout << "\nPress Enter to exit...";
    std::cin.get();
    return -1;
    }

    // Detect DLP devices
    if (!controller.DetectDevice()) {
    std::cout << "\nPress Enter to exit...";
    std::cin.get();
    return -1;
    }

    // Show current device status
    controller.ShowCurrentStatus();

    // Load FPGA firmware (if possible)
    bool fpgaSuccess = controller.LoadFPGA();

    if (fpgaSuccess) {
    std::cout << "\nVerifying device status after FPGA loading..." << std::endl;
    controller.ShowCurrentStatus();
    }

    // Test pattern display
    controller.TestDisplay();

    std::cout << "\n========================================" << std::endl;
    std::cout << "Program completed!" << std::endl;
    std::cout << "========================================" << std::endl;
    std::cout << "Press Enter to exit...";
    std::cin.get();

    return 0;
    }

  • Pan,

    Do you have the WIndows GUI installed.  If so can you show a screenshot of the About screen from the GUI.

    D2 illuminated red indicates that the APPS_FPGA is not correctly configured.  Please take a picture of your controller board (front) and post it.

    Fizix

  • Dear Fizix,

    I have already installed the Windows GUI and I can use it directly. You are right, after I run the code, D2 illuminated red indicates. Is that the FPGA version problem? How can I fix it?

    Looking forward to your support, THX!

    Pan

  • Hello again Pan,

    I am sorry, I do not understand what you mean by "after I run the code, D2 illuminated red indicates".

    does the board come up with D2 off and D16 green and then D2 comes on when you run the GUI?  Or when you run your C++ code?

    Fizix

  • Dear Fizix,

    Thx for your reply. When the development board is powered on, LED D16 is green and D2 is off. After running the C++ program, an FPGA firmware loading failure is indicated, with D2 turning red and D16 turning off (abnormal condition). When running the GUI, D16 is green and D2 is off (normal condition).

    Pan

  • Hello Pan,

    Your board is working normally.  The latest boards have SPI EEPROMs.  With these EEPROMs you can no longer push in an FPGA load over USB.  

    The SPI EEPROM requires that the FPGA is the clock source for configuration.  The result is that the Cypress USB chip can no longer drive configuration of the FPGA.

    If you are just using the DLL functionality, you should clip out the FPGA load part of your code.

    If you are wanting to change the FPGA code, then you will need to get a Xilinx platform cable.  You should be able to use an aftermarket one.  Use Xilinx Impact tool to push in your bit file.  We have had the best luck with v 14.1 of the Xilinx Lab Tools.  Later versions do not seem to work well with the LX50 and EEPROM.

    Fizix

  • Hello Fizix,

      I have already fixed this problem. THX a lot! All LED is green now after deleting the FPGA part. But now the problem is I set all functions right from D4100_usb.dll, but I cannot see the test pattern on my DMD sceen, you can check a part of my code below, all the feedback is Heavy check mark.

    def display_test_pattern_3(self):
    """Show Test Pattern 3"""
    if not self.dll:
    print("DLL is wrong")
    return False

    try:
    print("DMD is showing Test Pattern 3...")

    # 1. Clear FIFO
    result = self.dll.ClearFifos(self.device_number)
    if not result:
    print("Clear FIFO×")
    return False
    print("✓")

    # 2. Enable internal test pattern generator
    result = self.dll.SetTPGEnable(1, self.device_number)
    if not result:
    print(")
    return False
    print("✓")

    # 3. Enable pattern enforcement mode
    result = self.dll.SetPatternForce(1, self.device_number)
    if not result:
    print(")
    return False
    print("✓")

    # 4. Choose Test Pattern 3 (0x4)
    pattern_value = 0x4 # Test Pattern 3
    result = self.dll.SetPatternSelect(pattern_value, self.device_number)
    if not result:
    print(")
    return False
    print("✓")

    # 5. Load DMD
    result = self.dll.LoadControl(self.device_number)
    if not result:
    print(")
    return False
    print("✓")
           success = dmd.display_test_pattern_3()

    if success:
    print("\n✓ Test Pattern 3 already shown")


    Best Regards
    Pan

  • Thank you for confirming. 

    Regards,

    Tristan Bottone