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
}