Put the UNO R4 Minima to LPM (Low Power Mode)

Has anyone found a way to put the R4 Minima into and out of Low Power Mode? I've been searching for three days and I'm not finding anything other than switching over from the Arduino IDE to the Renesas Hardware / IDE solution and studying their e^2 studio and RA FSP architecture just to put this UNO R4 to sleep. That could take weeks to come up-to-speed. As far as I can tell, the Arduino Low Power library has not been updated to include the UNO R4 Minima at this point in time. The examples won't compile.

I'm not looking for alternative methods to accomplish the same results, I prefer to learn how to put the UNO R4 to sleep and wake it up.

As per msg the code you are looking for is:

  	asm volatile("wfi");           // Stop here and wait for an interrupt

Make sure you preferably have something with an interrupt running that you have control over; otherwise, one doesn't wake up.

One should wake up if WFI is used in loop() on the AGT0 1mS tick, but I haven't' tried all the combinations yet as I was using WFI with an already Hijacked AGT0 interrupt code.

Thank you very much Susan!

1 Like

Hello Susan
I have tried your instruction asm volatile("wfi"); at the end of my "loop" part, but nothing happens :
my Uno R4 minima board doesn't stop, and the board current consumption is still the some...
Have you an idea ?
Thanks in advance !

1 Like

Can you post your loop() code?

The processor should stop until the next mS AGT0 timer interrupt, or any USB activity.

If you have other peripherals with interrupts enabled, they will also wake up the processor.

===============================================================

A point to note, the GREEN power ON indicator LED is drawing 8.2mA (2.71V across R16 330R) when under USB power at c. 4.74V, so if people really want low-power that has to be disabled before anything else.

SCK-LED will also need dealing with if D13 is used for anything (like SPI), because ALL the LEDs according to the schematic (and confirmed by measurment) are on 330R series resistors... and I would also note that P111 has a IOH of -4mA irrespective of the drive-capacity setting (Low or Middle drive).
See RA4M1 datasheet Table 48.6
... and that is likely to tank the SPI clock high levels too! :frowning:

Hello Susan
Thank you very much for your very quick answer...
After you answer, I have disconnected the USB plug, but the board current consumption is still high (about 50mA under 9V battery). Later I will remove all LEDs on my uno R4 minima board, but at the present time, it is as if the board doesnt go into sleep...
I muste precise that the board is fitted with different peripherals:

  • RTC board (on I2C bus)
  • LoRa module (on SPI bus)
  • 4 lines liquid display (on I2C bus)

Here is the code:

