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.

[FAQ] AM13E23019: AM13E230x: Issue with the sysconfig interface for timer configuration

Part Number: AM13E23019
Other Parts Discussed in Thread: SYSCONFIG

Hi experts,

I wanted help with the Timer module configuration of the AM13E30x sysconfig. I open the example.syscfg and try to configure the timer, but notice the following issues:

  1. The TIMG12x instance gets added at index 0 and replaces the existing TIMG4x configurations
  2. Based on the clock pre-scalars and clock dividers, the range of timer period that can be set is shown but the sysconfig throws errors saying the timer period configured is invalid and out-of-range.
  3. There are issues with TIMG12x pre-scalar (TRM says there is no pre-scalar for TIMG12x but sysconfig has an option)

Can you please help provide a patch that fixes the above issues.

  • There are known bugs in the v26.00 SDK for Timer configuration in sysconfig. Please use the updated file below and replace it at: mcu_sdk/source/.meta/drivers/timer/v0/timer.syscfg.js

    /*
     * Copyright (c) 2025 Texas Instruments Incorporated - http://www.ti.com
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    /*
     *  ======== Timer.js ========
     */
    
    "use strict";
    
    let common = system.getScript("/common");
    let soc = system.getScript(`/soc/${common.getSocName()}/drivers`);
    let timerConfigOptions = system.getScript("/driverlib/device_driverlib_peripherals/"+common.getSocName()+"/dl_timer.js");
    
    const EmptyTimerProfile = {
        timerClkDiv: "DL_TIMER_CLOCK_DIVIDE_1",
        timerClkPrescale: 1,
        timerMode: "DL_TIMER_TIMER_MODE_ONE_SHOT",
        timerPeriod: "0 ms",
        timerStartTimer: false,
        interrupts: [],
        event1ControllerInterruptEn: [],
        event2ControllerInterruptEn: [],
    };
    
    const TimerProfiles = [
        {
            name: "Basic_Periodic",
            timerClkDiv: "DL_TIMER_CLOCK_DIVIDE_8",
            timerClkPrescale: 256,
            timerPeriod: "500 ms",
            timerMode: "DL_TIMER_TIMER_MODE_PERIODIC",
            interrupts: ["DL_TIMER_INTERRUPT_ZERO_EVENT"],
            registerInterrupt: true
        },
        {
            name: "Basic_OneShot",
            timerClkDiv: "DL_TIMER_CLOCK_DIVIDE_8",
            timerClkPrescale: 256,
            timerPeriod: "500 ms",
            timerMode: "DL_TIMER_TIMER_MODE_ONE_SHOT",
            interrupts: ["DL_TIMER_INTERRUPT_ZERO_EVENT"],
            registerInterrupt: true
        }
    ];
    
    let config = [
        common.addNameConfig("/drivers/timer", "TIMER_"),
        {
            name: "timerType",
            displayName: "Timer Type",
            longDescription: `The device supports the following types of timer instances. The actual instance can be selected under Pinmux group
            ![Timer Types](.meta/drivers/timer/v0/images/timerTypes.png "Timer Types")
            `,
            default: "TIMG4",
            options: [
                {name: "TIMG4"},
                {name: "TIMG12"}
            ],
            onChange : (inst, ui) => {
                ui.timerClkPrescale.hidden = inst.timerType == "TIMG12";
            }
        },
        /* Show selected peripheral below instance name */
        {
            name: "selectedInstance",
            displayName: "Selected Peripheral",
            default: "",
            longDescription: `Refer to the PinMux section for peripheral selection. Chosen instance name is not indicative of active peripheral.`,
            getValue: (inst) => {
                let solution = "";
                try{
                    solution = inst.peripheral.$solution.peripheralName;
                }catch (e) {
                    // do nothing
                }
                return solution;
            }
        },
        /****** PROFILES CONFIGURATION *******/
        {
            name: "GROUP_QUICK_PROFILE",
            displayName: "Quick Profiles",
            description: "",
            collapsed: false,
            config: [
                {
                    name: "profile",
                    displayName: "Timer Profiles",
                    description: "Pre-defined profiles for typical TIMER configurations",
                    longDescription: `
    The TIMER module is a set of general purpose timers that can be
    configured without an external pin to set an interrupt, event, or trigger other timers.
    The module allows the use of TIMG4 and TIMG12 instances. A specific instance can be selected
    in the PinMux Section, or one can be solved for based on the given capabilities
    
    * **TIMG4**:
        * 16-bit counter with 8-bit prescaler
    * **TIMG12**:
        * 32-bit counter without a prescaler
    
    The profiles that are given are:
    * **Basic Periodic**: Basic Periodic timer generating a zero interrupt every 500 ms
    * **Basic One-Shot**: Basic One-Shot timer generating a zero interrupt 500 ms after being triggered`,
                    default: "CUSTOM",
                    options: [
                        { name: "Basic_Periodic", displayName: "Periodic with 500 ms Period and Zero Event"},
                        { name: "Basic_OneShot", displayName: "One-Shot with 500 ms Period and Zero Event" },
                        { name: "CUSTOM", displayName: "Custom" }
                    ],
                    onChange: onChangeTimerProfile
                }
            ]
        },
        /******************** BASIC CONFIGURATIONS *************************/
        {
            name: "GROUP_BASIC",
            displayName: "Basic Configuration",
            description: "",
            longDescription: "",
            collapsed: false,
                config: [
                    {
                        name: "GROUP_CLOCK",
                        displayName: "Clock Configuration",
                        description: "",
                        longDescription: "Configures Timer clock source, divider and prescaler",
                        collapsed: false,
                        config: [
                            {
                                name        : "timerClkDiv",
                                displayName : 'Timer Clock Divider',
                                description : 'Timer Clock Divider',
                                hidden      : false,
                                default     : "DL_TIMER_CLOCK_DIVIDE_1",
                                options     : timerConfigOptions.DL_TIMER_CLOCK_DIVIDE,
                                onChange    : onChangeSetCustomProfile
                            },
                            {
                                name        : "timerClockSourceCalculated",
                                displayName : "Calculated Timer Clock Source",
                                description : 'Calculated Timer Clock Source in Hz',
                                hidden      : false,
                                getValue    : (inst) => getTimerClockSourceFreq(inst),
                                default     : 0
                            },
                            {
                                name        : "timerClkPrescale",
                                displayName : 'Timer Clock Prescaler',
                                description : 'Timer Clock Prescaler',
                                hidden      : false,
                                isInteger   : true,
                                default     : 1,
                                range       : [1, 256],
                                onChange    : onChangeSetCustomProfile
                            },
                            {
                                name: "GROUP_CLOCK_CAL",
                                displayName: "Calculated Timer Clock Values",
                                description: "",
                                collapsed: false,
                                config:
                                [
                                    {
                                        name: "timerClockFreqNum",
                                        displayName : 'Timer Clock Frequency',
                                        description : 'Timer Clock Frequency',
                                        hidden: true,
                                        default: 0,
                                        getValue: getTimerClockFreq,
                                    },
                                    {
                                        name: "timerClockFreqStr",
                                        displayName : 'Timer Clock Frequency',
                                        description : 'Timer Clock Frequency',
                                        longDescription:
    `
    This is the clock frequency that is seen by the timer count register. It is after the input clock has been
    divided and prescaled.\n
    Timer Clock Frequency calculation: timerClkFreq = (timerClkSrc / (timerClkDiv \* timerClkPrescale))\n
    ex.\n
    Timer clock sourced by BUSCLK running at 32000000 Hz\n
    Timer clock source divider set to 2\n
    Timer clock prescale set to 4\n
              timerClkFreq = (timerClkSrc / (timerClkDivRatio * timerClkPrescale))\n
              4000000 Hz = 16000000 Hz / (2 * 4)\n
    `,
                                        readOnly: true,
                                        hidden: false,
                                        default: "0 Hz",
                                        getValue: getTimerClockFreqStr,
                                    },
                                    {
                                        name: "timerPeriodRangeStr",
                                        displayName : 'Timer Period Range And Resolution',
                                        description : 'Range and Resolution of currently selected Timer instance',
                                        longDescription: 'Take into account if selected Timer instance has a 16-bit or 32-bit counter.',
                                        readOnly: true,
                                        hidden: false,
                                        default: "0 Hz",
                                        getValue: getTimerPeriodRangeStr,
                                    },
                                ]
                            },
                            {
                                name: "timerClockFreq",
                                hidden: true,
                                default: 0,
                                getValue: getTimerClockFreq,
                            },
                        ]
                    },
                    {
                        name        : "timerMode",
                        displayName : 'Timer Mode',
                        description : 'Timer Mode',
                        hidden      : false,
                        default     : "DL_TIMER_TIMER_MODE_ONE_SHOT",
                        options     : timerConfigOptions.DL_TIMER_TIMER_MODE,
                        /*
                         * counterZero should only be selectable when the timer is
                         * in periodic mode
                         */
                        onChange: (inst, ui) => {
                            ui.counterZero.hidden = !(inst.timerMode == "DL_TIMER_TIMER_MODE_PERIODIC");
                            onChangeSetCustomProfile(inst, ui);
                        }
                    },
                    {
                        name        : "timerPeriod",
                        displayName : 'Desired Timer Period',
                        description : 'Desired Timer Period in seconds',
                        longDescription: `The desired timer period is an input string that can set the period of the timer.
                                          Expected units (s). Valid formats:
    * Units with supported prefixes (G, M, k, c, m, u, n):
        * 234.56 ms, 150ns
    * Units without a prefix:
        * 0.0123 s, 1.0 s
    * Exponential form with units
        * 123.45e-8 s
    * No units or prefix (interpreted as seconds):
        * 1.234`,
                        hidden      : false,
                        default     : "0 ms",
                        onChange    : onChangeSetCustomProfile
                    },
                    {
                        name        : "timerPeriodActualTicks",
                        displayName : 'hidden-actualTimerTicks',
                        description : 'hidden-actualTimerTicks',
                        hidden      : true,
                        default     : 0,
                        getValue    : getActualTimerPeriodTicks,
                    },
                    {
                        name        : "timerPeriodActual",
                        displayName : 'Actual Timer Period',
                        description : 'Actual Timer Period',
                        hidden      : false,
                        default     : "0 s",
                        getValue    : getActualTimerPeriod,
                    },
                    {
                        name        : "timerStartTimer",
                        displayName : 'Start Timer',
                        description : 'Start Timer',
                        longDescription: `When selected, the timer starts counting
                        after the Timer is initialized. Otherwise the timer will start
                        counting after the application calls DL_TimerX_startCounter.`,
                        hidden      : false,
                        default     : false,
                        onChange    : onChangeSetCustomProfile
                    },
            ]
        },
        /******************** Advanced CONFIGURATION *************************/
        {
            name: "GROUP_ADVANCED",
            displayName: "Advanced Configuration",
            collapsed: true,
            config: [
                {
                    name            : "enableShadowLoad",
                    displayName     : "Enable Shadow Load",
                    description     : "Enables Shadow Load",
                    longDescription : `Enables shadow load feature. Only supported in TIMA instance and TIMG4-TIMG7 instances.
                    \n When enabled updates to Timer LOAD register are synchronized with the timer's ZERO event`,
                    default         : false,
                    onChange        : onChangeEnableShadowLoad
                }
            ]
        },
        /******************** INTERRUPT *************************/
        {
            name: "interruptsConfig",
            displayName: "Interrupts Configuration",
            collapsed: true,
            config: [
                {
                    name: "interrupts",
                    displayName: "Enable Interrupts",
                    description: "Specifies which interrupts are to be enabled",
                    longDescription: `Specifies the timer interrupts will be triggered`,
                    default: [],
                    options: timerConfigOptions.DL_TIMER_INTERRUPT,
                    minSelections: 0,
                    onChange: onChangeInterrupts,
                },
                {
                    name        : "registerInterrupt",
                    displayName : "Register Interrupt In The Core",
                    default     : false
                }
            ]
        },
        {
            name: "eventConfig",
            displayName: "Event Configuration",
            longDescription: `Specifies the Timer Events that are to trigger an Event Condition and where the events are to be published`,
            collapsed: true,
            config: [
                {
                    name: "event1ControllerInterruptEn",
                    displayName: "Event 1 Enable Controller Interrupts",
                    description: "Determines the Timer Events that will trigger an Event 1 condition",
                    longDescription: `Selects all possible timer Events that will create an Event 1 condition`,
                    default: [],
                    options: timerConfigOptions.DL_TIMER_EVENT,
                    minSelections: 0,
                },
                {
                    name: "event2ControllerInterruptEn",
                    displayName: "Event 2 Enable Controller Interrupts",
                    description: "Determines the Timer Events that will trigger an Event 2 condition",
                    longDescription: `Selects all possible timer Events that will create an Event 2 condition`,
                    default: [],
                    options: timerConfigOptions.DL_TIMER_EVENT,
                    minSelections: 0,
                },
                {
                    name: "counterZero",
                    displayName: "Zero Counter On A Published Event",
                    description: "Specifies whether the counter should be zeroed on a published event",
                    longDescription: "",
                    hidden: true,
                    default: false,
                }
            ]
        },
    ]
    
    /************************* Profile functions *******************************/
    function onChangeTimerProfile(inst, ui) {
        if(inst.profile !== "CUSTOM") {
            // matches name shorthand
            let selectedProfile = _.filter(TimerProfiles, ['name', inst.profile]);
            if(selectedProfile.length === 1){
                // assigns the empty profile with the selected profile on top
                Object.assign(inst, EmptyTimerProfile,
                    _.pickBy(selectedProfile[0], (_,key) => key !== 'name'));
    
            } else {
                throw `profileError`;
            }
        }
    }
    
    /************************* Basic onChange functions *******************************/
    function onChangeSetCustomProfile(inst, ui) {
        inst.profile = "CUSTOM";
    }
    
    /************************* Advanced onChange functions *******************************/
    function onChangeEnableShadowLoad(inst,ui)
    {
        onChangeSetCustomProfile(inst, ui);
    }
    
    /************************* Interrupt onChange functions *******************************/
    function onChangeInterrupts(inst,ui)
    {
        onChangeSetCustomProfile(inst, ui);
    }
    /************************* General functions **********************************/
    function getTimerClockSourceFreq(inst) {
    
        let timerClockFreq = common.getBUSCLKFreq("TIMER");
    
        timerClockFreq = timerClockFreq / inst.timerClkDiv.slice(-1);
    
        return timerClockFreq;
    }
    
    function getTimerClockFreq(inst,ui)
    {
        let timerClkFreq = common.getBUSCLKFreq("TIMER");;
        let timerDivider = inst.timerClkDiv.slice(-1);
        let timerPrescaler;
    
        if(isHighResolutionCapable(inst)){
            timerPrescaler = 1;
        }else{
            timerPrescaler = (inst.timerClkPrescale);
        }
    
        timerClkFreq = (timerClkFreq / (timerDivider * timerPrescaler));
    
        return timerClkFreq;
    
    }
    
    function getTimerClockFreqStr(inst,ui)
    {
        let freq = getTimerClockFreq(inst,ui);
        let freqStr = common.getUnitPrefix(freq);
    
        return freqStr.str + "Hz";
    }
    
    function getTimerPeriodRangeStr(inst,ui)
    {
        let bitRes;
        let minPeriod;
        let maxPeriod;
        let maxPeriodScaled;
        let maxPeriodVal;
        let maxPeriodUnits;
        let resolution;
        let timerFreq;
    
        timerFreq = getTimerClockFreq(inst,ui);
    
        bitRes = getTimerCountBitRes(inst,ui);
    
        resolution = minPeriod = common.getUnitPrefix( 1 / timerFreq);
        if(inst.timerMode.includes("UP_DOWN")){
            maxPeriod  = 2*Math.pow(2,bitRes) / timerFreq;
        }else{
            maxPeriod  = (Math.pow(2,bitRes) / timerFreq);
        }
    
        maxPeriodScaled = getScaledPeriod(maxPeriod);
        maxPeriodVal = maxPeriodScaled[0];
        maxPeriodUnits = maxPeriodScaled[1];
    
        let str = minPeriod.str + "s to " + maxPeriodVal + maxPeriodUnits + "w/ resolution of " + resolution.str + "s";
        return str;
    }
    
    function isHighResolutionCapable(inst)
    {
        return (inst.timerType == "TIMG12")
    }
    
    function getTimerCountBitRes(inst,ui)
    {
        let bitRes;
    
        if(isHighResolutionCapable(inst))
        {
            bitRes = 32;
        }else{
            bitRes = 16;
        }
    
        return bitRes;
    }
    
    function getScaledPeriod(valueInSec)
    {
        let value;
        let maxPerUnits;
        let maxPeriodStr;
    
        /* Avoid ks notation */
        if((valueInSec / 1000) > 1)
        {
            value = (valueInSec / 60);
            /* Avoid kmin notation */
            if((value / 1000) > 1)
            {
                value = (value / 60);
                maxPerUnits = "hrs ";
            }else
            {
                maxPerUnits = "min ";
            }
        }else{
           value = valueInSec;
           maxPerUnits = "s ";
        }
    
         maxPeriodStr = common.getUnitPrefix(value).str;
    
         return [maxPeriodStr , maxPerUnits]
    }
    
    function getActualTimerPeriodTicks(inst)
    {
        let desiredPeriod = common.parseFloatUnitInput(inst.timerPeriod,"s");
        if(desiredPeriod === NaN){
            return "NaN";
        }
        let timerFreq = getTimerClockFreq(inst);
    
        if(inst.timerMode.includes("UP_DOWN"))
        {
            desiredPeriod = desiredPeriod / 2;
        }else{
            desiredPeriod = desiredPeriod;
        }
        return (Math.round(desiredPeriod * timerFreq));
    
    }
    
    function getActualTimerPeriod(inst)
    {
        let timerFreq = getTimerClockFreq(inst);
        let maxTimerTicks = Math.pow(2,getTimerCountBitRes(inst));
        let timerMode = inst.timerMode
        let timerTicks;
        let actualStr;
    
        timerTicks = getActualTimerPeriodTicks(inst);
    
        if(timerMode.includes("UP_DOWN"))
        {
            maxTimerTicks = 2*maxTimerTicks;
        }else{
            maxTimerTicks = maxTimerTicks;
        }
    
        if(timerTicks > maxTimerTicks)
        {
            actualStr = 'Desired Timer Period is out of range'
        }else{
            let result = getScaledPeriod(timerTicks / timerFreq);
            actualStr = result[0] + result[1];
        }
        return actualStr;
    }
    
    function moduleInstances(inst)
    {
        let components = []
        if(inst.registerInterrupt) {
            components.push(
                {
                    moduleName  : "drivers/interrupt",
                    name        : "timerInt",
                    displayName : "Timer Interrupt",
                    collapsed   : false,
                    group       : "GROUP_INTERRUPTS",
                    requiredArgs : {
                        $name                   : inst.$name + "_INT",
                        pinmuxPeripheral        : true,
                        pinmuxPeripheralIntName : "#_INT"
                    },
                }
            )
        }
        return components
    }
    
    /*  ======== pinmuxRequirements ========
     *  Returns peripheral pin requirements of the specified instance
     *
     *  param inst    - a fully configured PWM instance
     *
     *  returns req[] - an array of pin requirements needed by inst
     */
    function pinmuxRequirements(inst)
    {
        let allResources = [];
    
        let timer = {
            name: "peripheral",
            displayName: "Timer Peripheral",
            interfaceName: "TIMER",
            filter: (peripheral) => {return peripheral.name.startsWith(inst.timerType)},
            resources: [],
            signalTypes: {
            },
        };
    
        let ind;
    
        return ([timer]);
    }
    
    /*
     *  ======== validate ========
     *  Validate this inst's configuration
     *
     *  param inst       - module instance to be validated
     *  param validation - object to hold detected validation issues
     */
    function validate(inst, validation)
    {
        if(inst.timerPeriodActual == 'Desired Timer Period is out of range')
            validation.logError("Desired Timer Period is out of range", inst, "timerPeriodActual")
    }
    
    /*
     *  ===================== Timer MODULE ===========================
     *  Define the Timer properties and methods
     */
    let timer_module = {
        displayName: "TIMER",
        description: "Timer Module",
        //TBD: Add long description with image
        defaultInstanceName: "APP_TIMER_",
        config: config,
    
        pinmuxRequirements: pinmuxRequirements,
    
        validate: validate,
    
        modules: common.autoForceModules(["config", "sysctl"]),
    
        /* override device-specific templates */
        templates: {
            configc: "/drivers/timer/"+soc.getDriverVer("timer")+"/dl_timer_config.c.xdt",
            configh: "/drivers/timer/"+soc.getDriverVer("timer")+"/dl_timer_config.h.xdt",
            Call: true,
            Reset: true,
            Power: true,
            Pinmux: true,
            Function: true,
    
        },
    
        moduleInstances,
        maxInstances: common.getInstanceList("TIM").length
    };
    
    exports = timer_module;

    Then re-open your example.syscfg and try to re-configure the timers.

    Regards,
    Shaunak