Can't use LPTMR0 on teensy 3.0.

Status
Not open for further replies.

ancc

Member
Hello.

I want to use LPTMR0 timer in my project, but when I try to read any LPTMR0 register board hangs.

for example I loaded simple blink sketch and inserted there something like

x = LPTMR0_CNR; at the end of the main loop.

Sketch is compiling and uploading as usual, but after restart board blinks one time and stops blinking.

Is it possible to use this timer, or may be another way for me? I need simple free running 16bit counter with prescaler, no interrupts needed.

I'm using Arduino 1.0.5 and teeensyduino 1.17
 
Isn't LPTMR0_CNR concerned with power conservation/wakeup and interrupts? Unreladed to timers?


could you use
Code:
short x;
x = (short)millis();
//or 
x = (short)micros();
to get 16 bits?
 
Last edited:
Isn't LPTMR0_CNR concerned with power conservation/wakeup and interrupts? Unreladed to timers?


could you use
Code:
short x;
x = (short)millis();
//or 
x = (short)micros();
to get 16 bits?

I'm now trying to adapt one library from AVR to teensy3. When I failed when LPTMR I begin to rewright this library to work with micros() but It was a bad idea.
 
Now the board is working. But when reading LPTMR0_CNR register I got "0" every time. Other registers of LPTMR0 is reading correctly.

Here is my config of this timer. I need to set prescaler to 8, no interrupts

LPTMR0_PSR = 0x10;
LPTMR0_CSR = 0x05;

What I'm doing wrong?
 
Try this, although trying to read LPTMR0_CNR will likely still read 0, it will trigger the interrupt at the period you specify in compare_value.

Code:
int compare_value;

void setup(){
  
  compare_value = 500;
  
  pinMode(5, OUTPUT);
  INIT_LPTMR_INT();

}

void loop(){
  asm("WFI");
}

void lptmr_isr(){
  digitalWriteFast(5, !digitalRead(5));
  LPTMR0_CSR|=LPTMR_CSR_TCF_MASK;  //Clear LPT Compare flag
}

void INIT_LPTMR_INT(){
  

  /* Enable LPT Module */
  SIM_SCGC5 |= SIM_SCGC5_LPTIMER;

  /* Reset LPTMR registers */
  lptmr_clear_registers();

  /* Configure LPT */
  LPTMR0_CMR=LPTMR_CMR_COMPARE(compare_value);  //Set compare value
  LPTMR0_PSR=LPTMR_PSR_PCS(0x1)|LPTMR_PSR_PBYP_MASK;  //Use LPO clock and bypass prescale
  LPTMR0_CSR=LPTMR_CSR_TIE_MASK;  //Enable LPT interrupt

  /* Enable LPT Interrupt in NVIC */
  NVIC_ENABLE_IRQ(IRQ_LPTMR); 

  LPTMR0_CSR|=LPTMR_CSR_TEN_MASK; 
}
 
I ran into this problem today.

Turns out there's an undocumented synchronism mechanism. You write zero (or probably any value) to LPTMR0_CNR to cause it to acquire a new reading from the actual counter (which runs asynchronously from the main CPU & peripheral bus).

The datasheet talks about reading LPTMR0_CNR multiple times and checking for 2 in a row that match. That probably applies to some older version. The one in Teensy 3.1 definitely has the write-to-sync mechanism, despite Freescale's documentation.
 
FYI
The other anomaly I have observed is that it is not possible to clear the interrupt TCF flag without disabling the LPTMR0. The reference manual suggests you can clear that flag by just writing a 1 to it. Didn't work for me. In Paul's entropy library ISR, he uses two steps to clear the interrupt
Code:
void lptmr_isr(void)
{
  LPTMR0_CSR = 0b10000100;
  LPTMR0_CSR = 0b01000101;
  isr_hardware_neutral(SYST_CVR);
}
 
Last edited:
LPTMR0 on Teensy-LC

Does LPTMR not work with the PLL clock (48MHz, Teensy-LC)? I have this code:

Code:
volatile uint32_t countdown;

void
delay_ms( uint32_t ms )
{
    SIM_SCGC5 |= SIM_SCGC5_LPTMR(1);
    
    LPTMR0_CSR = 0;						// Reset / disable LPTMR0

    NVIC_EnableIRQ( LPTMR0_IRQn );
    
    LPTMR0_CNR = 0;						// Clear counter (not possible?)
    LPTMR0_CMR = 48000;                 // Clock is 48MHz, so compare @ 48000 == 1mS
    LPTMR0_PSR = (LPTMR_PSR_PBYP(1) |   // Bypass prescaler, clock 0 selected
                  LPTMR_PSR_PCS(0));	// Select clock 0
    LPTMR0_CSR = (LPTMR_CSR_TCF_MASK |
                  LPTMR_CSR_TIE(1) |
                  LPTMR_CSR_TPS(0b00) |
                  LPTMR_CSR_TPP(0) |
                  LPTMR_CSR_TFC(0) |
                  LPTMR_CSR_TMS(0) |
                  LPTMR_CSR_TEN(1));

    
    for (countdown = ms; countdown; ) ;

    NVIC_DisableIRQ( LPTMR0_IRQn );
    LPTMR0_CSR = 0;
}

void __attribute__(( interrupt ))
lptmr_isr( void )
{
    GPIOC->PTOR = (1 << 5);
    if (countdown) {
        --countdown;
    } else {
        LPTMR0_CSR = 0;
    }
}

But PC5 (LED) never wiggles...
 
post #9 above would suggest it takes two steps to clear the interrupt, and those steps should be done unconditionally (outside the if/else) in your isr. i don't have an LC handy to test your sketch ...
 
I just put in a poor-man's breakpoint ("while (1) GPIOC->PTOR = (1 << 5);") in the ISR, and it never gets there. There's not even one interrupt happening.
 
...and there it is: you have to turn on MCGIRCLK...MCG_C1 |= MCG_C1_IRCLKEN(1).

Incidentally, it looks like you can clear the LPTMR F flag by writing 1 to it, as the documentation states. At least on the chip on my Teensy-LC.
 
Status
Not open for further replies.
Back
Top