liam-geotab opened a new pull request, #19959:
URL: https://github.com/apache/nuttx/pull/19959

   ## Summary
   
   Add LPTIM support.
   
   The implementation is based on STM32H7. setperiod and setcompare have been 
made to wait for the auto-reload value to apply before returning.
   
   STM32H5 has 6 LPTIMs. LPTIM2 has an incomplete implementation. It is in a 
different RCC APBx register than the other LPTIMs. Without contact with the 
author, I decided not to assume it's trivial to add without thorough testing so 
I left it as-is. The build fails if LPTIM2 is enabled so it's not a silent gap. 
I can try to add it, if that is the maintainers' wish. Supporting LPTIM6 would 
require the common configs to have LPTIM6 added.
   
   Some STM32H5 RCC definitions have been corrected. It's necessary for the 
clock source selection that a user would do before using the STM32 LPTIM API.
   
   Also add a missing CMakeLists.txt change that should have been in 
https://github.com/apache/nuttx/pull/19914
   
   ## Impact
   
   The changes are only additive except for RCC definition corrections.
   
   LPTIM2 complete implementation is missing. LPTIM6 needs a common config 
added for it.
   
   ## Testing
   
   Nothing in the nuttx tree calls `stm32_lptim_init` so here is how LPTIM has 
been sourced by the LSE (low speed external) clock to be used for the nuttx 
system tick on custom hardware. There is live adjustment of the timer period to 
deal with LSE modulo 100 Hz != 0.
   
   ```
   nsh> uptime
   00:00:03 up  0:00, load average: 0.00, 0.00, 0.00
   nsh> uptime
   00:00:05 up  0:00, load average: 0.00, 0.00, 0.00
   nsh> uptime
   00:26:33 up  0:26, load average: 0.00, 0.00, 0.00
   ```
   
   Enable `CONFIG_STM32_LPTIM1` and override 
arch/arm/src/stm32h5/stm32_timerisr.c or modify it to use LPTIM1 as the tick 
source:
   
   ```c
   #define SYSTICK_RELOAD_EXCESS_DIV    4       //Both CLK_TCK and EXCESS must 
be divisible by this value!
   #define SYSTICK_RELOAD (STM32_LSE_FREQUENCY / CLK_TCK)
   #define SYSTICK_RELOAD_EXCESS (((SYSTICK_RELOAD + 1) * CLK_TCK) - 
STM32_LSE_FREQUENCY)
   #define SYSTICK_RELOAD_REDUCED (SYSTICK_RELOAD - (SYSTICK_RELOAD_EXCESS / 
SYSTICK_RELOAD_EXCESS_DIV))
   #if ((CLK_TCK % SYSTICK_RELOAD_EXCESS_DIV) != 0)
   #error "CLK_TCK not divisible by SYSTICK_RELOAD_EXCESS_DIV"
   #endif
   #if ((SYSTICK_RELOAD_EXCESS % SYSTICK_RELOAD_EXCESS_DIV) != 0)
   #error "SYSTICK_RELOAD_EXCESS not divisible by SYSTICK_RELOAD_EXCESS_DIV"
   #endif
   
   int stm32_timerisr_counter = 0;
   static int stm32_timerisr(int irq, void * regs, void * arg)
   {
        struct stm32_lptim_dev_s * lptimer = arg;
        stm32_timerisr_counter++;
   
        /* Process timer interrupt */
        if (stm32_timerisr_counter >= (CLK_TCK / SYSTICK_RELOAD_EXCESS_DIV))
        {
                stm32_timerisr_counter = 0;
                lptimer->ops->setperiod(lptimer, SYSTICK_RELOAD_REDUCED);
        }
        else if (stm32_timerisr_counter == 1)
        {
                lptimer->ops->setperiod(lptimer, SYSTICK_RELOAD);
        }
   
        nxsched_process_timer();
   
        lptimer->ops->ackint(lptimer, LPTIM_ISR_ARRM | LPTIM_ISR_CMPM);
        return 0;
   }
   
   void up_timer_initialize(void)
   {
        struct stm32_lptim_dev_s * lptimer;
   
        stm32_rcc_enablelse();  //Enable the LSE clock input
   
        // Enable LPTIM1 peripheral clock FIRST before configuring clock source
        modifyreg32(STM32_RCC_APB3ENR, 0, RCC_APB3ENR_LPTIM1EN);
   
        // Now configure clock source to LSE
        modifyreg32(STM32_RCC_CCIPR2, RCC_CCIPR2_LPTIM1SEL_MASK, 
RCC_CCIPR2_LPTIM1SEL_LSEKERCK);        //Set LPTIM1 clock source as LSE
        modifyreg32(STM32_RCC_APB3LPENR, 0, RCC_APB3LPENR_LPTIM1LPEN);  //Set 
LPTIM1 to remain enabled in STOP mode
        
   
        lptimer = stm32_lptim_init(1);  //Init LPTIMER1 (this also enables the 
clock, but it's safe to enable twice)
   
        // For STM32H5: Must enable timer BEFORE writing ARR in continuous mode
        lptimer->ops->setcfgr(lptimer, 0);
        lptimer->ops->enable(lptimer, true);  // Enable FIRST
        lptimer->ops->setperiod(lptimer, SYSTICK_RELOAD);  // Then set ARR 
(ARROK wait happens inside)
   
        lptimer->ops->setisr(lptimer, stm32_timerisr, lptimer, 0);
        lptimer->ops->enableint(lptimer, LPTIM_ISR_ARRM);
        lptimer->ops->start(lptimer, STM32_LPTIM_MODE_CONTINUOUS);
   }
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to