Request for Source Code Review: Controlling FlexPWM Duty Cycle with DMA on RT1060

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Request for Source Code Review: Controlling FlexPWM Duty Cycle with DMA on RT1060

330 Views
pooisonner
Contributor III

Hello, I am trying to control the duty cycle of FlexPWM on the RT1060 using DMA. Could you please review my source code and check if there are any issues? The code is not working as expected.

  1. PWM Initialization

    void pwmInit(void)
    {
    uint32_t pwmFrequencyInHz = DEFAULT_PWM_FREQUENCY;
    uint32_t pwmSourceClockInHz = PWM_SRC_CLK_FREQ;

    /*===============================
    1. Clock Setup (Reusing Previous Settings)
    ===============================*/
    // CLOCK_SetDiv(kCLOCK_IpgDiv, 11); // IPG clock = 600MHz / (11+1) = 50MHz
    // CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2); // AHB clock = 600MHz / 3 = 200MHz
    // CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); // IPG clock = 200MHz / 4 = 50MHz

    /*===============================
    2. Pin Configuration (IOMUXC_GPIO_AD_B0_10_FLEXPWM1_PWMA03 -> FlexPWM1_PWMA03)
    ===============================*/
    IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_10_FLEXPWM1_PWMA03, 0U);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_10_FLEXPWM1_PWMA03, 0x10B0U);

    /*===============================
    3. XBARA Configuration (Disable Fault Inputs)
    ===============================*/
    XBARA_Init(XBARA1);
    XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault0);
    XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1Fault1);
    XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1234Fault2);
    XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, kXBARA1_OutputFlexpwm1234Fault3);

    /*===============================
    4. FlexPWM Configuration
    pwmConfig.enableDebugMode = false;
    pwmConfig.enableWait = false;
    pwmConfig.reloadSelect = kPWM_LocalReload;
    pwmConfig.clockSource = kPWM_BusClock;
    pwmConfig.prescale = kPWM_Prescale_Divide_1;
    pwmConfig.initializationControl = kPWM_Initialize_LocalSync;
    pwmConfig.forceTrigger = kPWM_Force_Local;
    pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity;
    pwmConfig.reloadLogic = kPWM_ReloadImmediate;
    pwmConfig.pairOperation = kPWM_Independent;
    ===============================*/
    pwm_config_t pwmConfig;
    PWM_GetDefaultConfig(&pwmConfig);

    /*===============================
    PWM Configuration: Independent Mode, 50% Duty Cycle, 20kHz
    ===============================*/
    pwmConfig.enableDebugMode = true; // Enable debug mode
    pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; // Reload after full cycle
    pwmConfig.pairOperation = kPWM_Independent;
    pwmConfig.clockSource = kPWM_BusClock; // Use IPG clock (150MHz)
    pwmConfig.prescale = kPWM_Prescale_Divide_2; // If divide is 1, 150MHz/2000 results in 75000, which exceeds 2-byte 65535, causing incorrect frequency output.

    /*===============================
    Initialize FlexPWM1 Submodule 3
    ===============================*/
    PWM_Init(PWM_BASEADDR, kPWM_Module_3, &pwmConfig);

    /*===============================
    config->faultClearingMode = kPWM_Automatic;
    config->faultLevel = false;
    config->enableCombinationalPath = true;
    config->recoverMode = kPWM_NoRecovery;
    ===============================*/
    pwm_fault_param_t faultConfig;

    PWM_FaultDefaultConfig(&faultConfig);

    PWM_SetupFaults(PWM_BASEADDR, kPWM_Fault_3, &faultConfig);

    PWM_OutputTriggerEnable(PWM_BASEADDR, kPWM_Module_3, kPWM_ValueRegister_3, true);

    /*===============================
    ===============================*/
    pwm_signal_param_t pwmSignal;
    pwmSignal.pwmChannel = kPWM_PwmA; // Use Channel A
    pwmSignal.level = kPWM_HighTrue; // High True output
    pwmSignal.dutyCyclePercent = 50; // 50% duty cycle
    pwmSignal.faultState = kPWM_PwmFaultState0;
    pwmSignal.pwmchannelenable = true;

    PWM_SetupPwm(PWM_BASEADDR, kPWM_Module_3, &pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz);

    PWM_EnableDMAWrite(PWM_BASEADDR, kPWM_Module_3, true);

    // Start PWM
    PWM_SetPwmLdok(PWM_BASEADDR, kPWM_Control_Module_3, true);
    PWM_StartTimer(PWM_BASEADDR, kPWM_Control_Module_3);
    }

  2. DMA Initialization and Callback Function

    void dmaInit(void)
    {
    edma_config_t dmaConfig;
    edma_transfer_config_t transferConfig;

    // DMAMUX Initialization
    DMAMUX_Init(DMAMUX);
    DMAMUX_SetSource(DMAMUX, 0, kDmaRequestMuxFlexPWM1ValueSub3);
    DMAMUX_EnableChannel(DMAMUX, 0);

    // DMA Initialization
    EDMA_GetDefaultConfig(&dmaConfig);
    dmaConfig.enableContinuousLinkMode = true;
    dmaConfig.enableRoundRobinArbitration = true;
    EDMA_Init(DMA0, &dmaConfig);
    EDMA_CreateHandle(&g_edmaHandle, DMA0, 0);
    EDMA_SetCallback(&g_edmaHandle, DMA_Callback, NULL);

    // DMA Transfer Configuration (Transfer data to PWM VALx register)
    EDMA_PrepareTransfer(&transferConfig,
    pwmDutyBuffer, 2,
    (void *)&PWM_BASEADDR->SM[kPWM_Module_3].VAL3, 2,
    2, sizeof(pwmDutyBuffer),
    kEDMA_MemoryToPeripheral);

    EDMA_SetModulo(DMA0, 0, kEDMA_Modulo32bytes, kEDMA_ModuloDisable);

    EDMA_SubmitTransfer(&g_edmaHandle, &transferConfig);
    EDMA_StartTransfer(&g_edmaHandle);
    EDMA_EnableChannelRequest(DMA0, 0);

    // Second DMA channel for LDOK setting (optional)
    // Additional DMA channel for setting MCTRL[LDOK]
    }

    void DMA_Callback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
    {
    if (transferDone)
    {
    // Set LDOK bit
    PWM_SetPwmLdok(PWM_BASEADDR, kPWM_Control_Module_3, true);
    }
    }


    Could you please review the source code? It is not working as expected.

