cancel
Showing results for 
Search instead for 
Did you mean: 

LPTIM Multiple odd behaviours

JustSomeGuy
Senior

I am writing an LPTIM driver without HAL or LL drivers on the B-L072Z-LRWAN1 board. I have been getting a number of odd behaviours here that I am hoping someone here can shed some light on.

1) cannot enable continuous start

          -bit 2 of the CR register is never set. I added a bunch of __NOP();s in between enabling the timer and setting continuous start with no success. I have also tried setting both bits together with LPTIM->CR = 0b101U; with no success.

2) ISR only clears every now and then.

          -using the IRQ handler function, the ISR is cleared the first time, and subsequently only clears about once every 5 times afterwards. the IRQ is being called constantly, when CNT = ARR should be true once a minute (Sysclock = MSI = 131072 Hz, PSC DIV = 128, ARR = 60963).

3) other ISR flags are set

          -even though i only set bit 1 (ARRMIE) in the IER register, when the IRQ handler is called, the debugger is telling me that CMPM is also set when entering the IRQ handler.

Here is the relevant code:

 

extern bool TxTimerDone;
extern uint8_t LPTimRollOver;


void LPTIM_Init(LPTIM_TypeDef *LPTIM, lpTimerMode mode, uint16_t period)
{
	uint32_t tmpcfg = 0;
	uint16_t tmpier = 0;

	//Select clock source as APB clock
	RCC->CCIPR &= ~RCC_CCIPR_LPTIM1SEL;

	//enable the oscillator for the peripheral
	RCC->APB1ENR |= RCC_APB1ENR_LPTIM1EN;

	//encoder mode disabled
	tmpcfg &= ~LPTIM_CFGR_ENC;
	//counter mode disabled
	tmpcfg &= ~LPTIM_CFGR_COUNTMODE;
	//preload ARR
	tmpcfg |= LPTIM_CFGR_PRELOAD;
	//set wave polarity.
	tmpcfg &= ~LPTIM_CFGR_WAVPOL;
	tmpcfg &= ~LPTIM_CFGR_WAVE;
	//disable trigger event reset
	tmpcfg &= ~LPTIM_CFGR_TIMOUT;
	//disable hardware triggers
	tmpcfg &= ~LPTIM_CFGR_TRIGEN;
	//clear trigger selection
	tmpcfg &= ~LPTIM_CFGR_TRIGSEL;
	//set prescalar division
	tmpcfg |= LPTIM_PRESCALER_DIV128;
	//clear trig filter settings
	tmpcfg &= ~LPTIM_CFGR_TRGFLT;
	//external clock settings; clear.
	tmpcfg &= ~LPTIM_CFGR_CKFLT;
	//external source clock polarity. not relevant
	tmpcfg &= ~LPTIM_CFGR_CKPOL;
	//clock selection: internal clock
	tmpcfg &= ~LPTIM_CFGR_CKSEL;

	//write the configurations to the register
	LPTIM->CFGR = tmpcfg;

	//set the ARR before enabling interrupts, since an interrupt will be called right away.
	//this mitigates the number of false interrupts called.

	//enable the timer
	LPTIM->CR = LPTIM_CR_ENABLE;

	LPTIM->ARR = period;
        //CMP flag in ISR is being set when it shouldn't be, so set the CMP register to ARR so it doesn't call the IRQ too often.
	LPTIM->CMP = period;

	//disable the timer
	LPTIM->CR = 0;

	//set interrupts to trigger on every ARR match
	if(mode == lptim_mode_interrupt)
	{
		//NVIC_SetVector(LPTIM1_IRQn, (uint32_t)&LPTIM1_IRQ_Handler);
		NVIC_SetPriority(LPTIM1_IRQn, 1);
		NVIC_EnableIRQ(LPTIM1_IRQn);
		//select the interrupt trigger sources
		tmpier |= LPTIM_IER_ARRMIE;
		//write the configurations to the register
		LPTIM->IER = tmpier;
		//set the interrupt vector
	}
}

void LPTIM_Start(LPTIM_TypeDef *LPTIM, uint16_t period)
{
	//enable the timer
	LPTIM->CR = LPTIM_CR_ENABLE;

	//enable continuous mode
	LPTIM->CR |= LPTIM_CR_CNTSTRT;
}

void LPTIM_Stop(LPTIM_TypeDef *LPTIM)
{
	//clear control register, disabling the timer.
	LPTIM->CR &= ~(0b111U);
}

void LPTIM_Set_ARR(LPTIM_TypeDef *LPTIM, uint16_t period)
{
	bool state = true;

	//enable the timer if it is not
	if((LPTIM->CR & LPTIM_CR_ENABLE) != LPTIM_CR_ENABLE)
	{
		//enable the timer
		LPTIM->CR |= LPTIM_CR_ENABLE;
		//toggle a status flag to show that LPTIMER was disabled
		//upon entering this function
		state = false;
	}

	//set the auto reload register
	LPTIM->ARR = period;

	//disable lptimer if it was disabled upon entering the function call.
	if(state == false)
		LPTIM->CR = 0;
}

//this function is called when the LP timer's CNT register = ARR
//in human terms, when the timer has counted up to its set point.
void LPTIM1_IRQHandler(void)
{
	uint16_t timeout = 1000;
	//read registers for debugging purposes
	uint8_t CRRead = LPTIM1->CR;
	uint8_t isrRead = LPTIM1->ISR;

	if(LPTIM1->ISR & LPTIM_ISR_ARRM)
	{
		//clear the interrupt flag register.
		LPTIM1->ICR = 127U;//LPTIM1->ISR;

		//keep track of how many times (minutes) passed.
		LPTimRollOver++;
		//if 'mTxDelay' number of minutes have passed,
		if(LPTimRollOver >= mTxDelay)
		{
			//toggle flag to indicate that the set number of minutes have passed
			TxTimerDone = true;
			LPTimRollOver = 0;
		}
		//if the timer disabled itself due to not being in CNTSRT mode, enable it again
		if((LPTIM1->CR & LPTIM_CR_ENABLE) != LPTIM_CR_ENABLE)
			LPTIM_Start(LPTIM1, LPTIMER_PERIOD);
	}
	//wait for interrupts to be cleared
	while((LPTIM1->ISR != 0) && ((timeout) != 0))
		timeout--;

	//read ISR for debugging
	isrRead = LPTIM1->ISR;
}

 

 and then in the main I have

 

 LPTIM_Init(LPTIM1, lptim_mode_interrupt, LPTIMER_PERIOD);
 LPTIM_Start(LPTIM1, LPTIMER_PERIOD);
 while(1)
 {
 }

 

 

0 REPLIES 0