#include <TimeLib.h>
#include "LiquidCrystal_PCF8574.h"
#include <EEPROM.h>
#include <SPI.h>
#include <LoRa.h>
#include <I2C_RTC.h>
///////////////////////////////////////////////////
void setup() {
  // init afficheur
  lcd.begin(20, 4); // 20 caracteres sur 4 lignes
  lcd.setBacklight(255);

  Serial.begin(9600);

  Serial.println("Init démarrée...");
  afficheLigne("INIT DEMARREE.", 0);


  // init gestion eeprom
  //    counter = EEPROM.read(adresseEEprom);

  // entrees logiques
  pinMode(2, INPUT_PULLUP); // Menu
  pinMode(3, INPUT_PULLUP); // fleche G
  pinMode(4, INPUT_PULLUP); // fleche D
  pinMode(5, INPUT_PULLUP); // OK
  pinMode(6, INPUT_PULLUP); // fleche H
  pinMode(7, INPUT_PULLUP); // fleche B
  pinMode(8, INPUT_PULLUP); // ESC

  // entree analogique (Ubatt)

  // init module LORA
  if (!LoRa.begin(433E6)) {
    Serial.println("## Echec démarrage LoRa!");
    while (1);
  }
  //  LoRa.setTxPower(17);
  Serial.println("LoRa démarré.");


  // init module RTC
  if (!RTC.begin()) {
    Serial.println("## Echec démarrage RTC!");
    while (1);
  }
  Serial.println("RTC démarrée.");
  RTC.setHourMode(CLOCK_H24);
  RTC.setWeek(4);
......

///////////////////////////////////////////////////
void loop() {
  if ( millis() - tempsHTR > tempsHTRmax) {       //tempsHTRmax=200 ms)
    // traitement de l'IT
    tempsHTR = millis();

    // lecture date et heure
    donneDateEtHeureCourante();    // reading RTC module on I2C bus
    String s = jourCourant +" "+ dateHeureCourante + " " + percentBatt + "%";
    afficheLigne(s, 0);


    // lecture entrees logiques et BP
    lectureEntreeLogiques();

    // lecture tension batterie et gestion %
    gereTensionBatterie();

    // gestion menu
    gereMenu();

    gerePGM();

    gereEnvoiCommandes();

    // gestion backLight
    gereBackLight();

  } // fin traitement de l'IT


  // hors temps réel, attente réception message
  if (LoRa.parsePacket()) {   // test taille paquet reception
    // read packet car par car
    messageRecu = "";
    while (LoRa.available()) {
      messageRecu += (char)LoRa.read();
    }
    nivRSSI = LoRa.packetRssi();
    
    Serial.print("Message acquittement reçu: ");
    Serial.print(messageRecu);
    Serial.print(" (niveau RSSI: ");
    Serial.print(nivRSSI);
    Serial.println(" dBm)");
  }
 **asm volatile("wfi");** 
}

That is strange, but there seems to be a lot going on.

At 9.00V supply on Vin, the Minima running with loop() active all the time, the power LED lit (but no others), and USB serial printing once per second, is showing as 22.5mA on my DVM.

With the same conditions, but with sleep active, I get 13.8mA.

I can see the difference since the chip die-temperature drops by 3 or 4 degrees Centigrade quite rapidly.

Noting that the overall current goes down as the Vin is raised, due to the DC/DC converter trading voltage for current.

The RTC board by definition "should" be low power. But the I2C communications will have a power impact, especially as the Arduino libraries are so inefficient.

The SPI bus code as implemented on the Arduino libraries is also inefficient.

For real low-power one has to specifically write code for the processor - not use generic libraries.

I have SPI working, including 16 and 32 bit transfers. I am still working on I2C code, writes work, but I still need to finish off the reading.

The backlight for the LCD will take power, of course.

One of the things needed to do for low power is to stop the USB module.

Datasheet Table 48.11 Operating and standby current

Max worst case current at 48MHz (not including anything loading the I/O pins), is 50mA.

To drive the currents down the clock can be slowed to 8MHz, to get it really low it can be slowed further, but that needs more than the simple WFI instruction.

1 Like

Hello Susan, and thank you again for all this information, sent even on the weekend!
I look forward to trying your libraries when you think they are ready.
As for me, I will not be able to rewrite more efficient libraries for controlling RTC and LoRa modules...
To reduce current consumption, I have already integrated the shutdown of the backLight of the liquid crystal screen after a time-out.

  • How could we slow down the clock by changing it to 8 MHz from C instructions?
  • How to stop managing the USB port using C instructions?
    I'm going to try again starting from an empty loop, with the instruction asm volatile("wfi"); then I will gradually add modules management (RTC, LoRa) , noting each time the new current consumption
1 Like

Hi Ivan,
I will have a look at the RTC at some point when I am back in the I2C code, that's something I want for my own projects too.
I have code that changes the HOCO clock to an external crystal up on my GitHub page - so I will need to check out the settings for changing the internal clock.
The USB needs a fixed 48Mhz clock, and I am assuming that one wants to have the USB available at startup, by detecting if it is present. If it isn't there, then one can shut the USB down.
USB is a bit tricky, and I will have to look a bit further to see what is easy to implement - turning it off is easy, turning it back on without a reset not necessarily so much.
Won't have much time until the weekend earliest before I can get back into this.

I have modified my dev Minima board to replace the 330R resistors on L and ON with 2.7K resistors.
I have also cut the +5V trace to the ON led and wired it to the USB's VUSB so the Power ON led only illuminates when the board is connected to a USB port, but remains unconnected when the board is supplied from VIN.

The modded board is now c. 15mA @ 9V VIN when in a continious executing code loop, and 7.6mA when running with sleep and WFI instruction (with the USB still connected for serial-data).

This mod to the ON led would I believe could be advantageous to be implemented as a design change since simpler/normal applications will be using the board with the USB power where power-consumption is not a primary concern, but allows for low(er) power operation for those of us who want to do such things.


My modded Minima on the left, and a standard "vanilla" Minima on the right.

Update:
ON has 2.7K (as before).
L has been changed to 1.7K as it was a bit dim (yellow not being as emissive as green).
RX and TX now also have 1.7K resistors.

Basic code example to show Sleep / Wake-From-Interrupt and disabling the USB module.
Turning off the USB module saves about 2mA when VIN is at 9.0V.

/*  Arduino UNO R4 test-code to demonstrate Wake-From-Interrupt and USB Module Disable
 *    Note this code is experimental, don't use without reading RA4M1 documentation.
 *
 *  Susan Parker - 17th December 2023.
 *

    This code is "AS IS" without warranty or liability. 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

======================================================

USB Serial input for very basic control of operations:

  s = Enable Sleep  / Wake From Interrupt.
  q = Disable Sleep / Wake From Interrupt.
  u = USB Module Disable - basic turn-off (not necessarly max power-saving).

Board changes for Low_Power:
1. ON LED series resistor changed to 2.7K, and LED VCC connection changed to VUSB.
2. L  LED series resistor changed to 1.7K (which = 1.8mA if 100% on).

Board running with +9.0V VIN:
  without sleep, USB active = c. 15.4 mA
  with WFI and USB active   = c.  7.5 mA
  with WFI but USB disabled = c.  5.8 mA (USB module still has power from PC conection).
  with WFI and USB unpluged = c.  5.9 mA (ON is partly backpowered through USB section).

When board has USB disabled - a full power-cycle OFF and ON needed to reattach PC serial.

*/

// ARM-developer - Accessing memory-mapped peripherals
// https://developer.arm.com/documentation/102618/0100

// Low Power Mode Control
#define MSTP 0x40040000 
#define MSTP_MSTPCRB   ((volatile unsigned int   *)(MSTP + 0x7000))      // Module Stop Control Register B
#define MSTPB11 11 // USBFS

// ==== USB 2.0 Full-Speed Module ====
#define USBFSBASE  0x40090000
#define USBFS_SYSCFG     ((volatile unsigned short *)(USBFSBASE + 0x0000))

// =========== Ports ============
#define PORTBASE 0x40040000
#define PFS_P111PFS_BY ((volatile unsigned char  *)(PORTBASE + 0x0843 + (11 * 4))) // D13 / SCLK

bool wfi_flag = true;       // Will start with WFI mode active
bool usb_flag = true;

void setup()
  {
  Serial.begin(115200);
  while (!Serial){};
  Serial.println("WFI and USB Disable Demo.");
  }

void loop()
  {
  if(wfi_flag)                     // For testing, make sure sleep mode isn't on at bootup
    {
    *PFS_P111PFS_BY = 0x04;        // D13 - CLEAR LED
  	asm volatile("wfi");           // Stop here and wait for an interrupt
    *PFS_P111PFS_BY = 0x05;        // D13 - Set LED
    }

  if(usb_flag == true)
    {
    if(Serial.available())           // If anything comes in on the USB Serial (which is done with USB interrupts)
      {
      char inbyte = Serial.read();
      Serial.write(inbyte);          // ... send it back out 

      switch (inbyte)                // Very basic control of operations
        {
        case 's':
          {
          wfi_flag = true;
          Serial.println("\nEnable Sleep");
          break;
          }
        case 'q':
          {
          wfi_flag = false;
          Serial.println("\nDisable Sleep");
         *PFS_P111PFS_BY = 0x04;        // D13 - CLEAR LED
          break;
          }
        case 'u':
          {
          usb_flag = false;
          Serial.println("\nDisable USBFS module");
          delayMicroseconds(900);              // Wait for USB serial print transaction...
          *USBFS_SYSCFG  = 0x0000;             // USBFS Operation Disable
          delayMicroseconds(1);                // Wait to ensure module stopped
          *MSTP_MSTPCRB |= (0x01 << MSTPB11);  // Disable USBFS module
          break;
          }
        case '?':
          {
          if(wfi_flag == false)
            Serial.println("\nNo Sleeping");
          else
            Serial.println("\nWake from IRQs");
          break;
          }
        default:
          break;
        }
      }
    }
  }

@ivan_buisson

I have added System-Clock switching to the Sleep / Wake-From-Interrupt and disabling the USB module code example.

Can now go from IDE standard settings, to x1/16 and x1/64, and back using the basic single-char commands.

USB-serial continues to operate at all the clock speeds, unless specifically disabled.

I have also implemented a timeout for the USB-disable, so the code does a software-reset after a short time delay (10 seconds) and the reset reboot re-establishes a USB serial connection to the PC.

To Upload new code to the Minima, use the "q" character command to quit WFI operations, otherwise the IDE has problems seeing the board.

/*  Arduino UNO R4 test-code to demonstrate Wake-From-Interrupt and USB Module Disable
 *    Note this code is experimental, don't use without reading RA4M1 documentation.
 *
 *  Susan Parker - 17th December 2023.
 *
 *  Susan Parker - 18th December 2023.
 *    Add processor clock-switching - not yet working.
 *
 *  Susan Parker - 19th December 2023.
 *    Add timeout delay SoftWare-Reset, to re-establish USB Serial connection to PC
 *    ... any application would need to do a tidyup before SW-Reset e.g. close files,
 *        save configurations into EEROM, etc.
 *    Update processor clock-switching - now working.
 *    ... USBFS clock runs seperatly, direct from the 48MHz HOCO clock,
*         USB serial still works at x1/16 and x1/64 sys-clock rates.

    This code is "AS IS" without warranty or liability. 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

======================================================

USB Serial input for very basic control of operations:

  s = Enable Sleep  / Wake From Interrupt.
  q = Disable Sleep / Wake From Interrupt.
  u = USB Module Disable - basic turn-off (not necessarly max power-saving).
  0 = Set the System Clocks to IDE default.
  4 = Change all System Clocks to x1/16.
  6 = Change all System Clocks to x1/64 rate.
  ? = Report code mode - WFI or Constant-Looping

Board changes for Low_Power:
1. ON LED series resistor changed to 2.7K, and LED VCC connection changed to VUSB.
2. L  LED series resistor changed to 1.7K (which = 1.8mA if 100% on).

Board running with +9.0V VIN at 48MHz HOCO clock with default IDE settings:
  without sleep, USB active = c. 15.4 mA
  with WFI and USB active   = c.  7.5 mA
  with WFI but USB disabled = c.  5.8 mA (USB module still has power from PC conection).
  with WFI and USB unpluged = c.  5.9 mA (The ON led is partly backpowered through USB section).

With all SysClocks at 1/16th rate:
  without sleep, USB active = c.  5.3 mA
  with WFI and USB active   = c.  4.1 mA
  with WFI but USB disabled = c.  2.2 mA

With all SysClocks at 1/64th rate:
  without sleep, USB active = c.  4.7 mA
  with WFI and USB active   = c.  3.8 mA
  with WFI but USB disabled = c.  2.0 mA

When board has USB disabled - a full power-cycle OFF and ON needed to reattach PC serial.
UPDATE: Code now can do a Software-Reset - saves on unplugging and plugging in cables.

*/

// ARM-developer - Accessing memory-mapped peripherals
// https://developer.arm.com/documentation/102618/0100

// Low Power Mode Control
#define MSTP 0x40040000 
#define MSTP_MSTPCRB   ((volatile unsigned int   *)(MSTP + 0x7000))      // Module Stop Control Register B
#define MSTPB11 11 // USBFS

// ==== USB 2.0 Full-Speed Module ====
#define USBFSBASE  0x40090000
#define USBFS_SYSCFG     ((volatile unsigned short *)(USBFSBASE + 0x0000))

// =========== Ports ============
#define PORTBASE 0x40040000
#define PFS_P111PFS_BY ((volatile unsigned char  *)(PORTBASE + 0x0843 + (11 * 4))) // D13 / SCLK

// Low Power Mode Control - See datasheet section 10
#define SYSTEM 0x40010000 // System Registers
#define SYSTEM_SBYCR    ((volatile unsigned short *)(SYSTEM + 0xE00C))  // Standby Control Register
#define SYSTEM_MSTPCRA  ((volatile unsigned int   *)(SYSTEM + 0xE01C))  // Module Stop Control Register A
#define SYSTEM_SCKDIVCR ((volatile unsigned int   *)(SYSTEM + 0xE020))  // System Clock Division Control Register
#define SYSTEM_PRCR     ((volatile unsigned short *)(SYSTEM + 0xE3FE))  // Protect Register
#define SYSTEM_SCKDIVCR ((volatile unsigned int   *)(SYSTEM + 0xE020))  // System Clock Division Control Register
                                // SYSTEM_SCKDIVCR = 10010100  Note: bit-7 is 1, and should be reading as 0
#define SCKDIVCR_PCKD_2_0   0   // Peripheral Module Clock D           = 4; 1/16
#define SCKDIVCR_PCKC_2_0   4   // Peripheral Module Clock C           = 1; 1/2
#define SCKDIVCR_PCKB_2_0   8   // Peripheral Module Clock B           = 0
#define SCKDIVCR_PCKA_2_0  12   // Peripheral Module Clock A           = 0
#define SCKDIVCR_ICK_2_0   24   // System Clock (ICLK) Select          = 0

#define SYSTEM_RSTSR0  ((volatile unsigned char  *)(SYSTEM + 0xE410))  //
#define RSTSR0_PORF    0   // Power-On Reset Detect Flag; 1: Power-on reset detected
#define SYSTEM_RSTSR1  ((volatile unsigned short *)(SYSTEM + 0xE0C0))  //
#define RSTSR1_IWDTRF  0   // Independent Watchdog Timer Reset Detect Flag; 1: Independent watchdog timer reset detected
#define RSTSR1_WDTRF   1   // Watchdog Timer Reset Detect Flag; 1: Watchdog timer reset detected
#define RSTSR1_SWRF    2   // Software Reset Detect Flag;       1: Software reset detected
#define SYSTEM_RSTSR2  ((volatile unsigned char  *)(SYSTEM + 0xE411))  //
#define RSTSR2_CWSF    0   // Cold/Warm Start Determination Flag; 0: Cold start, 1: Warm start

// System Control Block
#define SCBBASE 0xE0000000
#define SCB_AIRCR                  ((volatile unsigned int *)(SCBBASE + 0xED0C))
#define SCB_AIRCR_VECTKEY_Pos      16U                                   // SCB AIRCR: VECTKEY Position
#define SCB_AIRCR_SYSRESETREQ_Pos  2U                                    // SCB AIRCR: SYSRESETREQ Position
#define SCB_AIRCR_SYSRESETREQ_Msk  (1UL << SCB_AIRCR_SYSRESETREQ_Pos)    // SCB AIRCR: SYSRESETREQ Mask

// From: https://mcuoneclipse.com/2015/07/01/how-to-reset-an-arm-cortex-m-with-software/

bool wfi_flag = true;       // Will start with WFI mode active
bool usb_flag = true;

void setup()
  {
  Serial.begin(115200);
  while (!Serial){};
  Serial.println("\nWFI and USB Disable Demo.");
  }

#define WFI_MS_DOWNCOUNT 1000
#define WFI_SECONDS_DELAY  10

void loop()
  {
  static uint32_t loop_delay = 1000;
  static uint32_t seconds_count = 0;
  static uint32_t sys_clk_div_shift = 0;

  if(wfi_flag)                     // For testing, make sure sleep mode isn't on at bootup
    {
    *PFS_P111PFS_BY = 0x04;        // D13 - CLEAR LED
  	asm volatile("wfi");           // Stop here and wait for an interrupt
    *PFS_P111PFS_BY = 0x05;        // D13 - Set LED
    loop_delay--;
    if(loop_delay == 0)
      {
      loop_delay = (WFI_MS_DOWNCOUNT >> sys_clk_div_shift);
      seconds_count++;
      if(usb_flag == true)
        {
        Serial.print(".");          // print a "." once per second 
        }
      }
    }

  if(usb_flag == true)
    {
    if(Serial.available())           // If anything comes in on the USB Serial (which is done with USB interrupts)
      {
      char inbyte = Serial.read();
      Serial.write(inbyte);          // ... send it back out 

      switch (inbyte)                // Very basic control of operations
        {
        case 's':
          {
          wfi_flag = true;
          Serial.println("\nEnable Sleep");
          break;
          }
        case 'q':
          {
          wfi_flag = false;
          Serial.println("\nDisable Sleep");
         *PFS_P111PFS_BY = 0x04;        // D13 - CLEAR LED
          break;
          }
        case 'u':
          {
          usb_flag = false;
          seconds_count = 0;
          Serial.println("\nDisable USBFS module");
          delayMicroseconds(900);              // Wait for USB serial print transaction...
          Serial.end(); 
          *USBFS_SYSCFG  = 0x0000;             // USBFS Operation Disable
          delayMicroseconds(1);                // Wait to ensure module stopped
          *MSTP_MSTPCRB |= (0x01 << MSTPB11);  // Disable USBFS module
          break;
          }
        case '?':
          {
          if(wfi_flag == false)
            Serial.println("\nNo Sleeping");
          else
            Serial.println("\nWake from IRQs");
          break;
          }
        case '0':
          {
          sys_clk_div_shift = 0;                // PCLKB is already at x1/2
          Serial.println("\nSYSclk = 1x1");
          setup_sys_clock_divider(0x0);
          Serial.println(*SYSTEM_SCKDIVCR, BIN);
          break;
          }
        case '4':
          {
          sys_clk_div_shift = 3;
          Serial.println("\nSYSclk = 1/16");
          setup_sys_clock_divider(0x4);
          Serial.println(*SYSTEM_SCKDIVCR, BIN);
          break;
          }
        case '6':
          {
          sys_clk_div_shift = 5;
          Serial.println("\nSYSclk = 1/64");
          setup_sys_clock_divider(0x6);
          Serial.println(*SYSTEM_SCKDIVCR, BIN);
          break;
          }
        default:
          break;
        }
      }
    }
  else
    {
    if(seconds_count >= WFI_SECONDS_DELAY)  // Sortware reset needed to reinitialse USB with PC  
      { 
      *SCB_AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk);
      }
    }
  }


