Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 31 of 31

Thread: issue to reporogram T4.0

  1. #26
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,124
    Quote Originally Posted by WMXZ View Post
    What I not understand is the following:
    I tell SNVS to wake-up the processor, say in 1 minute.
    I expect that alarm ISR is called after 1 minute, but MCU is not running, therefore alarm ISR can not run.
    Also, power off means all RAM (including alarm ISR code) is lost.
    So what the purpose of ISR?
    commenting attachInterruptVector seems not work (no wake-up). I.e. the default ISR that has no "SNVS_LPSR |= 1;" and therefore seems not to work.
    It seems that the alarm interrupt is called immediately after being enabled, but the wake-up is at the indicated time.

    Edit, as '+' member could you please edit the title of this thread and remove the disturbing 'o'?
    +Not: Thread titles are set in stone as they are the root of any link I suppose … Sorry the 'o' stays

    I wasn't sure about the _isr() - it fires immediately on/at EXIT? Maybe that is the MCU giving an ACK that the timer has been activated? Firing going into Sleep means the CPU and RAM are still active - but it is about to sleep.

    Putting more BLINK code in _isr() - the ISR does not fire the first time after programming - but it does each time after that? And it fires before Sleep not on Wake.

    Also until the rtc_isr() exits - when called after the first time - the MCU does not enter sleep.

    Here is edited code - will Sleep when any USB char is sent - not on a timer. Altered blink(#) calls for flash:
    Code:
    #include "core_pins.h"
    #include "TimeLib.h"
    
    /******************* Seting Alarm ***************/
    #define SNVS_LPCR_LPTA_EN_MASK          (0x2U)
    
    void rtc_stopAlarm()
    {
       SNVS_LPSR |= 1;
    
       // disable alarm
       SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
       while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);
       // clear alarm value
       SNVS_LPTAR = 0;
       while (SNVS_LPTAR != 0);
    }
    
    void rtc_isr(void)
    {
       digitalWriteFast(13, 1);
       delayMicroseconds(2000000); // to let USB write last line
          for ( int ic = 0; ic < 12; ic++ ) {
             blink( 40 );
             delay(50); // to let USB write last line
          }
       SNVS_LPSR |= 1;
       Serial.println("Alarm"); Serial.flush();// only to tell if ISR is called
       asm volatile ("DSB");
    }
    
    void rtc_setAlarm(uint32_t alarmSeconds, uint32_t prio = 13)
    {  uint32_t tmp = SNVS_LPCR; //save control register
    
       /* disable SRTC alarm interrupt */
       rtc_stopAlarm();
    
       SNVS_LPTAR = alarmSeconds;
       while (SNVS_LPTAR != alarmSeconds);
    
       attachInterruptVector(IRQ_SNVS_IRQ, rtc_isr);
       NVIC_SET_PRIORITY(IRQ_SNVS_IRQ, prio * 16); // 8 is normal priority
       NVIC_DISABLE_IRQ(IRQ_SNVS_IRQ);
       NVIC_ENABLE_IRQ(IRQ_SNVS_IRQ);
    
       SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; // restore control register and set alarm
       while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));
    }
    
    uint32_t rtc_getAlarm()
    {
       return SNVS_LPTAR;
    }
    
    void doShutdown(void)
    {
       SNVS_LPCR |= (1 << 6) ; // turn off power
    }
    
    void setWakeupCallandSleep(uint32_t nsec)
    {
       uint32_t to = now();
       rtc_setAlarm(to + nsec, 4);
       doShutdown();
       while (1) asm("wfi");
    }
    
    
    uint32_t blink( uint32_t tWait)
    {  static uint32_t tx0;
       if (millis() > tx0 + tWait)
       {  digitalWriteFast(13, !digitalReadFast(13));
          tx0 = millis();
          Serial.println("blink");
          return 1;
       }
       return 0;
    }
    
    void setup() {
       Serial.begin(9600);
       while (!Serial);
    
       // set the Time library to use Teensy 3.0's RTC to keep time
       setSyncProvider((getExternalTime)Teensy3Clock.get);
       delay(100);
       if (timeStatus() != timeSet)
          Serial.println("Unable to sync with the RTC");
       else
          Serial.println("RTC has set the system time");
       //
       Serial.println("Start");
       rtc_stopAlarm();
       pinMode(13, OUTPUT);
    
    }
    
    void loop() {
       static uint32_t ic = 0;
       ic += blink( 1000 );
       if (Serial.available())
       //if (ic >= 20)
       {  Serial.println("End"); Serial.flush();
          for ( ic = 0; ic < 12; ic++ ) {
             blink( 40 );
             delay(50); // to let USB write last line
          }
          digitalWriteFast(13, 0);
          delay(400); // to let USB write last line
          setWakeupCallandSleep(2);
       }
    }

  2. #27
    Junior Member
    Join Date
    Dec 2019
    Posts
    6
    I don't know if Arduino IDE users can make use of a .a library, but if so, here's a simple reboot() implementation based on the code above.

    I assume that the NVIC_DISABLE_IRQ(IRQ_SNVS_IRQ) call in rtc_SetAlarm() would be better placed at the beginning of rtc_StopAlarm() instead. Otherwise there are no material changes in this version, other than organizing the code to remove Serial calls, loop/setup functions, etc.
    Attached Files Attached Files

  3. #28
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,124
    Quote Originally Posted by John Miles View Post
    I don't know if Arduino IDE users can make use of a .a library, but if so, here's a simple reboot() implementation based on the code above.

    I assume that the NVIC_DISABLE_IRQ(IRQ_SNVS_IRQ) call in rtc_SetAlarm() would be better placed at the beginning of rtc_StopAlarm() instead. Otherwise there are no material changes in this version, other than organizing the code to remove Serial calls, loop/setup functions, etc.
    No, that as .a doesn't work as I tried it.

    Normal code as :: sketchbook\libraries\reboot holding the reboot.h and .cpp instead of .a does work with this sketch:
    Code:
    #include "reboot.h"
    
    void setup() {
      Serial.begin(115200);
      while (!Serial && millis() < 4000 );
      Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
    }
    
    void loop() {
    	if ( Serial.available() ) reboot(2);
    }

  4. #29
    Junior Member
    Join Date
    Dec 2019
    Posts
    6
    By the way, I also found that the ISR isn't necessary (and can be removed) the first time the boot cycle is performed by a given program. After the first reboot, subsequent reboots don't happen unless the ISR is installed and interrupts are enabled at the time rtc_setAlarm() programs the control register.

    On further investigation, as long as somebody sets bit 0 of SNVS_LPSR, the boot cycle is consistently reliable. Whether that's done in the ISR or rtc_stopAlarm() doesn't seem to matter. SNVS_LPSR seems to be some kind of reset/acknowledge bit that is not otherwise initialized at startup time.

    So it appears that the reboot() function can be further simplified below:
    Code:
    //
    // Based on code from defragster (https://forum.pjrc.com/threads/29607-Over-the-air-updates/page3)
    // and WMXZ (https://forum.pjrc.com/threads/58484-issue-to-reporogram-T4-0)
    //
    
    #include <core_pins.h>
    #include <TimeLib.h>
    
    #include <reboot.h>
    
    #define SNVS_LPCR_LPTA_EN_MASK (0x2U)
    
    //static void rtc_isr(void)
    //{
    //   SNVS_LPSR |= 1;
    //   asm volatile("DSB");
    //}
    
    static void rtc_stopAlarm()      
    {
    //   NVIC_DISABLE_IRQ(IRQ_SNVS_IRQ);
       SNVS_LPSR |= 1;
    
       // disable alarm
       SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
       while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);
    
       // clear alarm value
       SNVS_LPTAR = 0;
       while (SNVS_LPTAR != 0);
    }
    
    static void rtc_setAlarm(uint32_t alarmSeconds, 
                             uint32_t prio=13)
    {
       uint32_t tmp = SNVS_LPCR; // save control register
    
       rtc_stopAlarm();          // disable SRTC alarm interrupt
    
       SNVS_LPTAR = alarmSeconds;
       while (SNVS_LPTAR != alarmSeconds);
    
    // attachInterruptVector(IRQ_SNVS_IRQ, rtc_isr);
    //   NVIC_SET_PRIORITY(IRQ_SNVS_IRQ, prio * 16); // 8 is normal priority
    //   NVIC_ENABLE_IRQ(IRQ_SNVS_IRQ);
    
       SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; // restore control register and set alarm
       while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));
    }
    
    void reboot(int delay_secs)
    {
       // set the Time library to use Teensy 3/4 RTC to keep time
       setSyncProvider((getExternalTime) Teensy3Clock.get);
       delay(100);
    
       rtc_setAlarm(now() + delay_secs);
    
       __disable_irq();
       SNVS_LPCR |= (1 << 6); // turn off power
    
       while (1) asm("wfi");
    }

  5. #30
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,124
    This should be #ifdef ?_1062_? since it is MCU specific?

    Also we know restart times under 2 are suspect or fail - it would be good perhaps to add:
    Code:
    if ( delay_secs <2 ) delay_secs=2;
    Indeed observed the _isr() trigger is not called after first 'PJRC Bootloader' programming - so if that can be set to unneeded that would be best.

    However the Wake time of 2 seconds is still FIXED in the Low Power system. So every time the Power Off is issues with that button/pad - the MCU immediately WAKES for the expired timer. See prior posts this thread, until the timer is canceled on power up { with what was in rtc_stopAlarm(); called in setup() } the Power button is rendered ODD - as WMXZ first noted when creating this thread.

  6. #31
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,398
    generated separated files
    I tested with T4.0 and T3.6

    hibernate.h
    Code:
    #ifndef _HIBERNATE_H_
    #define _HIBERNATE_H_
        void rtc_clearAlarm();
        void setWakeupCallandSleep(uint32_t nsec);
    #endif
    hibernate.cpp
    Code:
    #include "core_pins.h"
    #include "hibernate.h"
    
    #include "TimeLib.h"
      
      #if defined (__IMXRT1062__)
        #define SNVS_LPCR_LPTA_EN_MASK          (0x2U)
        
        void rtc_clearAlarm()
        {
          SNVS_LPSR |= 1;
          SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
          while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK); 
          SNVS_LPTAR=0;
        }
        
        
        void rtc_setAlarm(uint32_t alarmSeconds)
        {   uint32_t tmp = SNVS_LPCR; //save control register
        
            /* disable SRTC alarm interrupt */
            rtc_clearAlarm();
        
            SNVS_LPTAR=alarmSeconds;
            while(SNVS_LPTAR != alarmSeconds);
        
            SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; // restore control register and set alarm
            while(!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK)); 
        }
        
        uint32_t rtc_getAlarm()
        {
          return SNVS_LPTAR;  
        }
        
        void setWakeupCallandSleep(uint32_t nsec)
        {
          uint32_t to=now();
          rtc_setAlarm(to+nsec);
          SNVS_LPCR |=(1<<6) ; // turn off power
          while(1) continue;
        }
        
      #elif defined(KINETISK) 
          #define RTC_IER_TAIE_MASK       0x4u
          #define RTC_SR_TAF_MASK         0x4u
          
          void rtcSetAlarm(uint32_t nsec)
          { 
             SIM_SCGC6 |= SIM_SCGC6_RTC;// enable RTC clock
             RTC_CR |= RTC_CR_OSCE;// enable RTC
             // set alarm nsec seconds in the future
             RTC_TAR = RTC_TSR + nsec;
             RTC_IER |= RTC_IER_TAIE_MASK;
             while(!(RTC_IER & RTC_IER_TAIE_MASK));
          }
          
          /********************LLWU**********************************/
          #define LLWU_ME_WUME5_MASK       0x20u
          #define LLWU_F3_MWUF5_MASK       0x20u
          #define LLWU_MF5_MWUF5_MASK      0x20u
    
          static void llwuSetup(void)
          {
            LLWU_PE1 = 0;
            LLWU_PE2 = 0;
            LLWU_PE3 = 0;
            LLWU_PE4 = 0;
          #if defined(HAS_KINETIS_LLWU_32CH)
            LLWU_PE5 = 0;
            LLWU_PE6 = 0;
            LLWU_PE7 = 0;
            LLWU_PE8 = 0;
          #endif
            LLWU_ME  = LLWU_ME_WUME5_MASK; //rtc alarm
            //   
            SIM_SOPT1CFG |= SIM_SOPT1CFG_USSWE;
            SIM_SOPT1 |= SIM_SOPT1_USBSSTBY;
            //
          }
          
          /********************* go to deep sleep *********************/
          #define SMC_PMPROT_AVLLS_MASK   0x2u
          #define SMC_PMCTRL_STOPM_MASK   0x7u
          #define SCB_SCR_SLEEPDEEP_MASK  0x4u
          
          // see SMC section (e.g. p 339 of K66) 
          #define VLLS3 0x3 // RAM retained I/O states held
          #define VLLS2 0x2 // RAM partially retained
          #define VLLS1 0x1 // I/O states held
          #define VLLS0 0x0 // all stop
          
          #define VLLS_MODE VLLS0
          static void gotoSleep(void)
          {  
          //  /* Make sure clock monitor is off so we don't get spurious reset */
             MCG_C6 &= ~MCG_C6_CME0;
             //
          
          // if K66 is running in highspeed mode (>120 MHz) reduce speed
          // is defined in kinetis.h and mk20dx128c
          #if defined(HAS_KINETIS_HSRUN) && F_CPU > 120000000
              kinetis_hsrun_disable( );
          #endif   
             SYST_CSR &= ~SYST_CSR_TICKINT;      // disable systick timer interrupt
             SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;  // Set the SLEEPDEEP bit to enable deep sleep mode (STOP)
             
             /* Write to PMPROT to allow all possible power modes */
             SMC_PMPROT = SMC_PMPROT_AVLLS_MASK;
             /* Set the STOPM field to 0b100 for VLLSx mode */
             SMC_PMCTRL &= ~SMC_PMCTRL_STOPM_MASK;
             SMC_PMCTRL |= SMC_PMCTRL_STOPM(0x4); // VLLSx
          
             SMC_VLLSCTRL =  SMC_VLLSCTRL_VLLSM(VLLS_MODE);
             /*wait for write to complete to SMC before stopping core */
             (void) SMC_PMCTRL;
    
             asm volatile( "wfi" );  // WFI instruction will start entry into STOP mode
             // will never return, but wake-up results in call to ResetHandler() in mk20dx128.c
          }
          
          void rtc_clearAlarm(){}
          
          void setWakeupCallandSleep(uint32_t nsec)
          {  // set alarm to nsec secods in future and go to hibernate
             llwuSetup();
             
             rtcSetAlarm(nsec);
             gotoSleep();
          }
        
        #endif
    my test program is
    Code:
    #include "core_pins.h"
    #include "hibernate.h"
    
    uint32_t blink(void)
    { static uint32_t tx0;
      if(millis()>tx0+1000) 
      { digitalWriteFast(13,!digitalReadFast(13));
        tx0=millis();
        Serial.println("blink");
        return 1;
      }
      return 0;
    }
    
    void setup() {
      Serial.begin(9600);
      while (!Serial);
      Serial.println("\n" __FILE__ "\n " __DATE__ " " __TIME__);
      
      // set the Time library to use Teensy 3.0's RTC to keep time
      setSyncProvider(Teensy3Clock.get);
      delay(100);
      if (timeStatus()!= timeSet) 
        Serial.println("Unable to sync with the RTC");
      else 
        Serial.println("RTC has set the system time");
      //
      Serial.println("Start");
      rtc_clearAlarm(); // just in case
      pinMode(13,OUTPUT);
    }
    
    void loop() {
      static uint32_t ic=0;
      ic += blink();
      if(ic>=20)
      { Serial.println("End"); Serial.flush();
        delay(1000); // to let USB write last line
        setWakeupCallandSleep(2);
      }
    }
    I stick to hibernate and "setWakeupCallandSleep" for historic reason.
    Everyone may feel free to change filename and content.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •