KL25Z DMA With TPM Problems

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

KL25Z DMA With TPM Problems

Jump to solution
1,118 Views
gordondoughman
Contributor III

I have a project where I am attempting to use the TPM, configured for edge aligned PWM, to produce a series of 24 timed pulses, using the DMA to write new values to the TPM CnV register for each pulse. I'm having a couple of problems with which I need help.

I have the PWM set up as follows:

TPM1_SC = 0x0008;
TPM1_C0SC = 0x29;
TPM1_MOD = 29;
TPM1_C0V = 0;
SIM_SOPT2 |= 0x01000000; // select MCGPLLCLK/2 for TPM clock.

When the SIM_SOPT2 register is written, a 42 nS pulse (i.e. one TPM module clock) appears on the associated output pin. Does anyone have any ideas why this is happening and how to eliminate it?

 

Second, I have the DMA set up as follows:

const unsigned short DMATable [] = {8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,15,15,15,15,15,15,15,15,0};

 

DMAMUX0_CHCFG0 = 0x00;       // disable DMA channel 0.
DMA_SAR0 = (int)DMATable;    // set up DMA source address register.
DMA_DAR0 = (int)&TPM1_C0V;       // set up DMA destination address register.
DMA_DSR_BCR0 = sizeof(DMATable); // number of bytes to xfer.
DMA_DCR0 = 0x60640080;           // enable peripheral request (ERQ=1)
                                 // cycle steal (CS=1)
                                 // auto-align (AA=0)
                                 // source increment (SINC=1)
                                 // source size 16-bit (SSIZE=10)
                                 // destination increment (DINC=0)
                                 // destination size 16-bit (SSIZE=10),
                                // Disable request (D_REQ=1)
DMAMUX0_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK | TPM1Ch0Slot; // enable DMA channel 0 for TPM1 channel 0.

As the DMATable shows, 16 pulses, 8 TPM module clocks wide followed by 8 pulses, 15 TPM module clocks wide should appear on the associated TPM pin. Finally, the DMA transfers a value of zero to C0V to have the PWM output remain at zero. However, instead of 16 pulses 8 TPM module clocks wide, only 15 pulses are appearing, followed by the 8 longer pulses.

 

Does anyone have any ideas what might be going on here?

Labels (2)
0 Kudos
1 Solution
1,092 Views
gordondoughman
Contributor III

I found the solution to both problems.

 

For the errant 42 nS pulse on the associated PWM pin, the I/O pin associated with TPM1 channel 0 should not be enabled until AFTER the TPM is initialized. There’s absolutely nothing in the Reference Manual that I could find that indicates this is the case, but it fixed the problem. So, my code in main() was changed to:

 

InitMCG();
EnableModuleClocks();
InitTPM();
InitIOPorts();
InitDMA();

 

The issue with the DMA was about as subtle. The CHF flag in the TPM is set when a "event" occurs. For a channel configured as EPWM, this happens when the counter matches the value in CnV. Apparently, the TPM, even when initialized with a 0% duty cycle ends up setting the Channel Flag (CHF) in the TPMx_CnSC register. Evidently this creates an “extra” DMA request and write to the CnV register immediately after enabling the DMA channel. Clearing this flag just before enabling the DMA channel fixed the problem! So the DMA init code becomes:

 

DMAMUX0_CHCFG0 = 0x00;              // disable DMA channel 0.
DMA_SAR0 = (int)DMATable;           // set up DMA source address register.
DMA_DAR0 = (int)&TPM1_C0V;          // set up DMA destination address reg.
DMA_DSR_BCR0 = sizeof(DMATable);    // number of bytes to xfer.
DMA_DCR0 = 0x60640080;              // enable peripheral request (ERQ=1)
                                    // cycle steal (CS=1)
                                    // auto-align (AA=0)
                                    // source increment (SINC=1)
                                    // source size 16-bit (SSIZE=10)
                                    // destination increment (DINC=0)
                                    // destination size 16-bit (SSIZE=10),
                                    // Disable request (D_REQ=1)
TPM1_C0SC |= 0x80;                  // clear the CHF flag before enabling DMA.
DMAMUX0_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK | TPM1Ch0Slot; // enable DMA channel 0 for TPM1 channel 0.

View solution in original post

0 Kudos
4 Replies
1,093 Views
gordondoughman
Contributor III

I found the solution to both problems.

 

For the errant 42 nS pulse on the associated PWM pin, the I/O pin associated with TPM1 channel 0 should not be enabled until AFTER the TPM is initialized. There’s absolutely nothing in the Reference Manual that I could find that indicates this is the case, but it fixed the problem. So, my code in main() was changed to:

 

InitMCG();
EnableModuleClocks();
InitTPM();
InitIOPorts();
InitDMA();

 

The issue with the DMA was about as subtle. The CHF flag in the TPM is set when a "event" occurs. For a channel configured as EPWM, this happens when the counter matches the value in CnV. Apparently, the TPM, even when initialized with a 0% duty cycle ends up setting the Channel Flag (CHF) in the TPMx_CnSC register. Evidently this creates an “extra” DMA request and write to the CnV register immediately after enabling the DMA channel. Clearing this flag just before enabling the DMA channel fixed the problem! So the DMA init code becomes:

 

DMAMUX0_CHCFG0 = 0x00;              // disable DMA channel 0.
DMA_SAR0 = (int)DMATable;           // set up DMA source address register.
DMA_DAR0 = (int)&TPM1_C0V;          // set up DMA destination address reg.
DMA_DSR_BCR0 = sizeof(DMATable);    // number of bytes to xfer.
DMA_DCR0 = 0x60640080;              // enable peripheral request (ERQ=1)
                                    // cycle steal (CS=1)
                                    // auto-align (AA=0)
                                    // source increment (SINC=1)
                                    // source size 16-bit (SSIZE=10)
                                    // destination increment (DINC=0)
                                    // destination size 16-bit (SSIZE=10),
                                    // Disable request (D_REQ=1)
TPM1_C0SC |= 0x80;                  // clear the CHF flag before enabling DMA.
DMAMUX0_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK | TPM1Ch0Slot; // enable DMA channel 0 for TPM1 channel 0.

0 Kudos
1,114 Views
bobpaddock
Senior Contributor III

Module clocks should be enabled before configuring modules.

 

0 Kudos
1,099 Views
gordondoughman
Contributor III

Ok, continued to work on the errant 42 nS pulse issue, I was able to fix the problem by NOT initializing the I/O Ports until after configuring the TPM. In main() the calls were rearranged to:

InitMCG();           // initialize the MCG to use the external 8MHz crystal.
EnableModuleClocks(); // enable clocks to all modules we'll use.
InitTPM();          // initialize the TPM for edge aligned mode.
InitIOPorts();      // go initialize the I/O ports we'll use.
InitDMA();

Where InitIOPorts() contains the following line:

PORTA_PCR12 = 0x00000300; // put TPM1_CH0 out on pin PTA12.

I'm not sure why this is required to prevent a "glitch" on the associated TPM pin. I couldn't find anything in the KL25Z Reference Manual stating this requirement.

 

Still having the DMA issue and would appreciate any suggestions.

 

0 Kudos
1,106 Views
gordondoughman
Contributor III

I've tried that and it still generates the 42 nS pulse on the output pin. I moved the line:

SIM_SOPT2 |= 0x01000000; // select MCGPLLCLK/2 for TPM clock.

to the function EnableModuleClocks() which is called in main() before the call to InitTPM().

Any other suggestions?

0 Kudos