/*
Restrictions on setting the clock frequency: ICLK ≥ PCLKA ≥ PCLKB, PCLKD ≥ PCLKA ≥ PCLKB, ICLK ≥ FCLKA
Restrictions on the clock frequency ratio: (N: integer, and up to 64)
ICLK:FCLK = N:1, ICLK:PCLKA = N: 1, ICLK:PCLKB = N: 1
ICLK:PCLKC = N:1 or 1:N, ICLK:PCLKD= N:1 or 1:N
PCLKB:PCLKC = 1:1 or 1:2 or 1:4 or 2:1 or 4:1 or 8:1
*/
// After reset:
// 0100 0100 0000 0100 MSBs
// 0100 0100 0100 0100 LSBs
// 
// From IDE
// 0001 0000 0000 0001 MSBs
// 0000 0001 0000 0000 LSBs

void setup_sys_clock_divider(int divider) // Divider for HOCO On-Chip Oscillator
  {
  *SYSTEM_PRCR      = 0xA501;            // Enable writing to the clock registers

//  *SYSTEM_SCKDIVCR |= ((divider & 0x07) << SCKDIVCR_ICK_2_0);  // Set the ICK divider 
  if(divider == 4)
    *SYSTEM_SCKDIVCR = 0x44044444;  // Set the clock dividerers to 1/16th rate
  else if(divider == 6)
    *SYSTEM_SCKDIVCR = 0x66066666;  // Set the clock dividerers to 1/64th rate
  else
    *SYSTEM_SCKDIVCR = 0x10010100;  // Set the clock dividerers to main speeds
    
  *SYSTEM_PRCR      = 0xA500;            // Disable writing to the clock registers
  }

