SDK Multiple TPMs Don't Work

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

SDK Multiple TPMs Don't Work

Jump to solution
1,714 Views
bcstewart
Contributor III

I am using KL27Z256 48-pin QFN, Keil Tools, SDK 2.2.  

I have implemented TPM1Ch0 to trigger DMA from memory to DAC.

I used PWM example in SDK 2.2.  The timer drives the DMA and produces a PWM output on a pin.  It works.

Now I want to add another timer, TPM2ch0.  It is a simple timer with no outputs to pins.  I don't see any examples on using two separate TPM units, only one TPM and two channels.

When I try to set up TPM2, it causes failure with the DMA.  It happens right after 

TPM_SetTimerPeriod(BOARD_TPM2_BASEADDR, USEC_TO_COUNT(29000U, TPM_SOURCE_CLOCK));

or

TPM_SetupPwm(BOARD_TPM2_BASEADDR, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 24000U, TPM_SOURCE_CLOCK);

Where can I find an example SDK that uses two TPM units (TPM1 and TPM2)?

Tags (4)
0 Kudos
1 Solution
1,312 Views
jorge_a_vazquez
NXP Employee
NXP Employee

Hi BC Stewart

Sorry for the late reply, I was out of Office. we have checked your code and found the problem:

This is not a multiple TPM related problem, this is more related with the execution time and the TPM1 that is already counting when you setup DMAMUX, let me explain, in your code:

TPM_StartTimer(TPM1, kTPM_SystemClock);


/* Configure tpm 2 channel 0 params with frequency 24kHZ */
     //TPM_GetDefaultConfig(&tpmInfo);
     TPM_Init(TPM0, &tpmInfo);
     // PROBLEM:  next line kills DAC output unless I change source in dmamux.  Why?
     TPM_SetupPwm(TPM0, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 22050U, TPM_SOURCE_CLOCK);
//TPM2->CONTROLS[0].CnSC |= 1u ;// set DMA enable

     TPM_StartTimer(TPM0, kTPM_SystemClock);
     TPM_UpdatePwmDutycycle(TPM0,kTPM_Chnl_0, kTPM_EdgeAlignedPwm,50U);  //set up for 50% duty cycle

//set up DMA MUX--not sure how to set up for PIT
     DMAMUX_Init(DMAMUX0);
     DMAMUX_SetSource(DMAMUX0, 0 ,kDmaRequestMux0TPM1Channel0);  //will be using TPM2 channel 0, 
     DMAMUX_EnableChannel(DMAMUX0, 0);  // inline function defined in header file.

Now, as you can see, when try to set DMAMUX, TPM1 is already counting (TPM_StartTimer), this will cause a DMA request before DMAMUX initialization, this will cause problems in subsequent DMA requests.

This is why when you didn't have the TPM0 init part your code works without problem, because the TPM0 initialization (or any other code) consumes time and TPM1 request a DMA transfer before DMA being completely set.

If you start TPM0 timer after you set DMA the problem should disappear, so please locate

TPM_StartTimer(TPM1, kTPM_SystemClock);

After

DMA0->DMA[0].DCR &= ~(1u << 7u);  //clear DREQ

NOTE: you don't need line NVIC_EnableIRQ(DMA0_IRQn); because NVIC is set in the DMA_CreateHandle(&g_DMA_Handle, DMA0, 0); line

Hope this could resolve your problem.
Have a great day,
Jorge Alcala

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

View solution in original post

9 Replies
1,312 Views
jorge_a_vazquez
NXP Employee
NXP Employee

Hi BC Stewart 

Could you share how are you setting up the second TPM, there shouldn't be any problem with the if you set the TPM as you set it in the TPM1, the basic code two use two TPM is:

    tpmParam.chnlNumber = 0;
    tpmParam.level = kTPM_LowTrue;
    tpmParam.dutyCyclePercent = updatedDutycycle;

TPM_GetDefaultConfig(&tpmInfo);

/* Initialize TPM module */
TPM_Init(TPM1, &tpmInfo);

TPM_Init(TPM2, &tpmInfo);

TPM_SetupPwm(TPM1, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 24000U, TPM_SOURCE_CLOCK);

TPM_SetupPwm(TPM2, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 24000U, TPM_SOURCE_CLOCK);

TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock);

TPM_StartTimer(TPM2, kTPM_SystemClock);

then, for the PWM update you can use TPM_UpdatePwmDutycycle.

Now, if you are using DMA, please remember that your data and descriptors need to be aligned, if not, dma will not made transfers.

Hope this could help, please let me know if you have any question about this.
Best Regards

Jorge Alcala

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,311 Views
bcstewart
Contributor III

