How do I turn off the clock for RF? CLOCK_CONTROL_NRF_SUBSYS_HF

Hi,

On nRF52811 I use simple ESB radio for TX.  Before TX I turn Clock for radio on like in the example:

int clocks_start(void)
{
	int err;
	int res;
	struct onoff_manager *clk_mgr;
	struct onoff_client clk_cli;

	clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
	if (!clk_mgr) {
		return -ENXIO;
	}

	sys_notify_init_spinwait(&clk_cli.notify);

	err = onoff_request(clk_mgr, &clk_cli);
	if (err < 0) {
		return err;
	}

	do {
		err = sys_notify_fetch_result(&clk_cli.notify, &res);
		if (!err && res) {

			return res;
		}
	} while (err);

	return 0;
}

After TX is done, I want to turn this clock OFF. I assume at least that I have to do it - because after the TX I want to go to sleep mode with the lowest possible consumption. Now After TX is done, the CPU has nothing to do and the consumption is about 400 uA, when I do not turn the HF clock to ON the power consumption falls down about to 7 uA.

How to turn the clock off? Or something else I need to do?

P.S. Where I can find this kind of information? I am used to work with STM32 - Go to datasheet - find register and coresponding bit, then look in to HAL or LL lib and I am looking for the fuctions which works with this bit it - then I can easily find the function to be called. But in Nordic SDK I am lost.. How do you do that?

Thank you very much

Parents
  • Hello,

    Thank you for contacting DevZone at NordicSemi.

    To go to the Datasheet / Product Specification of any nordic SoC, please go to InfoCenter or the TechDocs.

    You will find detailed chapters on peripherals and their registers.

    We also provide HAL and Driver files for nordic peripherals. We have a collection of drivers and HAL called NRFX.

    You will find all these within the SDK and on the Github.

    As the Nordic's Connect SDK (NCS) is Zephyr RTOS based sdk, it is preferred to use Zephyr APIs and libraries.

    Also, we refer our customers to base their designs or start with the samples provided in the NCS (which contains both the Zephyr samples and Nordic specific samples).

    I am not sure how relevant to you it will be, but you can start by looking at ESB Transmitter sample, and then modify the code as per your requirements.

    Coming to the query which you have:
    As ESB is one of the supported protocols in the SDK, we has This ESB user guide that describes what it is and how to use with nordic devices.
    Within the product specification, we see that the clock system has "start" and "stop" tasks and have two corresponding events called "started" and "stopped".

    To start the HFClock, we need to set/enable the "start" task for HFClock and wait till it has been enabled.
    To stop the HFClock, we need to set/enable the "stop" task for HFClock and wait till it has been disabled.

    Showing sample code for starting HFClock:

    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);

    With regards,

    Naeem

  • Hi Naeem,

    Thank you for detailed answer!. Your code solved my problem. Anyway I would prefer to use Zephyr API as you wrote. I went to zephyr API and found this. Could it be he function what I am looking for to STOP HFLCK? 

    If yes, the input params *device  and sys - where I can get it? In nrf52840dk_nrf52811.dts I could not find nothing about clk.

    Maybe rather than a solution, I would be interested in how to proceed so that I can use the API myself next time.

  • Hello,

    Yes, you can use that API.

    From the 

    #include <zephyr/drivers/clock_control.h>
     we have 
    static int clock_control_on(const struct device *dev, clock_control_subsys_t sys);

    where the device is the clock-peripheral and the clock-control-subsystem is the HFCLock subsystem.

    (For details, please look at clock_control.h, nrf_clock_control.h, and clock_control_nrf.c).

    We can get the device and subsystem as:

    #define sys ((clock_control_subsys_t)CLOCK_CONTROL_NRF_TYPE_HFCLK)
    
    static const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(clock));
    

    /BR, Naeem

  • Thank you,

    I have tried but still can't succeed: I am exactly following the ESB TX example. All I need is to turn off the HFCLOCK after each transmission (believing that I reduce consumption to a minimum). I use Zephyr and my goal is to periodically transmit one packet every second. I have a SW timer that is triggered after each TX done and transmits again in a second, so I want Zephyr to put the processor to sleep as deeply as possible to reduce consumption between each transmission. I tried 2 ways:

    1. Using registers:
      NRF_CLOCK->TASKS_HFCLKSTOP = 1;
      while ((NRF_CLOCK->HFCLKSTAT & (1<<16)));
      But when I do this, HFCLKSTAT only changes the source from Xtall to RC, but STATE is still running, does that mean that the internal HFCLK RC is needed as a source for CPU operation and cannot be turned off, but is it turned off by zephyr upon entering sleep?

    2. I called while(clock_control_off(dev, CLOCK_CONTROL_NRF_SUBSYS_HF) !=0); But this loop gets stuck and never ends - the clock is still running on Xtall.

    3. If I disable the HCLK through the registers after TX_Done, it seems that Zephyr falls asleep and is no longer awakened by the software timer which is supposed to send the next packet. I don't understand this. However, if I connect via RTT to CPU what is happening in the processor, everything works fine. 


      Thank you.
  • Hello,

    Sorry for the delayed response.

    Is there any update at your end?

    What kind of error / issues you got after using that API?

    I started with blinky sample, and then incorporated the header files and then called those functions to enable and disable the HFClock.

    I am repeating in a loop with 10 seconds for each

    In the power profiler, I can see the average current consumption difference

    When the HFClock is ON, average current consumption is ~185uA higher than the case when HFClock is OFF.

    This is how I have defined the sys and dev:

    #define sys CLOCK_CONTROL_NRF_SUBSYS_HF
    static const struct device *const dev = DEVICE_DT_GET_ONE(nordic_nrf_clock);

    /BR, Naeem

Reply
  • Hello,

    Sorry for the delayed response.

    Is there any update at your end?

    What kind of error / issues you got after using that API?

    I started with blinky sample, and then incorporated the header files and then called those functions to enable and disable the HFClock.

    I am repeating in a loop with 10 seconds for each

    In the power profiler, I can see the average current consumption difference

    When the HFClock is ON, average current consumption is ~185uA higher than the case when HFClock is OFF.

    This is how I have defined the sys and dev:

    #define sys CLOCK_CONTROL_NRF_SUBSYS_HF
    static const struct device *const dev = DEVICE_DT_GET_ONE(nordic_nrf_clock);

    /BR, Naeem

Children
  • Thank you very very much, your code saved mea nd it works, I used code bellow, But I would be interested in why the codes below didn't work the same way.

    For Turning Off I used:

    NRF_CLOCK->TASKS_HFCLKSTOP = 1;
    while ((NRF_CLOCK->HFCLKSTAT & (1<<0)));  
    or 
    while(clock_control_off(dev, CLOCK_CONTROL_NRF_SUBSYS_HF) !=0);
    And for On I used:
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    or 
    clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
        if (!clk_mgr) {
            return -ENXIO;
        }

        sys_notify_init_spinwait(&clk_cli.notify);

        err = onoff_request(clk_mgr, &clk_cli);
        if (err < 0) {
            return err;
        }

        do {
            err = sys_notify_fetch_result(&clk_cli.notify, &res);
            if (!err && res) {

                return res;
            }
        } while (err);
  • Did you try and test like the code provided?

Related