Hello Susan

Thank you very much for this excellent work and information
at the present time, My mother is deceased, so I will test that a little bit later
A bientôt

1 Like

My condolences.

No worries, as and when you have time.

Small code updates - and fixed USB residual power issue when module is disabled.

UPDATED 21st Dec - Now has HOCO and MOCO (and PLL with XTAL if fitted) clock source switching.

/*  Arduino UNO R4 test-code to demonstrate:
    1. Wake-From-Interrupt
    2. Change System-Clock divisors 1/1, 1/16, and 1/64 settings 
    3. Switching between 48MHz HOCO and 8MHz MOCO internal oscillators (and PLL with XTAL if fitted)
    4. USB Module Disable (with code initiated Reset after timeout delay)

NOTE: This code is experimental, don't use without reading RA4M1 documentation. 
      Clock, division, and low-power modes have lots of variations - not ALL will work! 

Susan Parker - 17th December 2023.
  First draft - WFI and USB disable

Susan Parker - 18th December 2023.
  Add processor clock-switching - not yet working.

Susan Parker - 19th December 2023.
  Add timeout delay SoftWare-Reset, to re-establish USB Serial connection to PC
  ... any application would need to do a tidyup before SW-Reset e.g. close files,
      save configurations into EEPROM, etc.
  Update processor clock-switching - now working.
  ... USBFS clock runs seperatly, direct from the 48MHz HOCO clock,
      USB serial still works at x1/16 and x1/64 sys-clock rates.

Susan Parker - 20th December 2023.
  Add additinal USB register clears - RA4M1 no longer backpowers ON led when USB removed.
  Update SysClk switching - restore IDE defaults before SW-Reset on "u" command.

Susan Parker - 21st December 2023.
  Add change of System Clock between HOCO and MOCO sources (and PLL if XTAL fitted)
  ... turn off HOCO clock when USBFS is disabled if using MOCO 8MHz clock,
      or MOSC and PLL with external XTAL (e.g. EK-RA4M1 dev-board).

  This code is "AS IS" without warranty or liability. 

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

======================================================

USB Serial input for very basic control of operations:

  s = Enable  Sleep / Wake From Interrupt.
  q = Disable Sleep / Wake From Interrupt.
  u = USB Module Disable - will perform a code function HW-Reset after 10s delay.
  0 = Set the System Clocks to IDE default.
  4 = Change all System Clocks to x1/16 rate.
  6 = Change all System Clocks to x1/64 rate.
  8 = Change System Clock from HOCO to MOCO.
  9 = Change System Clock from MOCO to HOCO.
  m = Report mode - Clock settings, WFI or Constant-Looping, etc.
  ? = Display all Char Commands (this list).

  7 = Change System Clock to PLL with XTAL. [ For boards with external XTAL fitted.]

Board changes for Low_Power:
1. ON LED series resistor changed to 2.7K, and LED VCC connection changed to VUSB.
2. L  LED series resistor changed to 1.7K (which = 1.8mA if 100% on).

Board running with +9.0V VIN at 48MHz HOCO clock with default IDE settings:
  without sleep, USB active = c. 15.5 mA
  with WFI and USB active   = c.  7.5 mA
  with WFI but USB disabled = c.  5.3 mA (Clear USBFS.USBMC and USBFS.USBBCCTRL0 to defaults)
  with WFI and USB unpluged = c.  5.3 mA (  "     "     "  ...)

(Without clearing USBFS.USBMC and USBFS.USBBCCTRL0 to defaults)
  with WFI but USB disabled = c.  5.8 mA (USB module still has power from PC conection).
  with WFI and USB unpluged = c.  5.9 mA (The ON led is partly backpowered through USB section).

With all SysClocks at 1/16th rate (3.0 MHz):
  without sleep, USB active = c.  5.3 mA
  with WFI and USB active   = c.  4.1 mA
  with WFI but USB disabled = c.  2.2 mA

With all SysClocks at 1/64th rate (750 kHz):
  without sleep, USB active = c.  4.7 mA
  with WFI and USB active   = c.  3.8 mA
  with WFI but USB disabled = c.  1.8 mA

Board running with +9.0V VIN at 8MHz MOCO clock with default IDE settings:
  without sleep, USB active = c.  6.2 mA - HOCO still running for USBFS Module
  with WFI and USB active   = c.  4.1 mA
  with WFI but USB disabled = c.  2.8 mA - HOCO stopped

With all SysClocks at 1/16th rate (500 kHz):
  without sleep, USB active = c.  4.5 mA
  with WFI and USB active   = c.  3.5 mA
  with WFI but USB disabled = c.  1.2 mA

With all SysClocks at 1/64th rate (125 kHz):
  without sleep, USB active = c.  4.4 mA
  with WFI and USB active   = c.  3.4 mA
  with WFI but USB disabled = c.  1.1 mA 

When board has USB disabled - a full power-cycle OFF and ON needed to reattach PC serial.
UPDATE: Code now can do a Software-Reset - saves on unplugging and plugging in cables.


### ARM-developer - Accessing memory-mapped peripherals ###
    https://developer.arm.com/documentation/102618/0100

Fastest possible pin writes and reads with the RA4M1 processor
  *PFS_P107PFS_BY = 0x05;      // Each Port Output bit clear > to > set   takes c. 83nS 
  *PFS_P107PFS_BY = 0x04;      // Each Port Output bit   set > to > clear takes c. 83nS 

  *PFS_P107PFS_BY = 0x05;      // Set HIGH
  char_val = *PFS_P107PFS_BY;  // Port State Input read - takes about 165nS
  *PFS_P107PFS_BY = 0x04;      // Read plus Set LOW = c. 250nS

*/


