Why is K32L2A41 LPTMR always in overflow mode?

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Why is K32L2A41 LPTMR always in overflow mode?

ソリューションへジャンプ
1,034件の閲覧回数
bobpaddock
Senior Contributor III

I am trying to use the LPTMRs of the K32L2A41 to toggle an LED in this example.
To the best of my knowledge the code below follows the same register initialization sequence as the SDK example.

The problem that I'm having is that no matter what I sent the compare value to, or what mode I sent the TFC bit (controls match or overflow) I always get a timeout on overflow and never compare match.

Using the LPO clock of 1 KHz a timeout value of 65536 (overflow) works out to be every 66 seconds and that is what I'm seeing on the terminal.

What am I doing wrong here?:

#include "K32L2A41A.h"

/*
* The LPTMR interrupt is generated asynchronously to the system clock
* and can be used to generate a wakeup from any low-power mode,
* including the low-leakage modes, provided the LPTMR is enabled as a
* wakeup source
*/
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR0_IRQHandler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR0_IRQHandler( void ) /* LPTMR0 */
{
LPTMR0->CSR |= LPTMR_CSR_TFC_MASK; /* Clear IRQ flag W1C */

CPU_LED1G_TOGGLE(); /* SWD_DIO */

/* Output RTC timestamp on the terminal: */
uint8_t *str_ptr_u8, string_u8[ 256U ];
str_ptr_u8 = string_u8;
*str_ptr_u8++ = '\r';
*str_ptr_u8++ = '\n';
*str_ptr_u8++ = '0';
*str_ptr_u8++ = ' ';

(void) rtc_date_time_ts_to_string( secs2TimeStamp( seconds_get() ), &str_ptr_u8 );
*str_ptr_u8++ = '\r';
*str_ptr_u8++ = '\n';
*str_ptr_u8++ = 0U;

debug_write_err( (char *) string_u8, strlen( (char *) string_u8 ) );
}

/* This is called via INTMUX0 IRQ0, from INTMUX0_0_IRQHandler(): */
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR1_IRQHandler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR1_IRQHandler( void ) /* LPTMR1 interrupt via INTMUX source IRQ0 */
{
LPTMR1->CSR |= LPTMR_CSR_TFC_MASK; /* Clear IRQ flag W1C */

CPU_LED1R_TOGGLE(); /* SWD_CLK */

uint8_t *str_ptr_u8, string_u8[ 256U ];
str_ptr_u8 = string_u8;
*str_ptr_u8++ = '\r';
*str_ptr_u8++ = '\n';
*str_ptr_u8++ = '1';
*str_ptr_u8++ = ' ';

(void) rtc_date_time_ts_to_string( secs2TimeStamp( seconds_get() ), &str_ptr_u8 );
*str_ptr_u8++ = '\r';
*str_ptr_u8++ = '\n';
*str_ptr_u8++ = 0U;

debug_write_err( (char *) string_u8, strlen( (char *) string_u8 ) );
}