0 Kudos
Reply
3 Replies

302 Views
Habib_MS
NXP Employee
NXP Employee

Hello @pooisonner,
To better assist you, could you please provide the following details?

  • When you mentioned "The code is not working as expected", could you clarify what behavior you are observing? For example:
    • Is the PWM not functioning?
    • Does the DMA interrupt fail to trigger?
    • Are there any error messages or unexpected outputs?
  • What is the intended functionality of your application?
  • What is the current value of PWM_BASEADDR?
  • Could you share the declaration of pwmDutyBuffer?

BR
Habib

0 Kudos
Reply

298 Views
pooisonner
Contributor III

1. PWM is operating.
However, it only operates once, and the DMA callback occurs once and does not occur again afterward.
There are no other error messages.

2. I am experimenting with PWM duty control using DMA.

3. PWM_Base is PWM1, and it is outputting through submodule 3.

4. The PWM duty buffer is
uint16_t pwmDutyBuffer[10] = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}; // Example: Duty cycle values

Please respond.

0 Kudos
Reply

39 Views
Habib_MS
NXP Employee
NXP Employee

Hello @pooisonner,

It appears the problem stems from the way g_edmaHandle is currently being instantiated. Right now, you're creating g_edmaHandle inside the dmaInit function. This means that the memory allocated and configured for g_edmaHandle is local to that function and gets discarded once dmaInit completes execution. As a result, any values set within g_edmaHandle are lost.

This behavior is evident in the first two transfers:

First transfer (Works correctly):

image_DMA.jpg

Second transfer (Fails due to missing or incorrect parameters):

image_DMA2.jpg

To resolve this, please declare g_edmaHandle as a global variable. This will ensure that its configuration persists beyond the scope of dmaInit, maintaining the integrity of the EDMA handle across multiple transfers.

BR
Habib

0 Kudos
Reply