// Low Power Mode Control
#define MSTP 0x40040000 
#define MSTP_MSTPCRB   ((volatile unsigned int   *)(MSTP + 0x7000))      // Module Stop Control Register B
#define MSTPB11 11 // USBFS

// ==== USB 2.0 Full-Speed Module ====
#define USBFSBASE  0x40090000
#define USBFS_SYSCFG     ((volatile unsigned short *)(USBFSBASE + 0x0000))
#define USBFS_USBMC      ((volatile unsigned short *)(USBFSBASE + 0x00CC))
#define USBFS_USBBCCTRL0 ((volatile unsigned short *)(USBFSBASE + 0x00B0))

// =========== Ports ============
#define PORTBASE 0x40040000
#define PFS_P111PFS_BY ((volatile unsigned char  *)(PORTBASE + 0x0843 + (11 * 4))) // D13 / SCLK

// Low Power Mode Control - See datasheet section 10
#define SYSTEM 0x40010000 // System Registers
#define SYSTEM_SBYCR    ((volatile unsigned short *)(SYSTEM + 0xE00C))  // Standby Control Register
#define SYSTEM_MSTPCRA  ((volatile unsigned int   *)(SYSTEM + 0xE01C))  // Module Stop Control Register A
#define SYSTEM_SCKDIVCR ((volatile unsigned int   *)(SYSTEM + 0xE020))  // System Clock Division Control Register
#define SYSTEM_PRCR     ((volatile unsigned short *)(SYSTEM + 0xE3FE))  // Protect Register
#define SYSTEM_SCKDIVCR ((volatile unsigned int   *)(SYSTEM + 0xE020))  // System Clock Division Control Register
                                // SYSTEM_SCKDIVCR = 10010100  Note: bit-7 is 1, and should be reading as 0