void lptmr_startup( void )
{
uint32_t tmp_u32;

PCC_LPTMR0 = PCC_CLKCFG_CGC( 1U ); /* Enable LPTMx clocks */
PCC_LPTMR1 = PCC_CLKCFG_CGC( 1U );

/*
* When configuring the LPTMR registers, the CSR must be initially
* written with the timer disabled, before configuring the PSR and
* CMR. Then, CSR[TIE] must be set as the last step in the
* initialization. [Should this really say CSR[TEN] as that is what
* the example SDK does?]
*/
LPTMR0->CSR = 0U; /* Reset Low Power Timer (LPTMR) */
LPTMR1->CSR = 0U;
FILE_LINE( LPTMR0->CSR );
FILE_LINE( LPTMR1->CSR );

LPTMR0->CSR = LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C [Adding this made no difference] */
LPTMR1->CSR = LPTMR_CSR_TCF_MASK;
FILE_LINE( LPTMR0->CSR ); // Reads 0x00
FILE_LINE( LPTMR1->CSR ); // Reads 0x00

/* LPTMR1 uses INTMUX, LPTMR0 does not: */
INTMUX0->CHANNEL[0U].CHn_IER_31_0 |= ( 1UL << 0U ); /* LPTMR1 IRQ0 Enable on INTMUX0 Channel zero */

NVIC_EnableIRQ( LPTMR0_IRQn );
NVIC_EnableIRQ( LPTMR1_IRQn );

/*
* fLPTMRmax = 24 MHz.
*
* LPTMRclk DIV_BY: 0:/2 1:/4, 2:/8, 3:16, 4:32, 5:64, 6:128, 7:256,
* 8:512, 9:1024, 10:2048, 11:4096, 12:8192,
* 13:16384, 14:32768, 15:65536.
*
* LPTMR Clock Source: 0:SIRCCLK, 1:LPO, 2:OSC32KCLK, 3:ERCLK [8 MHz Crystal].
*/
tmp_u32 = (LPTMR_PSR_PBYP_MASK | LPTMR_PSR_PRESCALE( 0U ) | LPTMR_PSR_PCS( 1U )); /* 1 KHz from LPO with no prescaler */
LPTMR0->PSR = tmp_u32;
LPTMR1->PSR = tmp_u32;

tmp_u32 = LPTMR0->CSR;

/*! TCF - Timer Compare Flag
* 0b0..The value of CNR is not equal to CMR and increments.
* 0b1..The value of CNR is equal to CMR and increments.
*/
tmp_u32 &= ~LPTMR_CSR_TCF_MASK; /* Clear the TCF bit to avoid clearing the W1C bit when writing back. [Why would it even be set here?] */

/*! TIE - Timer Interrupt Enable
* 0b0.. Timer interrupt disabled.
* 0b1.. Timer interrupt enabled.
*/
tmp_u32 |= LPTMR_CSR_TIE_MASK;

/*! TFC - Timer Free-Running Counter
* 0b0..CNR is reset whenever TCF is set.
* 0b1..CNR is reset on overflow.
*/
// tmp_u32 |= LPTMR_CSR_TFC_MASK; /* [Makes no difference if it is set or not, still counts to overflow] */

LPTMR0->CSR = tmp_u32;
LPTMR1->CSR = tmp_u32;

LPTMR0->CMR = LPTMR_CMR_COMPARE( 2U - 1U );
LPTMR1->CMR = LPTMR_CMR_COMPARE( 16U - 1U );
FILE_LINE( LPTMR0->CMR ); // Reads 0x01
FILE_LINE( LPTMR1->CMR ); // Reads 0x15

tmp_u32 = LPTMR0->CSR;
tmp_u32 &= ~LPTMR_CSR_TCF_MASK;

/*! TEN - Timer Enable
* 0b0..LPTMR is disabled and internal logic is reset.
* 0b1..LPTMR is enabled.
*/
tmp_u32 |= LPTMR_CSR_TEN_MASK;
LPTMR0->CSR = tmp_u32;
LPTMR1->CSR = tmp_u32;

FILE_LINE( tmp_u32 ); // Reads 0x41
FILE_LINE( LPTMR0->CSR ); // Reads 0x41
FILE_LINE( LPTMR1->CSR ); // Reads 0x41
}

0 件の賞賛
返信
1 解決策
1,009件の閲覧回数
bobpaddock
Senior Contributor III

Thank you for the help.
Alas that code made no difference.

Fixing the dyslexic

LPTMR0->CSR |= LPTMR_CSR_TFC_MASK; /* Clear IRQ flag W1C */

for the correct

LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C */

in the IRQ handler did fix the problem.

This is a complete working example for anyone else that might need it:

 

#include "K32L2A41A.h"

void INTMUX0_0_IRQHandler( void ) __attribute__((used, interrupt( "IRQ")));
void INTMUX0_0_IRQHandler( void )
{
uint32_t const im0_vect_u32 = INTMUX0->CHANNEL[0U].CHn_VEC;

if( 0UL != im0_vect_u32 ) /* Ignore spurious IRQs as INTMUX IRQs are not latched */
{
void( *IRQ_ptr )( void ); /* Define pointer to the Muxed IRQ function. [MISRA] */

/*
* Get base of the vector table via the Vector Table
* Offset Register, plus the INTMUX0 vector
* offset: [MISRA] */
uint8_t const*const vector_ptr = ( ( ( uint8_t * ) SCB->VTOR ) + im0_vect_u32 );

#if( __GCC_VERSION__ >= 40700U ) /* GCC 4.7.0 or later */
#pragma GCC diagnostic push
#endif

#pragma GCC diagnostic ignored "-Wcast-align" /* Cast increases required alignment of vector_ptr */

IRQ_ptr = ( void( * )( void ) ) * ( uint32_t * ) vector_ptr; /* Load the handler address */
IRQ_ptr(); /* Call the IRQ handler */

#if( __GCC_VERSION__ >= 40700U ) /* GCC 4.7.0 or later */
#pragma GCC diagnostic pop
#else
#pragma GCC diagnostic error "-Wcast-align"
#endif
}
}