Update:  when the failure happens, the program never reaches the for(;;)

loop.

Also please note that I never had these problems with KL25 or K22F using PE.

--Brad

0 Kudos
1,312 Views
gerardo_rodriguez
NXP Employee
NXP Employee

Hello Brad,

I'm trying to replicate your issue on a FRDM-KL43Z (same mask as KL27Z256) with the code you shared and I think I'm seeing the same behavior as you. When the second TPM instance is configured, the DMA seems to get stuck in the interrupt and the execution never reaches the infinite loop. I'll investigate what could be causing this behavior and see how this can be fixed.

Regards,

Gerardo

0 Kudos
1,312 Views
bcstewart
Contributor III

Any updates?  

0 Kudos
1,313 Views
jorge_a_vazquez
NXP Employee
NXP Employee

Hi BC Stewart

Sorry for the late reply, I was out of Office. we have checked your code and found the problem:

This is not a multiple TPM related problem, this is more related with the execution time and the TPM1 that is already counting when you setup DMAMUX, let me explain, in your code:

TPM_StartTimer(TPM1, kTPM_SystemClock);


/* Configure tpm 2 channel 0 params with frequency 24kHZ */
     //TPM_GetDefaultConfig(&tpmInfo);
     TPM_Init(TPM0, &tpmInfo);
     // PROBLEM:  next line kills DAC output unless I change source in dmamux.  Why?
     TPM_SetupPwm(TPM0, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 22050U, TPM_SOURCE_CLOCK);
//TPM2->CONTROLS[0].CnSC |= 1u ;// set DMA enable

     TPM_StartTimer(TPM0, kTPM_SystemClock);
     TPM_UpdatePwmDutycycle(TPM0,kTPM_Chnl_0, kTPM_EdgeAlignedPwm,50U);  //set up for 50% duty cycle

//set up DMA MUX--not sure how to set up for PIT
     DMAMUX_Init(DMAMUX0);
     DMAMUX_SetSource(DMAMUX0, 0 ,kDmaRequestMux0TPM1Channel0);  //will be using TPM2 channel 0, 
     DMAMUX_EnableChannel(DMAMUX0, 0);  // inline function defined in header file.

Now, as you can see, when try to set DMAMUX, TPM1 is already counting (TPM_StartTimer), this will cause a DMA request before DMAMUX initialization, this will cause problems in subsequent DMA requests.

This is why when you didn't have the TPM0 init part your code works without problem, because the TPM0 initialization (or any other code) consumes time and TPM1 request a DMA transfer before DMA being completely set.

If you start TPM0 timer after you set DMA the problem should disappear, so please locate

TPM_StartTimer(TPM1, kTPM_SystemClock);

After

DMA0->DMA[0].DCR &= ~(1u << 7u);  //clear DREQ

NOTE: you don't need line NVIC_EnableIRQ(DMA0_IRQn); because NVIC is set in the DMA_CreateHandle(&g_DMA_Handle, DMA0, 0); line

Hope this could resolve your problem.
Have a great day,
Jorge Alcala

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

1,312 Views
bcstewart
Contributor III

Yes.  You are seeing the same thing I saw--the program is stuck in the DMA interrupt handler and never reaches the main infinite loop.

0 Kudos
1,312 Views
vicentegomez
NXP TechSupport
NXP TechSupport

Hi Brad

Today is holiday in MX

Tomorrow we will answer you.

Regards

Vicente Gomez

0 Kudos
1,312 Views
bcstewart
Contributor III

OK.

Have a good "Dia de la Revolucion".

Brad

0 Kudos
1,312 Views
bcstewart
Contributor III

Hello Jorge,

I am doing what you describe.

I am using TPM1Ch0 to drive a PWM output which is filtered and applied

to DAC Vrefh (multiplying DAC function).  It also triggers the DMA to

transfer buffer &data to the DAC in a continuous loop (for audio

output).  The value read by the ADC sets the output level by modifying

the PWM (see function in the main for(;;) loop).

It works as designed until I try to enable TPM2Ch0. (I also tried

TPM0Ch0 with same results).

This line #108 causes the failure:

TPM_SetupPwm(TPM2, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 22050U,

TPM_SOURCE_CLOCK);

I still get DMA interrupts, but no output on the DAC.  The TPM2

registers seem to contain the correct initial values.

What is very strange is that if I manually change DMAMUX0 CHCFG0_SOURCE

in the debugger from 0x20 to 0x22, then back to 0x20, it works! 

(program is halted between changing the value).  Is this a hardware bug?

Also note that the SDK does not set the DMA DCR register.  I had to do

this manually.

Attached is my code.

Brad

0 Kudos