#define SCKDIVCR_PCKD_2_0   0   // Peripheral Module Clock D           = 4; 1/16
#define SCKDIVCR_PCKC_2_0   4   // Peripheral Module Clock C           = 1; 1/2
#define SCKDIVCR_PCKB_2_0   8   // Peripheral Module Clock B           = 0
#define SCKDIVCR_PCKA_2_0  12   // Peripheral Module Clock A           = 0
#define SCKDIVCR_ICK_2_0   24   // System Clock (ICLK) Select          = 0
#define SYSTEM_SCKSCR  ((volatile unsigned char *)(SYSTEM + 0xE026))  // System Clock Source Control Register
#define SCKSCR_CKSEL_2_0    0   // Clock Source Select - See section 8.2.2
#define SYSTEM_PLLCR   ((volatile unsigned char *)(SYSTEM + 0xE02A))  // PLL Control Register
#define PLLCR_PLLSTP        0   // PLL Stop Control; 0: PLL is operating, 1: PLL is stopped
#define SYSTEM_PLLCCR2 ((volatile unsigned char *)(SYSTEM + 0xE02B))  // PLL Clock Control Register 2
#define PLLCCR2_PLLMUL_4_0  0   // PLL Frequency Multiplication Factor Select
#define PLLCCR2_PLODIV_1_0  6   // PLL Output Frequency Division Ratio Select

#define SYSTEM_MOSCCR   ((volatile unsigned char *)(SYSTEM + 0xE032))  // Main Clock Oscillator Control Register
#define MOSCCR_MOSTP        0   // Main Clock Oscillator Stop; 0: Main clock oscillator is operating, 1: MCO is stopped
#define SYSTEM_HOCOCR   ((volatile unsigned char *)(SYSTEM + 0xE036))  // High-Speed On-Chip Oscillator Control Register
#define HOCOCR_HCSTP        0   // HOCO Stop; 0: HOCO is operating, 1: HOCO is stopped
#define SYSTEM_MOCOCR   ((volatile unsigned char *)(SYSTEM + 0xE038))  // Middle-Speed On-Chip Oscillator Control Register
#define MOCOCR_MCSTP        0   // MOCO Stop; 0: MOCO is operating, 1: MOCO is stopped

#define SYSTEM_MOSCWTCR ((volatile unsigned char *)(SYSTEM + 0xE0A2))  // Main Clock Oscillator Wait Control Register
#define MOSCWTCR_MSTS_3_0   0   // Main Clock Oscillator Wait Time Setting
#define SYSTEM_HOCOWTCR ((volatile unsigned char *)(SYSTEM + 0xE0A5))  // High-Speed On-Chip Oscillator Wait Control Register
#define HOCOWTCR_MSTS_2_0   0   // HOCO Wait Time Setting

#define SYSTEM_MOMCR    ((volatile unsigned char *)(SYSTEM + 0xE413))  // Main Clock Oscillator Mode Oscillation Control Register
#define MOMCR_MODRV1        3   // Main Clock Oscillator Drive Capability 1 Switching; 0: 10 MHz to 20 MHz, 1: 1 MHz to 10 MHz
#define MOMCR_MOSEL         6   // Main Clock Oscillator Switching; 0: Resonator, 1: External clock input

// Reset Status
#define SYSTEM_RSTSR0  ((volatile unsigned char  *)(SYSTEM + 0xE410))  //
#define RSTSR0_PORF    0   // Power-On Reset Detect Flag; 1: Power-on reset detected
#define SYSTEM_RSTSR1  ((volatile unsigned short *)(SYSTEM + 0xE0C0))  //
#define RSTSR1_IWDTRF  0   // Independent Watchdog Timer Reset Detect Flag; 1: Independent watchdog timer reset detected
#define RSTSR1_WDTRF   1   // Watchdog Timer Reset Detect Flag; 1: Watchdog timer reset detected
#define RSTSR1_SWRF    2   // Software Reset Detect Flag;       1: Software reset detected
#define SYSTEM_RSTSR2  ((volatile unsigned char  *)(SYSTEM + 0xE411))  //
#define RSTSR2_CWSF    0   // Cold/Warm Start Determination Flag; 0: Cold start, 1: Warm start

// Flash Memory
#define FCACHE_FCACHEE  ((volatile unsigned short *)(SYSTEM + 0xC100))  // Flash Cache Enable Register
#define FCACHEE_FCACHEEN    0    // FCACHE Enable - 0: Disable FCACHE, 1: Enable FCACHE.
#define FCACHE_FCACHEIV ((volatile unsigned short *)(SYSTEM + 0xC100))  // Flash Cache Invalidate Register
#define FCACHEIV_FCACHEIV   0    // Flash Cache Invalidate - 0: Do not invalidate, 1: Invalidate

// System Control Block
#define SCBBASE 0xE0000000
#define SCB_AIRCR                  ((volatile unsigned int *)(SCBBASE + 0xED0C))
#define SCB_AIRCR_VECTKEY_Pos      16U                                   // SCB AIRCR: VECTKEY Position
#define SCB_AIRCR_SYSRESETREQ_Pos  2U                                    // SCB AIRCR: SYSRESETREQ Position
#define SCB_AIRCR_SYSRESETREQ_Msk  (1UL << SCB_AIRCR_SYSRESETREQ_Pos)    // SCB AIRCR: SYSRESETREQ Mask

// From: https://mcuoneclipse.com/2015/07/01/how-to-reset-an-arm-cortex-m-with-software/

#define WFI_MS_DOWNCOUNT 1000
#define WFI_SECONDS_DELAY  10

// #define CLOCK_PLL    // ONLY use when external 12MHz crystal fitted e.g. EK-RA4M1 Dev-board

bool wfi_flag = true;       // Start with WFI mode active
bool usb_flag = true;       // USB Module active
bool moco_flag = false;     // True when switched to MOCO 8MHz oscillator
bool  pll_flag = false;     // True when PLL and external XTAL

int sys_clk_div = 1;

void setup()
  {
  Serial.begin(115200);
  while (!Serial){};
  Serial.println("\nWFI, SysClk switching, and USB Disable demo code.");
  Serial.println(" - use 'q' command to halt WFI before an IDE Upload");
  print_command();
  }