/*
* The LPTMR interrupt is generated asynchronously to the system clock
* and can be used to generate a wakeup from any low-power mode,
* including the low-leakage modes, provided the LPTMR is enabled as a
* wakeup source
*/
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR0_IRQHandler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR0_IRQHandler( void ) /* LPTMR0 */
{
LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C */

CPU_LED1G_TOGGLE(); /* SWD_DIO pin */
}

/* This is called via INTMUX0 IRQ0, from INTMUX0_0_IRQHandler(): */
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR1_IRQHandler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR1_IRQHandler( void ) /* LPTMR1 interrupt via INTMUX source IRQ0 */
{
LPTMR1->CSR |= LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C */

CPU_LED1R_TOGGLE(); /* SWD_CLK pin */
}

void lptmr_startup( void )
{
uint32_t tmp_u32;

PCC_LPTMR0 = PCC_CLKCFG_CGC( 1U ); /* Enable LPTMx clocks */
PCC_LPTMR1 = PCC_CLKCFG_CGC( 1U );

/*
* When configuring the LPTMR registers, the CSR must be initially
* written with the timer disabled, before configuring the PSR and
* CMR. Then CSR[TEN] must be set as the last step in the
* initialization.
*/
LPTMR0->CSR = 0U;/* Disable Low Power Timer (LPTMR) so can configure it */
LPTMR1->CSR = 0U;

/* LPTMR1 uses INTMUX, LPTMR0 does not: */
INTMUX0->CHANNEL[0U].CHn_IER_31_0 |= ( 1UL << 0U ); /* LPTMR1 IRQ0 Enable on INTMUX0 Channel zero */

NVIC_EnableIRQ( LPTMR0_IRQn );
NVIC_EnableIRQ( LPTMR1_IRQn );

/*
* fLPTMRmax = 24 MHz.
*
* LPTMRclk DIV_BY: 0:/2, 1:/4, 2:/8, 3:/16,
* 4:/32, 5:/64, 6:/128, 7:/256,
* 8:/512, 9:/1024, 10:/2048, 11:/4096,
* 12:/8192, 13:/16384, 14:/32768, 15:/65536.
*
* LPTMR Clock Sources: 0:SIRCCLK, 1:LPO, 2:OSC32KCLK, 3:ERCLK [8 MHz Crystal].
*/
tmp_u32 = (LPTMR_PSR_PBYP_MASK | LPTMR_PSR_PRESCALE( 0U ) | LPTMR_PSR_PCS( 1U )); /* 1 KHz from LPO with no prescaler */
LPTMR0->PSR = tmp_u32;
LPTMR1->PSR = tmp_u32;

/* Set the comparison values: */
LPTMR0->CMR = LPTMR_CMR_COMPARE( 16U - 1U );
LPTMR1->CMR = LPTMR_CMR_COMPARE( 64U - 1U );

/*!
*
* Configure LPTMR:
*
* TCF - Timer Compare Flag
* 0b0..The value of CNR is not equal to CMR and increments.
* 0b1..The value of CNR is equal to CMR and increments. W1C
*
* TFC - Timer Free-Running Counter
* 0b0..CNR is reset whenever TCF is set.
* 0b1..CNR is reset on overflow.
*
* TIE - Timer Interrupt Enable
* 0b0..Timer interrupt disabled.
* 0b1..Timer interrupt enabled.
*
* TEN - Timer Enable
* 0b0..LPTMR is disabled and internal logic is reset.
* 0b1..LPTMR is enabled.
*/
tmp_u32 = (LPTMR_CSR_TCF_MASK | LPTMR_CSR_TIE_MASK | LPTMR_CSR_TEN_MASK); /* Clear the TCF flag, Enable the timer interrupt, Enable the timer */
LPTMR0->CSR = tmp_u32;
LPTMR1->CSR = tmp_u32;
}

 

元の投稿で解決策を見る

0 件の賞賛
返信
3 返答(返信)
1,015件の閲覧回数
Celeste_Liu
NXP Employee
NXP Employee

Hello @bobpaddock ,

Thanks for your post.

