This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28379D: CLB Counter Event Load Register is Overwritten by the HLC

Part Number: TMS320F28379D


Greetings,

In our CLB implementation, a counter, C0, is used to generate pulses via the zero, match1, and match2 outputs.  At the beginning of the transaction there is a rising edge at the EVENT input which causes the counter to load the LOAD VALUE into C0.  Later in the transaction, the HLC is used to load R2 into C0.  This is the only instruction for the  HLC event, and no other HLC events are being used.

The first transaction works perfectly.  But when the second transaction begins and the EVENT signal is generated, instead of the LOAD VALUE appearing in the counter, the R2 value is loaded instead.  I can find nothing in the TRM which suggests that this will happen.  Is this the expected behavior, or did I overlook something in the literature?

In debugging this, I also noted that a write to the LOAD VALUE register also results in the value being written to C0, without needing an event.  Is this expected too?

Thank you,

Ed

  • Ed,

    So to summarize:

    1. COUNTER mode = LOAD

    2. COUNTER EVENT signal is connected to?

    Updating the LOAD_val should not automatically update the COUNTER C0 register. only on an EVENT or an HLC triggered instruction should the C0 be updated. What is the EVENT signal?

  • Nima,

    1. Yes

    2.  The CLB_GP_REG.  So the 28x controls the event input of the counter.

    I expected this answer, so I created a small project, which uses none of our IP, but demonstrates the issue.  I could zip it up and send it to you if you like.  If so, please tell me how to attach it.

    Thanks,

    Ed

  • Yes just send me your C file and your syscfg file. I will import them into an example project on my side!

    Is your EVENT signal high when you write to the COUNTE Cx?

  • The project has several files including the syscfg file.  I have zipped them up, but I can't find a way to attach the file.  It seems to want an image or video file.

    In the attached project, the EVENT signal is toggled high and low.  In our IP, the signal will go high for a prolonged period of time and then go low.  But in neither case is LOAD_VAL written during the EVENT signal’s high time.  Does a high value on EVENT cause a different behavior when LOAD_VAL is written?

    Thank you,

    Ed

  • OK.  I’ve combined the files into a single C file which includes the clb_config.h output from the build of the syscfg file, and copied it and the syscfg files below.  Hope you can see these.  If you put the C0_x variables in order in the Expressions window, you can see the evolution of the C0 value under the various stimuli.

    Ed

    ///////////////////////////////////////////////////////////
    //
    // HLC Overwrites Event Load Value
    //
    ///////////////////////////////////////////////////////////
    
    #include "clb_config.h"
    
    /////////////////////////////////////////
    // Data types for this experiment.
    typedef unsigned int            uint16;
    typedef int                     int16;
    
    typedef unsigned long           uint32;
    typedef long                    int32;
    /////////////////////////////////////////
    
    
    
    /////////////////////////////////////////
    // Access control
    #define  EALLOW   __asm(" EALLOW")
    #define  EDIS     __asm(" EDIS")
    /////////////////////////////////////////
    
    
    
    /////////////////////////////////////////
    // Clock Setup
    //
    // Prototypes for the Clock Setup
    void Setup_Clocks();
    //
    /////////////////////////////////////////
    
    
    
    
    
    /////////////////////////////////////////
    // CLB Access
    
    // Board input values
    #define BOUNDARY_INPUT_0    0x01
    #define BOUNDARY_INPUT_1    0x02
    #define BOUNDARY_INPUT_2    0x04
    #define BOUNDARY_INPUT_3    0x08
    #define BOUNDARY_INPUT_4    0x10
    #define BOUNDARY_INPUT_5    0x20
    #define BOUNDARY_INPUT_6    0x40
    #define BOUNDARY_INPUT_7    0x80
    
    // Translate the generic boundary inputs into their respective signals.
    #define COUNTER0_RESET  BOUNDARY_INPUT_0
    #define COUNTER0_EVENT  BOUNDARY_INPUT_1
    #define HLC_EV0_EVENT   BOUNDARY_INPUT_2
    
    
    // Logic Config Registers
    #define CLB4_LOGIC_CFG_REGS 0x3C00
    #define CLB_COUNT_RESET     0x02
    #define CLB_COUNT_MODE_1    0x04
    #define CLB_COUNT_MODE_0    0x06
    #define CLB_COUNT_EVENT     0x08
    #define CLB_MISC_CONTROL    0x2A
    #define CLB_HLC_EVENT_SEL   0x3C
    
    // Logic Control Registers
    #define CLB4_LOGIC_CTL_REGS 0x3D00
    #define CLB_LOAD_EN         0x00
    #define CLB_LOAD_ADDR       0x02
    #define CLB_LOAD_DATA       0x04
    #define CLB_IN_MUX_SEL_0    0x08
    #define CLB_GP_REG          0x10
    #define CLB_DBG_C0          0x38
    
    // CLB_LOAD_EN data fields
    #define LOAD_EN             1
    #define GLOBAL_EN           2
    
    // Register values for CLB_IN_MUX_SEL_0
    #define SEL_GP_IN_0         0x01
    #define SEL_GP_IN_1         0x02
    #define SEL_GP_IN_2         0x04
    #define SEL_GP_IN_3         0x08
    #define SEL_GP_IN_4         0x10
    #define SEL_GP_IN_5         0x20
    #define SEL_GP_IN_6         0x40
    #define SEL_GP_IN_7         0x80
    
    // Indirect Registers
    #define COUNTER0_LOAD_VAL_ADDR      0x0000
    #define COUNTER1_LOAD_VAL_ADDR      0x0001
    #define COUNTER2_LOAD_VAL_ADDR      0x0002
    #define COUNTER0_MATCH1_ADDR        0x0004
    #define COUNTER1_MATCH1_ADDR        0x0005
    #define COUNTER2_MATCH1_ADDR        0x0006
    #define COUNTER0_MATCH2_ADDR        0x0008
    #define COUNTER1_MATCH2_ADDR        0x0009
    #define COUNTER2_MATCH2_ADDR        0x000A
    #define R0_ADDR                     0x000C
    #define R1_ADDR                     0x000D
    #define R2_ADDR                     0x000E
    #define R3_ADDR                     0x000F
    #define INSTRUCTIONS_EVENT0_ADDR    0x0020
    
    // Instructions for all the HLCs.
    #define HLC_INSTRUCTIONS_PER_TILE   32
    uint32 HlcInstructions[HLC_INSTRUCTIONS_PER_TILE] =
    {
        Tile4_HLCINSTR_0,
        Tile4_HLCINSTR_1,
        Tile4_HLCINSTR_2,
        Tile4_HLCINSTR_3,
        Tile4_HLCINSTR_4,
        Tile4_HLCINSTR_5,
        Tile4_HLCINSTR_6,
        Tile4_HLCINSTR_7,
        Tile4_HLCINSTR_8,
        Tile4_HLCINSTR_9,
        Tile4_HLCINSTR_10,
        Tile4_HLCINSTR_11,
        Tile4_HLCINSTR_12,
        Tile4_HLCINSTR_13,
        Tile4_HLCINSTR_14,
        Tile4_HLCINSTR_15,
        Tile4_HLCINSTR_16,
        Tile4_HLCINSTR_17,
        Tile4_HLCINSTR_18,
        Tile4_HLCINSTR_19,
        Tile4_HLCINSTR_20,
        Tile4_HLCINSTR_21,
        Tile4_HLCINSTR_22,
        Tile4_HLCINSTR_23,
        Tile4_HLCINSTR_24,
        Tile4_HLCINSTR_25,
        Tile4_HLCINSTR_26,
        Tile4_HLCINSTR_27,
        Tile4_HLCINSTR_28,
        Tile4_HLCINSTR_29,
        Tile4_HLCINSTR_30,
        Tile4_HLCINSTR_31
    };
    
    
    // Prototypes Public
    void     Setup_CLB();
    void     Toggle_Input(uint16 boundary_input);
    uint32   Get_C0();
    
    // Prototypes Private
    void     Write_IndirectRegister(uint32 address, uint32 data);
    void     Setup_Counters();
    void     Setup_HLC();
    void     Disable_CLB();
    void     Enable_CLB();
    
    //
    /////////////////////////////////////////
    
    
    // Variables to capture the state of C0 at various points in the process.
    uint32 C0_0_BeforeFirstCounterReset = 0;
    uint32 C0_1_AfterFirstCounterReset = 0;
    uint32 C0_2_BeforeFirstCounterEvent = 0;
    uint32 C0_3_AfterFirstCounterEvent = 0;
    uint32 C0_4_BeforeHlcEvent = 0;
    uint32 C0_5_AfterHlcEvent = 0;
    uint32 C0_6_BeforeSecondCounterReset = 0;
    uint32 C0_7_AfterSecondCounterReset = 0;
    uint32 C0_8_BeforeSecondCounterEvent = 0;
    uint32 C0_9_AfterSecondCounterEvent = 0;
    
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // The test consists of the following steps each of which is preceded and followed by a capture
    // of the state of the counter register (C0).
    //
    //          Action          Result                                           Conclusion
    //          ---------------------------------------------------------------------------
    //          Counter Reset - Clears C0                                      - Pass
    //          Counter Event - Puts the LOAD VALUE into C0                    - Pass
    //          HLC Event     - Loads R2 into C0                               - Pass
    //          Counter Reset - Clears C0                                      - Pass
    //          Counter Event - Puts the R2 value into C0, not the LOAD VALUE  - FAIL
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    void main(void)
    {
       // Setup the clocks
       Setup_Clocks();
    
       // Setup the CLB
       Setup_CLB();
    
    
       /////////////////////////////////////////////////////////////////////////////////////////////////
       // Record the value of the counter before and after the first reset
       /////////////////////////////////////////////////////////////////////////////////////////////////
       C0_0_BeforeFirstCounterReset = Get_C0();   // Record the counter before the reset
       Toggle_Input(COUNTER0_RESET);              // Toggle the reset event
       C0_1_AfterFirstCounterReset = Get_C0();    // Record the counter value after the reset
    
    
       /////////////////////////////////////////////////////////////////////////////////////////////////
       // Record the value of the counter before and after the first  counter event
       /////////////////////////////////////////////////////////////////////////////////////////////////
       C0_2_BeforeFirstCounterEvent = Get_C0();   // Record the counter before the event
       Toggle_Input(COUNTER0_EVENT);              // Toggle the counter event
       C0_3_AfterFirstCounterEvent = Get_C0();    // Record the counter value after the event
    
    
       /////////////////////////////////////////////////////////////////////////////////////////////////
       // Record the value of the counter before and after the HLC event
       /////////////////////////////////////////////////////////////////////////////////////////////////
       C0_4_BeforeHlcEvent = Get_C0();            // Record the counter value before the event
       Toggle_Input(HLC_EV0_EVENT);               // Toggle the HLC event
       C0_5_AfterHlcEvent = Get_C0();             // Record the counter value after the event
    
    
       /////////////////////////////////////////////////////////////////////////////////////////////////
       // Record the value of the counter before and after the second reset
       /////////////////////////////////////////////////////////////////////////////////////////////////
       C0_6_BeforeSecondCounterReset = Get_C0();  // Record the counter before the reset
       Toggle_Input(COUNTER0_RESET);              // Toggle the reset event
       C0_7_AfterSecondCounterReset = Get_C0();   // Record the counter value after the reset
    
    
       /////////////////////////////////////////////////////////////////////////////////////////////////
       // Record the value of the counter before and after the second counter event
       //
       // THIS IS WERE THE FAILURE IS SEEN.  C0_9_AfterSecondCounterEvent will contain the incorrect
       // value.
       /////////////////////////////////////////////////////////////////////////////////////////////////
       C0_8_BeforeSecondCounterEvent = Get_C0();  // Record the counter value before the event
       Toggle_Input(COUNTER0_EVENT);              // Toggle the counter event
       C0_9_AfterSecondCounterEvent = Get_C0();   // Record the counter value after the event
    
       // Hang so we can look at the results.
       while(1);
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // Start Clock Setup Code
    //
    
    // Clock config registers
    #define CLK_CFG_REGS    0x05D200
    #define CLKSRCCTL1      0x08
    #define SYSPLLCTL1      0x0E
    #define SYSPLLMULT      0x14
    #define SYSPLLSTS       0x16
    #define SYSCLKDIVSEL    0x22
    
    // CPU Sys Registers
    #define CPU_SYS_REGS    0x05D300
    #define PCLKCR2         0x26
    
    // PCLKR2 Register
    #define ALL_EPWMS       0x0FFF
    
    // CLKSRCCTL1 Register Values
    #define XTALOFF             0x10
    #define OSCCLKSRCSEL_INIT   1
    
    // AUXPLLCTL1 Register
    #define PLLCLKEN            2
    
    void Setup_Clocks()
    {
       EALLOW;
    
       uint32 clk_src_ctl1 = *(uint32*)(CLK_CFG_REGS + CLKSRCCTL1);
       clk_src_ctl1 |= OSCCLKSRCSEL_INIT;
       clk_src_ctl1 &= ~XTALOFF;
       *(uint32*)(CLK_CFG_REGS + CLKSRCCTL1) = clk_src_ctl1;
    
       *(uint32*)(CLK_CFG_REGS + SYSPLLCTL1) &= ~2;
       *(uint32*)(CLK_CFG_REGS + SYSCLKDIVSEL) = 0;
    
       *(uint32*)(CLK_CFG_REGS + SYSPLLMULT) = 10;
    
       *(uint32*)(CLK_CFG_REGS + SYSPLLCTL1) |= 1;
    
       // Wait for the PLL to lock
       while(1 != (*(uint32*)(CLK_CFG_REGS + SYSPLLSTS) & 1))
          {
          }
    
       *(uint32*)(CLK_CFG_REGS + SYSPLLCTL1) |= PLLCLKEN;
    
       asm(" RPT #100 || NOP");
    
       *(uint32*)(CLK_CFG_REGS + SYSCLKDIVSEL) = 0;
    
       // Enable the clocks which supply the CLB
       *(uint32*)(CPU_SYS_REGS + PCLKCR2) = ALL_EPWMS;
    
       EDIS;
    }
    
    
    //
    // End Clock Setup Code
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // Start CLB Code
    //
    
    ///////////////////////////////////////////////////////////
    //
    // Setup_CLB
    //
    ///////////////////////////////////////////////////////////
    void Setup_CLB()
    {
        // Setup so we can load the CLB.
        Disable_CLB();
    
        // Set an initial value for the cell inputs.
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_GP_REG) = 0;
    
        // Setup Boundary Inputs 0, 1 and 2 to be controlled by
        // the processor.
        EALLOW;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_IN_MUX_SEL_0) |= SEL_GP_IN_0;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_IN_MUX_SEL_0) |= SEL_GP_IN_1;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_IN_MUX_SEL_0) |= SEL_GP_IN_2;
        EDIS;
    
        // Setup the tile's Counters
        Setup_Counters();
    
        // Setup the HLC
        Setup_HLC();
    
        // Enable the CLB.
        Enable_CLB();
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Toggle_Input
    //
    ///////////////////////////////////////////////////////////
    void Toggle_Input(uint16 boundary_input)
    {
        // Toggle the requested input
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_GP_REG) |= boundary_input;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_GP_REG) &= ~boundary_input;
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Get_C0
    //
    ///////////////////////////////////////////////////////////
    uint32 Get_C0()
    {
        // Return the current value of the debug register.
        return *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_DBG_C0);
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Write_IndirectRegister
    //
    ///////////////////////////////////////////////////////////
    void Write_IndirectRegister(uint32 address, uint32 data)
    {
        // Setup the address and data
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_LOAD_ADDR) = address;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_LOAD_DATA) = data;
    
        // Write the value.
        EALLOW;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_LOAD_EN) |= LOAD_EN;
        EDIS;
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Setup_Counter
    //
    ///////////////////////////////////////////////////////////
    void Setup_Counters()
    {
        // Load the logic config registers.
        EALLOW;
        *(uint32*)(CLB4_LOGIC_CFG_REGS + CLB_COUNT_RESET)  = Tile4_CFG_COUNTER_RESET;
        *(uint32*)(CLB4_LOGIC_CFG_REGS + CLB_COUNT_MODE_1) = Tile4_CFG_COUNTER_MODE_1;
        *(uint32*)(CLB4_LOGIC_CFG_REGS + CLB_COUNT_MODE_0) = Tile4_CFG_COUNTER_MODE_0;
        *(uint32*)(CLB4_LOGIC_CFG_REGS + CLB_COUNT_EVENT)  = Tile4_CFG_COUNTER_EVENT;
        *(uint32*)(CLB4_LOGIC_CFG_REGS + CLB_MISC_CONTROL) = Tile4_CFG_MISC_CONTROL;
        EDIS;
    
        // Load the event load registers.
        Write_IndirectRegister(COUNTER0_LOAD_VAL_ADDR, Tile4_COUNTER_0_LOAD_VAL);
        Write_IndirectRegister(COUNTER1_LOAD_VAL_ADDR, Tile4_COUNTER_1_LOAD_VAL);
        Write_IndirectRegister(COUNTER2_LOAD_VAL_ADDR, Tile4_COUNTER_2_LOAD_VAL);
    
        // Load the match1 registers.
        Write_IndirectRegister(COUNTER0_MATCH1_ADDR, Tile4_COUNTER_0_MATCH1_VAL);
        Write_IndirectRegister(COUNTER1_MATCH1_ADDR, Tile4_COUNTER_1_MATCH1_VAL);
        Write_IndirectRegister(COUNTER2_MATCH1_ADDR, Tile4_COUNTER_2_MATCH1_VAL);
    
        // Load the match2 registers.
        Write_IndirectRegister(COUNTER0_MATCH2_ADDR, Tile4_COUNTER_0_MATCH2_VAL);
        Write_IndirectRegister(COUNTER1_MATCH2_ADDR, Tile4_COUNTER_1_MATCH2_VAL);
        Write_IndirectRegister(COUNTER2_MATCH2_ADDR, Tile4_COUNTER_2_MATCH2_VAL);
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Setup_HLC
    //
    ///////////////////////////////////////////////////////////
    void Setup_HLC()
    {
        // Load the event instructions
        uint32 address = INSTRUCTIONS_EVENT0_ADDR;
        for(uint32 j = 0 ; j < HLC_INSTRUCTIONS_PER_TILE; j++, address++)
        {
            Write_IndirectRegister(address, HlcInstructions[j]);
        }
    
        // Configure the events
        EALLOW;
        *(uint32*)(CLB4_LOGIC_CFG_REGS + CLB_HLC_EVENT_SEL) = Tile4_HLC_EVENT_SEL;
        EDIS;
    
        // Load the HLC's registers
        Write_IndirectRegister(R0_ADDR, Tile4_HLC_R0_INIT);
        Write_IndirectRegister(R1_ADDR, Tile4_HLC_R1_INIT);
        Write_IndirectRegister(R2_ADDR, Tile4_HLC_R2_INIT);
        Write_IndirectRegister(R3_ADDR, Tile4_HLC_R3_INIT);
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Disable_CLB
    //
    ///////////////////////////////////////////////////////////
    void Disable_CLB()
    {
        EALLOW;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_LOAD_EN) &= ~GLOBAL_EN;
        EDIS;
    }
    
    
    ///////////////////////////////////////////////////////////
    //
    // Enable_CLB
    //
    ///////////////////////////////////////////////////////////
    void Enable_CLB()
    {
        EALLOW;
        *(uint32*)(CLB4_LOGIC_CTL_REGS + CLB_LOAD_EN) |= GLOBAL_EN;
        EDIS;
    }
    
    //
    // End CLB Code
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    

    // These arguments were used when this file was generated. They will be automatically applied on subsequent loads 
    // via the GUI or CLI invocations. Run CLI with '--help' for additional information on how to override these arguments.
    // @cliArgs --device "CC3200" --package "Default" --part "Default" --product "CLB Configuration Tool@1.0.0"
    // @versions {"data":"2019051709","timestamp":"2019051709","tool":"1.1.792","templates":"2019051709"}
    
    var TILE = scripting.addModule("/utilities/clb_tool/clb_syscfg/source/TILE");
    var TILE1 = TILE.addInstance();
    var TILE2 = TILE.addInstance();
    var TILE3 = TILE.addInstance();
    var TILE4 = TILE.addInstance();
    // clock_period - Period of the clock (in Nano Seconds) used for simulation in System C
    TILE.clock_period = 5;
    // reset_duration - Time at which reset signal is deassrted, specified in Nano Seconds
    TILE.reset_duration = 1;
    // sim_duration - Duration of the simulation (in Nano Seconds)
    TILE.sim_duration = 2000;
    // Name
    TILE1.$name = "Tile1";
    // Name
    TILE1.BOUNDARY.$name = "BOUNDARY0";
    // in0
    TILE1.BOUNDARY.in0 = "squareWave";
    // in_duty0 - Duty or ON time of the square wave
    TILE1.BOUNDARY.in_duty0 = 1;
    // in_repeat_count0 - Number of periods the waveform is repeated
    TILE1.BOUNDARY.in_repeat_count0 = 1;
    // in1
    TILE1.BOUNDARY.in1 = "TILE2_BOUNDARY.out5";
    // in_period0 - Period of the square wave
    TILE1.BOUNDARY.in_period0 = 2;
    // Name
    TILE1.LUT_0.$name = "LUT_0";
    // Name
    TILE1.LUT_1.$name = "LUT_1";
    // Name
    TILE1.LUT_2.$name = "LUT_2";
    // Name
    TILE1.FSM_0.$name = "FSM_0";
    // Name
    TILE1.FSM_1.$name = "FSM_1";
    // eqn_s1 - Boolean equation on the variables e1,e0,s1,s0 for the S1 output.
    TILE1.FSM_1.eqn_s1 = "0";
    // Name
    TILE1.FSM_2.$name = "FSM_2";
    // Name
    TILE1.COUNTER_0.$name = "COUNTER_0";
    // Name
    TILE1.COUNTER_1.$name = "COUNTER_1";
    // Name
    TILE1.COUNTER_2.$name = "COUNTER_2";
    // Name
    TILE1.OUTLUT_0.$name = "OUTLUT_0";
    // Name
    TILE1.OUTLUT_1.$name = "OUTLUT_1";
    // Name
    TILE1.OUTLUT_2.$name = "OUTLUT_2";
    // Name
    TILE1.OUTLUT_3.$name = "OUTLUT_3";
    // Name
    TILE1.OUTLUT_4.$name = "OUTLUT_4";
    // Name
    TILE1.OUTLUT_5.$name = "OUTLUT_5";
    // Name
    TILE1.OUTLUT_6.$name = "OUTLUT_6";
    // Name
    TILE1.OUTLUT_7.$name = "OUTLUT_7";
    // Name
    TILE1.HLC.$name = "HLC_0";
    // Name
    TILE1.HLC.program0.$name = "HLCP_0";
    // Name
    TILE1.HLC.program1.$name = "HLCP_1";
    // Name
    TILE1.HLC.program2.$name = "HLCP_2";
    // Name
    TILE1.HLC.program3.$name = "HLCP_3";
    var clb_run_dynamic_template_clb_h = scripting.addModule("/utilities/clb_tool/clb_syscfg/source/clb_run_dynamic_template_clb_h.js");
    var clb_run_dynamic_template_clb_c = scripting.addModule("/utilities/clb_tool/clb_syscfg/source/clb_run_dynamic_template_clb_c.js");
    var clb_run_dynamic_template_clb_sim = scripting.addModule("/utilities/clb_tool/clb_syscfg/source/clb_run_dynamic_template_clb_sim.js");
    var clb_run_dynamic_template_clb_dot = scripting.addModule("/utilities/clb_tool/clb_syscfg/source/clb_run_dynamic_template_clb_dot.js");
    // Name
    TILE2.$name = "Tile2";
    // Name
    TILE2.BOUNDARY.$name = "BOUNDARY2";
    // in0
    TILE2.BOUNDARY.in0 = "squareWave";
    // in_period0 - Period of the square wave
    TILE2.BOUNDARY.in_period0 = 40;
    // in_duty0 - Duty or ON time of the square wave
    TILE2.BOUNDARY.in_duty0 = 20;
    // in_repeat_count0 - Number of periods the waveform is repeated
    TILE2.BOUNDARY.in_repeat_count0 = 4;
    // Name
    TILE2.LUT_0.$name = "LUT_6";
    // Name
    TILE2.LUT_1.$name = "LUT_7";
    // Name
    TILE2.LUT_2.$name = "LUT_8";
    // Name
    TILE2.FSM_0.$name = "FSM_6";
    // Name
    TILE2.FSM_1.$name = "FSM_7";
    // Name
    TILE2.FSM_2.$name = "FSM_8";
    // Name
    TILE2.COUNTER_0.$name = "COUNTER_6";
    // Name
    TILE2.COUNTER_1.$name = "COUNTER_7";
    // Name
    TILE2.COUNTER_2.$name = "COUNTER_8";
    // Name
    TILE2.OUTLUT_0.$name = "OUTLUT_16";
    // Name
    TILE2.OUTLUT_1.$name = "OUTLUT_17";
    // Name
    TILE2.OUTLUT_2.$name = "OUTLUT_18";
    // Name
    TILE2.OUTLUT_3.$name = "OUTLUT_19";
    // Name
    TILE2.OUTLUT_4.$name = "OUTLUT_20";
    // Name
    TILE2.OUTLUT_5.$name = "OUTLUT_21";
    // Name
    TILE2.OUTLUT_6.$name = "OUTLUT_22";
    // Name
    TILE2.OUTLUT_7.$name = "OUTLUT_23";
    // Name
    TILE2.HLC.$name = "HLC_2";
    // Name
    TILE2.HLC.program0.$name = "HLCP_8";
    // Name
    TILE2.HLC.program1.$name = "HLCP_9";
    // Name
    TILE2.HLC.program2.$name = "HLCP_10";
    // Name
    TILE2.HLC.program3.$name = "HLCP_11";
    // Name
    TILE3.$name = "Tile3";
    // Name
    TILE3.BOUNDARY.$name = "BOUNDARY1";
    // Name
    TILE3.LUT_0.$name = "LUT_3";
    // Name
    TILE3.LUT_1.$name = "LUT_4";
    // Name
    TILE3.LUT_2.$name = "LUT_5";
    // Name
    TILE3.FSM_0.$name = "FSM_3";
    // Name
    TILE3.FSM_1.$name = "FSM_4";
    // Name
    TILE3.FSM_2.$name = "FSM_5";
    // Name
    TILE3.COUNTER_0.$name = "COUNTER_3";
    // Name
    TILE3.COUNTER_1.$name = "COUNTER_4";
    // Name
    TILE3.COUNTER_2.$name = "COUNTER_5";
    // Name
    TILE3.OUTLUT_0.$name = "OUTLUT_8";
    // Name
    TILE3.OUTLUT_1.$name = "OUTLUT_9";
    // Name
    TILE3.OUTLUT_2.$name = "OUTLUT_10";
    // Name
    TILE3.OUTLUT_3.$name = "OUTLUT_11";
    // Name
    TILE3.OUTLUT_4.$name = "OUTLUT_12";
    // Name
    TILE3.OUTLUT_5.$name = "OUTLUT_13";
    // Name
    TILE3.OUTLUT_6.$name = "OUTLUT_14";
    // Name
    TILE3.OUTLUT_7.$name = "OUTLUT_15";
    // Name
    TILE3.HLC.$name = "HLC_1";
    // Name
    TILE3.HLC.program0.$name = "HLCP_4";
    // Name
    TILE3.HLC.program1.$name = "HLCP_5";
    // Name
    TILE3.HLC.program2.$name = "HLCP_6";
    // Name
    TILE3.HLC.program3.$name = "HLCP_7";
    // Name
    TILE4.$name = "Tile4";
    // Name
    TILE4.BOUNDARY.$name = "BOUNDARY3";
    // Name
    TILE4.LUT_0.$name = "LUT_9";
    // Name
    TILE4.LUT_1.$name = "LUT_10";
    // Name
    TILE4.LUT_2.$name = "LUT_11";
    // Name
    TILE4.FSM_0.$name = "FSM_9";
    // Name
    TILE4.FSM_1.$name = "FSM_10";
    // Name
    TILE4.FSM_2.$name = "FSM_11";
    // Name
    TILE4.COUNTER_0.$name = "COUNTER_9";
    // What action should be taken on an event trigger?
    TILE4.COUNTER_0.action = "Load";
    // event - Trigger actions in the counter.
    TILE4.COUNTER_0.event = "BOUNDARY.in1";
    // reset - Reset the counter to 0 on next clock cycle (triggers low to high)
    TILE4.COUNTER_0.reset = "BOUNDARY.in0";
    // event_load_val - Sets the value of the event load value register.
    TILE4.COUNTER_0.event_load_val = "0xAAAAAAAA";
    // Name
    TILE4.COUNTER_1.$name = "COUNTER_10";
    // Name
    TILE4.COUNTER_2.$name = "COUNTER_11";
    // Name
    TILE4.OUTLUT_0.$name = "OUTLUT_24";
    // Name
    TILE4.OUTLUT_1.$name = "OUTLUT_25";
    // Name
    TILE4.OUTLUT_2.$name = "OUTLUT_26";
    // Name
    TILE4.OUTLUT_3.$name = "OUTLUT_27";
    // Name
    TILE4.OUTLUT_4.$name = "OUTLUT_28";
    // Name
    TILE4.OUTLUT_5.$name = "OUTLUT_29";
    // Name
    TILE4.OUTLUT_6.$name = "OUTLUT_30";
    // Name
    TILE4.OUTLUT_7.$name = "OUTLUT_31";
    // Name
    TILE4.HLC.$name = "HLC_3";
    // Event 0 (e0) - Event 0
    TILE4.HLC.e0 = "BOUNDARY.in2";
    // R2_init - Initial value for register R2
    TILE4.HLC.R2_init = "0x55555555";
    // Name
    TILE4.HLC.program0.$name = "HLCP_12";
    // instruct0
    TILE4.HLC.program0.instruct0 = "MOV R2, C0";
    // Name
    TILE4.HLC.program1.$name = "HLCP_13";
    // Name
    TILE4.HLC.program2.$name = "HLCP_14";
    // Name
    TILE4.HLC.program3.$name = "HLCP_15";
    

  • Let me dig into your example and I will get back to you!

  • Ed,

    I just ran the following scenario, and you are correct. When the CLB counter is in Load mode, and the load value is change:

    CLB_configCounterLoadMatch(CLB1_BASE, CLB_CTR0, 5000, 8000, 0);

    Whether the CLB is enabled or disabled, the C0 (counter's active counter value) is also updated to the LOAD value. WITHOUT AN EVENT signal.

    This is certainly something that we will document in the TRM.

    Nima

  • For your reference:

    #include "driverlib.h"
    #include "device.h"
    #include "clb_config.h"
    #include "clb.h"
    
    __interrupt void clb1ISR(void);
    
    #define EVENT_TIMER     1
    #define ENABLE_TIMER    2
    #define COUNTUP_MODE    4
    
    
    void main(void)
    {
        Device_init();
        Device_initGPIO();
    
        Interrupt_initModule();
        Interrupt_initVectorTable();
    
        //
        // Enabling EPWM1 to enable CLB1
        //
    	SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    
        CLB_disableCLB(CLB1_BASE);
        initTILE1(CLB1_BASE);
    
        //
        // Select Global input instead of local input for all CLB IN
        //
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN0, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN1, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN2, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN3, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN4, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN5, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN6, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN7, CLB_LOCAL_IN_MUX_GLOBAL_IN);
    
    
        //
        // Unused Inputs below
        //
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN0, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN1, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN2, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN3, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN4, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN5, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN6, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN7, CLB_GLOBAL_IN_MUX_EPWM1A);
    
    
        //
        // Inputs set to GP register
        //
        CLB_configGPInputMux(CLB1_BASE, CLB_IN0, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN1, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN2, CLB_GP_IN_MUX_GP_REG);
    
        //
        // Unused inputs to GP register
        //
        CLB_configGPInputMux(CLB1_BASE, CLB_IN3, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN4, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN5, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN6, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN7, CLB_GP_IN_MUX_GP_REG);
    
    
        CLB_enableCLB(CLB1_BASE);
        CLB_setGPREG(CLB1_BASE, ENABLE_TIMER | COUNTUP_MODE);
    
    
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        uint32_t c0 = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
        CLB_configCounterLoadMatch(CLB1_BASE, CLB_CTR0, 5000, 8000, 0);
        //CLB_setGPREG(CLB1_BASE, ENABLE_TIMER | COUNTUP_MODE | EVENT_TIMER);
        uint32_t c0_after_event = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_after_event_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
        ESTOP0;
        while(1)
        {
    
        }
    }
    
    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/clb_5F00_ed.syscfg

    In the code, you can see that if you run this, it will halt on ESTOP0.

    The values are:

    I will add this to the TRM as a note. 

  • Ahh.  You took my experiment a step further.  Great information.  Thank you!

    In my experiment, I also used the HLC to load C0, and the appearance is that the LOAD_VALUE register was written too because, after the HLC event, when the counter event occurs, C0 is written with the value from the HLC, not the original value written to the LOAD_VALUE register.  Is it possible that the HLC writes to C0 through the LOAD_VALUE register using the mechanism you illustrated above?

    Thank you,

    Ed

  • I dont think HLC can update the LOAD_val. HLC directly updates the C0. We can check this too to confirm!

  • Thank you for checking.  The middle step in my experiment uses the HLC to load C0 with a value, in R2, which is different from the value loaded into LOAD_VALUE.  After the HLC event, it shows that C0 contains the value in the HLC's R2 register.  After a reset of the counter to put 0 into C0, the counter event is toggled and the R2 value can then be seen in C0, not the original LOAD_VALUE.

    Thanks,

    Ed

  • I'm going to code this too really quick and we can add this to the TRM as well.

    Nima

  • Yes the HLC MOVing value from Rx to C0, updates the LOAD_val as well.

    Main.c file

    #include "driverlib.h"
    #include "device.h"
    #include "clb_config.h"
    #include "clb.h"
    
    __interrupt void clb1ISR(void);
    
    #define EVENT_TIMER     1
    #define ENABLE_TIMER    2
    #define COUNTUP_MODE    4
    #define HLC_TRIG        8
    
    
    void main(void)
    {
        Device_init();
        Device_initGPIO();
    
        Interrupt_initModule();
        Interrupt_initVectorTable();
    
        //
        // Enabling EPWM1 to enable CLB1
        //
    	SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    
        CLB_disableCLB(CLB1_BASE);
        initTILE1(CLB1_BASE);
    
        //
        // Select Global input instead of local input for all CLB IN
        //
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN0, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN1, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN2, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN3, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN4, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN5, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN6, CLB_LOCAL_IN_MUX_GLOBAL_IN);
        CLB_configLocalInputMux(CLB1_BASE, CLB_IN7, CLB_LOCAL_IN_MUX_GLOBAL_IN);
    
    
        //
        // Unused Inputs below
        //
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN0, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN1, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN2, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN3, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN4, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN5, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN6, CLB_GLOBAL_IN_MUX_EPWM1A);
        CLB_configGlobalInputMux(CLB1_BASE, CLB_IN7, CLB_GLOBAL_IN_MUX_EPWM1A);
    
    
        //
        // Inputs set to GP register
        //
        CLB_configGPInputMux(CLB1_BASE, CLB_IN0, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN1, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN2, CLB_GP_IN_MUX_GP_REG);
    
        //
        // Unused inputs to GP register
        //
        CLB_configGPInputMux(CLB1_BASE, CLB_IN3, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN4, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN5, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN6, CLB_GP_IN_MUX_GP_REG);
        CLB_configGPInputMux(CLB1_BASE, CLB_IN7, CLB_GP_IN_MUX_GP_REG);
    
    
        CLB_enableCLB(CLB1_BASE);
        CLB_setGPREG(CLB1_BASE, ENABLE_TIMER | COUNTUP_MODE);
    
    
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        uint32_t c0 = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
        CLB_configCounterLoadMatch(CLB1_BASE, CLB_CTR0, 5000, 8000, 0);
        //CLB_setGPREG(CLB1_BASE, ENABLE_TIMER | COUNTUP_MODE | EVENT_TIMER);
        uint32_t c0_after_load_changed = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_after_load_changed_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
    
    #if 0
        CLB_disableCLB(CLB1_BASE);
        uint32_t c0_after_disable = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_after_disable_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
        CLB_enableCLB(CLB1_BASE);
        uint32_t c0_after_enable = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_after_enable_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    #endif
    
        CLB_setGPREG(CLB1_BASE, ENABLE_TIMER | COUNTUP_MODE | HLC_TRIG);
        // HLC Loads 6000 to C0
        uint32_t c0_after_HLC = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_after_HLC_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
        CLB_setGPREG(CLB1_BASE, ENABLE_TIMER | COUNTUP_MODE | EVENT_TIMER);
        // Generate an EVENT trigger to see what value is loaded into C0
        uint32_t c0_after_EVENT = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
        uint32_t c0_after_EVENT_later = CLB_getRegister(CLB1_BASE, CLB_REG_CTR_C0);
    
    
        ESTOP0;
        while(1)
        {
    
        }
    }
    

    SysCfg File

    /**
     * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
     * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
     * @cliArgs --device "F2837xD" --package "F2837xD_176PTP" --part "F2837xD_176PTP" --product "CLB Configuration Tool@4.0.0"
     * @versions {"tool":"1.10.0+2029"}
     */
    
    /**
     * Import the modules used in this configuration.
     */
    const TILE  = scripting.addModule("/utilities/clb_tool/clb_syscfg/source/TILE");
    const TILE1 = TILE.addInstance();
    
    /**
     * Write custom configuration values to the imported modules.
     */
    TILE.clock_period = 10;
    TILE.sim_duration = 100000;
    
    TILE1.$name                     = "TILE1";
    TILE1.BOUNDARY.$name            = "BOUNDARY0";
    TILE1.BOUNDARY.in_repeat_count0 = 50;
    TILE1.BOUNDARY.in_repeat_count3 = 1;
    TILE1.BOUNDARY.in0              = "squareWave";
    TILE1.BOUNDARY.in_repeat_count1 = 50;
    TILE1.BOUNDARY.in_repeat_count2 = 50;
    TILE1.BOUNDARY.in_period0       = 10000;
    TILE1.BOUNDARY.in_duty0         = 5001;
    TILE1.BOUNDARY.in_period1       = 1000;
    TILE1.BOUNDARY.in_duty1         = 500;
    TILE1.BOUNDARY.in_period2       = 3000;
    TILE1.BOUNDARY.in_duty2         = 1500;
    TILE1.BOUNDARY.in1              = "1";
    TILE1.BOUNDARY.in2              = "1";
    TILE1.LUT_0.$name               = "LUT_0";
    TILE1.LUT_1.$name               = "LUT_1";
    TILE1.LUT_2.$name               = "LUT_2";
    TILE1.FSM_0.$name               = "FSM_0";
    TILE1.FSM_0.e0                  = "COUNTER_0.count_match1";
    TILE1.FSM_0.eqn_s0              = "e0 ^ s0";
    TILE1.FSM_1.$name               = "FSM_1";
    TILE1.FSM_2.$name               = "FSM_2";
    TILE1.COUNTER_0.$name           = "COUNTER_0";
    TILE1.COUNTER_0.action          = "Load";
    TILE1.COUNTER_0.reset           = "COUNTER_0.count_match1";
    TILE1.COUNTER_0.event           = "BOUNDARY.in0";
    TILE1.COUNTER_0.mode0           = "BOUNDARY.in1";
    TILE1.COUNTER_0.mode1           = "BOUNDARY.in2";
    TILE1.COUNTER_0.match1_val      = "8000";
    TILE1.COUNTER_0.event_load_val  = "2000";
    TILE1.COUNTER_1.$name           = "COUNTER_1";
    TILE1.COUNTER_2.$name           = "COUNTER_2";
    TILE1.OUTLUT_0.$name            = "OUTLUT_0";
    TILE1.OUTLUT_1.$name            = "OUTLUT_1";
    TILE1.OUTLUT_2.$name            = "OUTLUT_2";
    TILE1.OUTLUT_3.$name            = "OUTLUT_3";
    TILE1.OUTLUT_4.$name            = "OUTLUT_4";
    TILE1.OUTLUT_5.$name            = "OUTLUT_5";
    TILE1.OUTLUT_6.$name            = "OUTLUT_6";
    TILE1.OUTLUT_7.$name            = "OUTLUT_7";
    TILE1.HLC.$name                 = "HLC_0";
    TILE1.HLC.e0                    = "BOUNDARY.in3";
    TILE1.HLC.R0_init               = "6000";
    TILE1.HLC.program0.$name        = "HLCP_0";
    TILE1.HLC.program0.instruct0    = "MOV R0,C0";
    TILE1.HLC.program1.$name        = "HLCP_1";
    TILE1.HLC.program2.$name        = "HLCP_2";
    TILE1.HLC.program3.$name        = "HLCP_3";
    

  • Everything makes sense now.  Thank you again for all your help Nima.

    Regards,

    Ed