void loop()
  {
  static uint32_t loop_delay = 1000;
  static uint32_t seconds_count = 0;
  static uint32_t sys_clk_div_shift = 0;

  if(wfi_flag)                     // For testing, make sure sleep mode isn't on at bootup
    {
    *PFS_P111PFS_BY = 0x04;        // D13 - CLEAR LED
  	asm volatile("wfi");           // Stop here and wait for an interrupt
    *PFS_P111PFS_BY = 0x05;        // D13 - Set LED
    loop_delay--;
    if(loop_delay == 0)
      {
      loop_delay = (WFI_MS_DOWNCOUNT >> sys_clk_div_shift);
      seconds_count++;
      if(usb_flag == true)
        {
        Serial.print(".");          // print a "." once per second 
        }
      }
    }

  if(usb_flag == true)
    {
    if(Serial.available())           // If anything comes in on the USB Serial (which is done with USB interrupts)
      {
      char inbyte = Serial.read();
      Serial.write(inbyte);          // ... send it back out 

      switch (inbyte)                // Very basic control of operations
        {
        case 's':
          {
          wfi_flag = true;
          Serial.println("\nEnable Sleep");
          break;
          }
        case 'q':
          {
          wfi_flag = false;
          Serial.println("\nDisable Sleep");
         *PFS_P111PFS_BY = 0x04;        // D13 - CLEAR LED
          break;
          }
        case 'u':
          {
          usb_flag = false;
          seconds_count = 0;
          Serial.println("\nDisable USBFS module");
          delayMicroseconds(900);                        // Wait for USB serial print transaction...
          Serial.end();                                  // Probably does something?
          *USBFS_USBMC      = 0x0002;                    // Turn off USB power circuits
          *USBFS_USBBCCTRL0 = 0x0000;                    // Turn off Pin Functions
          *USBFS_SYSCFG     = 0x0000;                    // USBFS Operation Disable
          delayMicroseconds(1);                          // Wait to ensure module stopped
          *MSTP_MSTPCRB |= (0x01 << MSTPB11);            // Disable USBFS module
          if((moco_flag == true) || (pll_flag == true))  // If MOCO or PLL clock in use
            {
            disable_sys_clock_hoco();
            }
          break;
          }
        case 'm':
          {
          print_status();
          break;
          }
        case '?':
          {
          print_command();
          break;
          }
        case '0':
          {
          if(moco_flag == true)                 // If MOCO clock in use
            sys_clk_div_shift = 2;
          else
            sys_clk_div_shift = 0;              // PCLKB is already at x1/2
          loop_delay = 1;
          sys_clk_div = 1;
          Serial.println("\nSYSclk = 1x1");
          setup_sys_clock_divider(0x0);
          Serial.println(*SYSTEM_SCKDIVCR, BIN);
          break;
          }
        case '4':
          {
          if(moco_flag == true)                // If MOCO clock in use
            sys_clk_div_shift = 3 + 2;
          else
            sys_clk_div_shift = 3;
          loop_delay = 1;
          sys_clk_div = 16;
          Serial.println("\nSYSclk = 1/16");
          setup_sys_clock_divider(0x4);
          Serial.println(*SYSTEM_SCKDIVCR, BIN);
          break;
          }
        case '6':
          {
          if(moco_flag == true)                // If MOCO clock in use
            sys_clk_div_shift = 5 + 2;
          else
            sys_clk_div_shift = 5;
          loop_delay = 1;
          sys_clk_div = 64;
          Serial.println("\nSYSclk = 1/64");
          setup_sys_clock_divider(0x6);
          Serial.println(*SYSTEM_SCKDIVCR, BIN);
          break;
          }
#ifdef CLOCK_PLL            // Only use when external XTAL is fitted
        case '7':
          {
          if(moco_flag == true)
            {
            moco_flag = false;
            sys_clk_div_shift -= 2;
            }
          loop_delay = 1;
          Serial.println("\n Change to MOSC - XTAL & PLL"); 
          setup_sys_clock_pll();        
          pll_flag = true;
          break;
          }
#endif
        case '8':
          {
          sys_clk_div_shift += 2;
          loop_delay = 1;
          setup_sys_clock_moco();
          if(pll_flag == true)
            {
            pll_flag = false;
            Serial.println("\nChange from PLL to 8MHz MOCO"); 
            disable_sys_clock_pll();
            }
          else
            Serial.println("\nChange from HOCO to 8MHz MOCO"); 
            // Don't disable HOCO as used for USB-serial
          moco_flag = true;
          break;
          }
        case '9':
          {
          loop_delay = 1;
          setup_sys_clock_hoco();
          if(moco_flag == true)
            {
            moco_flag = false;
            sys_clk_div_shift -= 2;
            Serial.println("\nChange from MOCO to 48MHz HOCO");
            disable_sys_clock_moco();
            }
          else
            {
            pll_flag = false;
            Serial.println("\nChange from XTAL PLL to 48MHz HOCO");
            disable_sys_clock_pll();
            }
          break;
          }
        default:
          break;
        }
      }
    }
  else
    {
    if(seconds_count >= WFI_SECONDS_DELAY)  // Sortware reset needed to reinitialse USB with PC  
      { 
      *SCB_AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk);
      }
    }
  }

void print_status(void)
  {
  Serial.print("\nSysClk source  = ");
  if(pll_flag == true)                      // If external XTAL and PLL clock in use
    Serial.println("48 MHz PLL from XTAL");   
  else if(moco_flag == true)                // If MOCO clock in use
    Serial.println("8 MHz MOCO");
  else
    Serial.println("48 MHz HOCO");

  Serial.print("SysClk divider = 1/");
  Serial.print(sys_clk_div);

  Serial.print("\nMode = ");
  if(wfi_flag == false)
    Serial.println("No Sleeping");
  else
    Serial.println("Wake from IRQs");
  }

void print_command(void)
  {
  Serial.println("\nSingle Char Commands:");
  Serial.println("s = Enable  Sleep / Wake From Interrupt.");
  Serial.println("q = Disable Sleep / Wake From Interrupt.");
  Serial.println("u = USB Module Disable - code function HW-Reset after 10s delay.");
  Serial.println("0 = Set the System Clocks to IDE default.");
  Serial.println("4 = Change all System Clocks to x1/16 rate.");
  Serial.println("6 = Change all System Clocks to x1/64 rate.");
#ifdef CLOCK_PLL
  Serial.println("7 = Change System Clock to PLL with XTAL.");
  Serial.println("8 = Change System Clock to MOCO.");
  Serial.println("9 = Change System Clock to HOCO.");
#else
  Serial.println("8 = Change System Clock from HOCO to MOCO.");
  Serial.println("9 = Change System Clock from MOCO to HOCO.");
#endif
  Serial.println("m = Report mode - Clock settings, WFI or Constant-Looping, etc.");
  Serial.println("? = Display all Char Commands (this list).");
  }

/*
Restrictions on setting the clock frequency: ICLK ≥ PCLKA ≥ PCLKB, PCLKD ≥ PCLKA ≥ PCLKB, ICLK ≥ FCLKA
Restrictions on the clock frequency ratio: (N: integer, and up to 64)
ICLK:FCLK = N:1, ICLK:PCLKA = N: 1, ICLK:PCLKB = N: 1
ICLK:PCLKC = N:1 or 1:N, ICLK:PCLKD= N:1 or 1:N
PCLKB:PCLKC = 1:1 or 1:2 or 1:4 or 2:1 or 4:1 or 8:1
*/
// After reset:
// 0100 0100 0000 0100 MSBs
// 0100 0100 0100 0100 LSBs
// 
// From IDE
// 0001 0000 0000 0001 MSBs
// 0000 0001 0000 0000 LSBs