Please try the following modifications:
Before setting the CMR, make sure the timer is disabled. This avoids the timer starting to count before the comparison value is set.
Before setting TEN, clear the TCF flag again to ensure the flag bit is cleared correctly.
Set the TFC bit to 0 so that the counter resets when there is a compare match, not when an overflow occurs.

void lptmr_startup( void )
{
    uint32_t tmp_u32;

    PCC_LPTMR0 = PCC_CLKCFG_CGC( 1U );/* Enable LPTMx clocks */
    PCC_LPTMR1 = PCC_CLKCFG_CGC( 1U );

    LPTMR0->CSR = 0U;/* Reset Low Power Timer (LPTMR) */
    LPTMR1->CSR = 0U;

    LPTMR0->CSR = LPTMR_CSR_TCF_MASK; // Clear IRQ flag
    LPTMR1->CSR = LPTMR_CSR_TCF_MASK;

    /* LPTMR1 uses INTMUX, LPTMR0 does not: */
    INTMUX0->CHANNEL[0U].CHn_IER_31_0 |= ( 1UL << 0U ); // LPTMR1 IRQ0 Enable on INTMUX0 Channel zero
    NVIC_EnableIRQ( LPTMR0_IRQn );
    NVIC_EnableIRQ( LPTMR1_IRQn );

    // set LPTMR clock source and prescaler
    tmp_u32 = (LPTMR_PSR_PBYP_MASK | LPTMR_PSR_PRESCALE( 0U ) | LPTMR_PSR_PCS( 1U )); // 1 KHz from LPO with no prescaler
    LPTMR0->PSR = tmp_u32;
    LPTMR1->PSR = tmp_u32;

    // Set the comparison value
    LPTMR0->CMR = LPTMR_CMR_COMPARE( 2U - 1U );
    LPTMR1->CMR = LPTMR_CMR_COMPARE( 16U - 1U );

    // Configure the CSR register
    tmp_u32 = LPTMR0->CSR;
    tmp_u32 &= ~LPTMR_CSR_TCF_MASK; // Clear the TCF flag
    tmp_u32 |= LPTMR_CSR_TIE_MASK;  // Enable the timer interrupt
    tmp_u32 &= ~LPTMR_CSR_TFC_MASK; // Set TFC to 0 to make the counter reset upon a compare match.
    LPTMR0->CSR = tmp_u32;
    LPTMR1->CSR = tmp_u32;

    // Enable the timer
    tmp_u32 = LPTMR0->CSR;
    tmp_u32 &= ~LPTMR_CSR_TCF_MASK;
    tmp_u32 |= LPTMR_CSR_TEN_MASK;
    LPTMR0->CSR = tmp_u32;
    LPTMR1->CSR = tmp_u32;
}


After making these changes, test whether the LPTMR works properly.

Hope it can help you.

BRs,

Celeste

0 件の賞賛
返信
1,010件の閲覧回数
bobpaddock
Senior Contributor III

Thank you for the help.
Alas that code made no difference.

Fixing the dyslexic

LPTMR0->CSR |= LPTMR_CSR_TFC_MASK; /* Clear IRQ flag W1C */

for the correct

LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C */

in the IRQ handler did fix the problem.

This is a complete working example for anyone else that might need it:

 

#include "K32L2A41A.h"

void INTMUX0_0_IRQHandler( void ) __attribute__((used, interrupt( "IRQ")));
void INTMUX0_0_IRQHandler( void )
{
uint32_t const im0_vect_u32 = INTMUX0->CHANNEL[0U].CHn_VEC;

if( 0UL != im0_vect_u32 ) /* Ignore spurious IRQs as INTMUX IRQs are not latched */
{
void( *IRQ_ptr )( void ); /* Define pointer to the Muxed IRQ function. [MISRA] */

/*
* Get base of the vector table via the Vector Table
* Offset Register, plus the INTMUX0 vector
* offset: [MISRA] */
uint8_t const*const vector_ptr = ( ( ( uint8_t * ) SCB->VTOR ) + im0_vect_u32 );

#if( __GCC_VERSION__ >= 40700U ) /* GCC 4.7.0 or later */
#pragma GCC diagnostic push
#endif

#pragma GCC diagnostic ignored "-Wcast-align" /* Cast increases required alignment of vector_ptr */

IRQ_ptr = ( void( * )( void ) ) * ( uint32_t * ) vector_ptr; /* Load the handler address */
IRQ_ptr(); /* Call the IRQ handler */

#if( __GCC_VERSION__ >= 40700U ) /* GCC 4.7.0 or later */
#pragma GCC diagnostic pop
#else
#pragma GCC diagnostic error "-Wcast-align"
#endif
}
}

