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.

MSPM0L1306: Generic publisher event example of Timer

Part Number: MSPM0L1306
Other Parts Discussed in Thread: SYSCONFIG

Hi,

I want to change the duty of PWM every cycle.

So I'm trying to use DMA to write duty to a capture/counter register every cycle.

I use a GEN_EVENT0 as the DMA trigger source.

But my project is not working.

1. PWM event setting

2. DMA setting

I attached a project file.

PWM_DMA_TEST_LP_MSPM0L1306.zip

Could I get some example about generic publisher event example of Timer?

  • For the DMA1 is configured to move the data from a buffer to PWM load value, but why do you configure the DMA1 destination address to another buffer as below?

        DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t) &gPwmReg[0]);

    I think you should move the data to CC register I think.

  • Hi Gary Gao,

    The reason why the DMA destination address is set to buffer is to test the DMA trigger source first. This is not a problem.

    I guess the cause of the problem is the DMA subscriber settings.

    The DL_DMA_setSubscriberChanID function is not automatically included in the file generated by sysconfig.

    I am trying to implement the picture below. And try to write TIMx.LOAD = A with DMA instead of SW.

    ST already provides examples and references as following link.

    https://community.st.com/t5/stm32-mcus/custom-signal-generation-using-pwm-and-dma/ta-p/49809

    Below is the code I simply tested for PWM and DMA operation.

    It seems to work normally, but I don't know if I set it up correctly.

    /*
     * Copyright (c) 2021, Texas Instruments Incorporated
     * 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.
     */
    
    /*
     *  ============ ti_msp_dl_config.c =============
     *  Configured MSPM0 DriverLib module definitions
     *
     *  DO NOT EDIT - This file is generated for the MSPM0L130X
     *  by the SysConfig tool.
     */
    
    #include "ti_msp_dl_config.h"
    
    /*
     *  ======== SYSCFG_DL_init ========
     *  Perform any initialization needed before using any board APIs
     */
    SYSCONFIG_WEAK void SYSCFG_DL_init(void)
    {
        SYSCFG_DL_initPower();
        SYSCFG_DL_GPIO_init();
        /* Module-Specific Initializations*/
        SYSCFG_DL_SYSCTL_init();
        SYSCFG_DL_PWM_0_init();
        SYSCFG_DL_DMA_CH0_init();
    }
    
    SYSCONFIG_WEAK void SYSCFG_DL_initPower(void)
    {
        DL_GPIO_reset(GPIOA);
        DL_TimerG_reset(PWM_0_INST);
    
        DL_GPIO_enablePower(GPIOA);
        DL_TimerG_enablePower(PWM_0_INST);
        delay_cycles(POWER_STARTUP_DELAY);
    }
    
    SYSCONFIG_WEAK void SYSCFG_DL_GPIO_init(void)
    {
    
    
        DL_GPIO_initPeripheralOutputFunction(GPIO_PWM_0_C0_IOMUX,GPIO_PWM_0_C0_IOMUX_FUNC);
        DL_GPIO_enableOutput(GPIO_PWM_0_C0_PORT, GPIO_PWM_0_C0_PIN);
    
    
    
    }
    
    
    SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_init(void)
    {
        DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE);
        DL_SYSCTL_enableMFCLK();
        DL_SYSCTL_setMCLKDivider(DL_SYSCTL_MCLK_DIVIDER_DISABLE);
    
    	//Low Power Mode is configured to be SLEEP0
        DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_0);
    
    
    }
    
    
    
    
    
    /*
     * Timer clock configuration to be sourced by  / 1 (4000000 Hz)
     * timerClkFreq = (timerClkSrc / (timerClkDivRatio * (timerClkPrescale + 1)))
     *   1000000 Hz = 4000000 Hz / (1 * (3 + 1))
     */
    static const DL_TimerG_ClockConfig gPWM_0ClockConfig = {
        .clockSel = DL_TIMER_CLOCK_MFCLK,
        .divideRatio = DL_TIMER_CLOCK_DIVIDE_1,
        .prescale = 3U
    };
    
    static const DL_TimerG_PWMConfig gPWM_0Config = {
        .pwmMode = DL_TIMER_PWM_MODE_EDGE_ALIGN,
        .period = 50000,
        .startTimer = DL_TIMER_STOP,
    };
    
    SYSCONFIG_WEAK void SYSCFG_DL_PWM_0_init(void) {
    
        DL_TimerG_setClockConfig(
            PWM_0_INST, (DL_TimerG_ClockConfig *) &gPWM_0ClockConfig);
    
        DL_TimerG_initPWMMode(
            PWM_0_INST, (DL_TimerG_PWMConfig *) &gPWM_0Config);
    
    
        DL_TimerG_setCaptureCompareValue(PWM_0_INST, 25000, DL_TIMER_CC_0_INDEX);
        DL_TimerG_enableClock(PWM_0_INST);
        DL_TimerG_enableEvent(PWM_0_INST, DL_TIMER_EVENT_ROUTE_1, (DL_TIMER_EVENT_CC0_DN_EVENT));
    
        DL_TimerG_setPublisherChanID(PWM_0_INST, DL_TIMER_PUBLISHER_INDEX_0, PWM_0_INST_PUB_0_CH);
    
    
        DL_TimerG_enableInterrupt(PWM_0_INST , DL_TIMER_INTERRUPT_CC0_DN_EVENT);
    
        DL_TimerG_setCCPDirection(PWM_0_INST , DL_TIMER_CC0_OUTPUT );
    }
    
    
    static const DL_DMA_Config gDMA_CH0Config = {
        .transferMode   = DL_DMA_SINGLE_TRANSFER_MODE,
        .extendedMode   = DL_DMA_NORMAL_MODE,
        .destIncrement  = DL_DMA_ADDR_UNCHANGED,
        .srcIncrement   = DL_DMA_ADDR_INCREMENT,
        .destWidth      = DL_DMA_WIDTH_HALF_WORD,
        .srcWidth       = DL_DMA_WIDTH_HALF_WORD,
        .trigger        = DMA_CH0_TRIGGER_SEL_FSUB_0
    };
    
    SYSCONFIG_WEAK void SYSCFG_DL_DMA_CH0_init(void)
    {
        DL_DMA_clearInterruptStatus(DMA, DL_DMA_INTERRUPT_CHANNEL0);
        DL_DMA_enableInterrupt(DMA, DL_DMA_INTERRUPT_CHANNEL0);
        DL_DMA_initChannel(DMA, DMA_CH0_CHAN_ID , (DL_DMA_Config *) &gDMA_CH0Config);
    }
    
    
    
    4452.ti_msp_dl_config.h

    /*
     * Copyright (c) 2021, Texas Instruments Incorporated
     * 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.
     */
    
    #include "ti_msp_dl_config.h"
    
    
    
    #define DMA_TRANSFER_SIZE_WORDS (16)
    
    const uint16_t gSrcData[DMA_TRANSFER_SIZE_WORDS] =
    {1000, 5000, 10000, 15000, 20000, 25000, 30000, 35000,
     40000, 45000, 49999, 40000, 30000, 20000, 10000, 2000};
    
    uint16_t gDstData;
    
    volatile bool gChannel0InterruptTaken = false;
    
    volatile uint32_t gUpdateCnt;
    
    
    int main(void)
    {
        SYSCFG_DL_init();
    
        gUpdateCnt = 0;
        DL_TimerG_startCounter(PWM_0_INST);
    
        /* Setup interrupts on device */
        DL_SYSCTL_disableSleepOnExit();
        NVIC_EnableIRQ(DMA_INT_IRQn);
    
        /* Configure DMA source, destination and size */
        DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gSrcData[0]);
        DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&PWM_0_INST->COUNTERREGS.CC_01[0]));
        DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, DMA_TRANSFER_SIZE_WORDS);
        DL_DMA_setSubscriberChanID(DMA, DL_DMA_SUBSCRIBER_INDEX_0, PWM_0_INST_PUB_0_CH);
        DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
    
    
        gChannel0InterruptTaken = false;
        DL_DMA_startTransfer(DMA, DMA_CH0_CHAN_ID);
    
        /* Wait for transfer */
        while (gChannel0InterruptTaken == false) {
            __WFE();
        }
    
        /* Breakpoint to inspect verification result */
        __BKPT(0);
    
    
        while (1)
        {
            __WFI();
        }
    }
    
    void PWM_0_INST_IRQHandler(void)
    {
        switch (DL_TimerG_getPendingInterrupt(PWM_0_INST))
        {
            case DL_TIMERG_IIDX_CC0_DN:
                gUpdateCnt++;
                default:
                    break;
        }
    }
    
    void DMA_IRQHandler(void)
    {
        /* Example interrupt code -- just used to break the WFI in this example */
        switch (DL_DMA_getPendingInterrupt(DMA)) {
            case DMA_IIDX_STAT_DMACH0:
                gChannel0InterruptTaken = true;
                break;
            default:
                break;
        }
    }
    

  • Do you do the configuration with sysconfig right? If so and it works, the code should be no problem.