void setup_sys_clock_divider(int divider) // Divider for HOCO On-Chip Oscillator
  {
  *SYSTEM_PRCR      = 0xA501;            // Enable writing to the clock registers
  if(divider == 4)
    *SYSTEM_SCKDIVCR = 0x44044444;  // Set the clock dividerers to 1/16th rate
  else if(divider == 6)
    *SYSTEM_SCKDIVCR = 0x66066666;  // Set the clock dividerers to 1/64th rate
  else
    if(moco_flag == true)             // If MOCO clock in use, don't need wait on FLASH 
      *SYSTEM_SCKDIVCR = 0x00010100;  // Set the clock dividerers to main speeds
    else
      *SYSTEM_SCKDIVCR = 0x10010100;  // Set the clock dividerers to main speeds
    
  *SYSTEM_PRCR      = 0xA500;            // Disable writing to the clock registers
  }


char setup_sys_clock_moco(void)
  {
  *FCACHE_FCACHEE    = 0x0000;        // Disable the flash cache
  *SYSTEM_PRCR       = 0xA501;        // Enable writing to the clock registers
  *SYSTEM_MOCOCR     = 0x00;          // Start Middle-Speed On-Chip Oscillator Control Register
	asm volatile("dsb");                // Data bus Synchronization instruction
  delayMicroseconds(1);               // wait for MOCO to stabilise
  *SYSTEM_SCKSCR     = 0x01;          // Select MOCO as the system clock 
  *SYSTEM_PRCR       = 0xA500;        // Disable writing to the clock registers
  *FCACHE_FCACHEIV   = 0x0001;        // Invalidate the flash cache
  delayMicroseconds(1);               // wait for a moment
  char test = *FCACHE_FCACHEIV;       // Check that FCACHEIV.FCACHEIV is 0
  *FCACHE_FCACHEE    = 0x0001;        // Enable the flash cache
  return(test);
  }

char setup_sys_clock_hoco(void)
  {
  *FCACHE_FCACHEE    = 0x0000;        // Disable the flash cache
  *SYSTEM_PRCR       = 0xA501;        // Enable writing to the clock registers
// This part only needed is USB has been disable as otherwise HOCO is still running
  *SYSTEM_HOCOCR     = 0x00;          // Start High-Speed On-Chip Oscillator Control Register
	asm volatile("dsb");                // Data bus Synchronization instruction
  delayMicroseconds(1);               // wait for HOCO to stabilise

  *SYSTEM_SCKSCR     = 0x00;          // Select HOCO as the system clock 
  *SYSTEM_PRCR       = 0xA500;        // Disable writing to the clock registers
  *FCACHE_FCACHEIV   = 0x0001;        // Invalidate the flash cache
  delayMicroseconds(1);               // wait for a moment
  char test = *FCACHE_FCACHEIV;       // Check that FCACHEIV.FCACHEIV is 0
  *FCACHE_FCACHEE    = 0x0001;        // Enable the flash cache
  return(test);
  }

void setup_sys_clock_pll(void)        // Only use when external XTAL is fitted
  {
  *SYSTEM_PRCR     = 0xA501;          // Enable writing to the clock registers
  *SYSTEM_MOSCCR   = 0x01;            // Make sure XTAL is stopped
  *SYSTEM_MOMCR    = 0x00;            // MODRV1 = 0 (10 MHz to 20 MHz); MOSEL = 0 (Resonator)
  *SYSTEM_MOSCWTCR = 0x07;            // Set stability timeout period 
  *SYSTEM_MOSCCR   = 0x00;            // Enable XTAL
	asm volatile("dsb");                // Data bus Synchronization instruction
  char enable_ok = *SYSTEM_MOSCCR;    // Check bit 
  delay(100);                         // wait for XTAL to stabilise  
  *SYSTEM_PLLCR    = 0x01;            // Disable PLL
  *SYSTEM_PLLCCR2  = 0x07;            // Setup PLLCCR2_PLLMUL_4_0 PLL PLL Frequency Multiplication to 8x
  *SYSTEM_PLLCCR2 |= 0x40;            // Setup PLLCCR2_PLODIV_1_0 PLL Output Frequency Division to /2
  *SYSTEM_PLLCR    = 0x00;            // Enable PLL
  delayMicroseconds(1000);            // wait for PLL to stabilise
  *SYSTEM_SCKSCR   = 0x05;            // Select PLL as the system clock 
  *SYSTEM_PRCR     = 0xA500;          // Disable writing to the clock registers
  }

void disable_sys_clock_hoco(void)
  {
  *SYSTEM_PRCR   = 0xA501;       // Enable writing to the clock registers
  *SYSTEM_HOCOCR = 0x01;         // Stop the HOCO clock
  *SYSTEM_PRCR   = 0xA500;       // Disable writing to the clock registers
  }

void disable_sys_clock_moco(void)
  {
  *SYSTEM_PRCR   = 0xA501;       // Enable writing to the clock registers
  *SYSTEM_MOCOCR = 0x01;         // Stop the MOCO clock
  *SYSTEM_PRCR   = 0xA500;       // Disable writing to the clock registers
  }

void disable_sys_clock_pll(void)
  {
  *SYSTEM_PRCR   = 0xA501;       // Enable writing to the clock registers
  *SYSTEM_MOSCCR = 0x01;         // Stop the Main clock
  *SYSTEM_PRCR   = 0xA500;       // Disable writing to the clock registers
  }
2 Likes

Latest version code now up on GitHub:

https://github.com/TriodeGirl/Arduino-UNO-R4-Wake_from_interrupt-and-system-clock-switching/

2 Likes

Hello Susan
I'm back...
Thank you again a thousand times for this excellent work
I tried all the configurations that you coded: nominal, sleep mode woken up by interruption, USB mode inhibited, clock modes /16 and /64, LED completely removed: In each mode, I have a significant reduction in consumption , which was divided by 2 in the end (I have other powered components: 2x L293D (of which I control the 5V power supply by a P-channel MOSFET), a PCF 8235 circuit, a LoRA module...)
Thanks again, when I see your code which manipulates the lowest layer, I would have been incapable of doing that!

1 Like