/*
* The LPTMR interrupt is generated asynchronously to the system clock
* and can be used to generate a wakeup from any low-power mode,
* including the low-leakage modes, provided the LPTMR is enabled as a
* wakeup source
*/
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR0_IRQHandler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR0_IRQHandler( void ) /* LPTMR0 */
{
LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C */

CPU_LED1G_TOGGLE(); /* SWD_DIO pin */
}

/* This is called via INTMUX0 IRQ0, from INTMUX0_0_IRQHandler(): */
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR1_IRQHandler( void ) __attribute__((used, interrupt("IRQ")));
void ATTR_NO_INSTRUMENT_FUNCTION LPTMR1_IRQHandler( void ) /* LPTMR1 interrupt via INTMUX source IRQ0 */
{
LPTMR1->CSR |= LPTMR_CSR_TCF_MASK; /* Clear IRQ flag W1C */

CPU_LED1R_TOGGLE(); /* SWD_CLK pin */
}

void lptmr_startup( void )
{
uint32_t tmp_u32;

PCC_LPTMR0 = PCC_CLKCFG_CGC( 1U ); /* Enable LPTMx clocks */
PCC_LPTMR1 = PCC_CLKCFG_CGC( 1U );

/*
* When configuring the LPTMR registers, the CSR must be initially
* written with the timer disabled, before configuring the PSR and
* CMR. Then CSR[TEN] must be set as the last step in the
* initialization.
*/
LPTMR0->CSR = 0U;/* Disable Low Power Timer (LPTMR) so can configure it */
LPTMR1->CSR = 0U;

/* LPTMR1 uses INTMUX, LPTMR0 does not: */
INTMUX0->CHANNEL[0U].CHn_IER_31_0 |= ( 1UL << 0U ); /* LPTMR1 IRQ0 Enable on INTMUX0 Channel zero */

NVIC_EnableIRQ( LPTMR0_IRQn );
NVIC_EnableIRQ( LPTMR1_IRQn );

/*
* fLPTMRmax = 24 MHz.
*
* LPTMRclk DIV_BY: 0:/2, 1:/4, 2:/8, 3:/16,
* 4:/32, 5:/64, 6:/128, 7:/256,
* 8:/512, 9:/1024, 10:/2048, 11:/4096,
* 12:/8192, 13:/16384, 14:/32768, 15:/65536.
*
* LPTMR Clock Sources: 0:SIRCCLK, 1:LPO, 2:OSC32KCLK, 3:ERCLK [8 MHz Crystal].
*/
tmp_u32 = (LPTMR_PSR_PBYP_MASK | LPTMR_PSR_PRESCALE( 0U ) | LPTMR_PSR_PCS( 1U )); /* 1 KHz from LPO with no prescaler */
LPTMR0->PSR = tmp_u32;
LPTMR1->PSR = tmp_u32;

/* Set the comparison values: */
LPTMR0->CMR = LPTMR_CMR_COMPARE( 16U - 1U );
LPTMR1->CMR = LPTMR_CMR_COMPARE( 64U - 1U );

/*!
*
* Configure LPTMR:
*
* TCF - Timer Compare Flag
* 0b0..The value of CNR is not equal to CMR and increments.
* 0b1..The value of CNR is equal to CMR and increments. W1C
*
* TFC - Timer Free-Running Counter
* 0b0..CNR is reset whenever TCF is set.
* 0b1..CNR is reset on overflow.
*
* TIE - Timer Interrupt Enable
* 0b0..Timer interrupt disabled.
* 0b1..Timer interrupt enabled.
*
* TEN - Timer Enable
* 0b0..LPTMR is disabled and internal logic is reset.
* 0b1..LPTMR is enabled.
*/
tmp_u32 = (LPTMR_CSR_TCF_MASK | LPTMR_CSR_TIE_MASK | LPTMR_CSR_TEN_MASK); /* Clear the TCF flag, Enable the timer interrupt, Enable the timer */
LPTMR0->CSR = tmp_u32;
LPTMR1->CSR = tmp_u32;
}

 

0 件の賞賛
返信
1,005件の閲覧回数
Celeste_Liu
NXP Employee
NXP Employee

Sorry for not helping you and thanks for sharing the correct answer.

0 件の賞賛
返信