Name

Power Management — Details

Synopsis

#include <cyg/hal/hal_io.h>
    

void hal_str7xx_clocks_setup(int index);

void hal_str7xx_set_clock_speed(int index);

cyg_uint32 hal_str7xx_get_clock_speed(void);

cyg_bool hal_str7xx_mode_stop(void);

void hal_str7xx_mode_standby(void);

cyg_uint32 hal_str7xx_startup_mode(void);

void hal_str7xx_uart_setbaud(cyg_uint32 uart, cyg_uint32 baud);

void hal_str7xx_uart_reinit(void);

void hal_str7xx_i2c_init(cyg_uint32 bus, cyg_uint32 clock);

void hal_str7xx_i2c_reinit(void);

void hal_str7xx_watchdog_init(cyg_uint32 timeout);

void hal_str7xx_can_init(cyg_uint32 devno, cyg_uint32 clock);

void hal_str7xx_can_reinit(void);

void hal_str7xx_adc_init(cyg_uint32 rate);

void hal_str7xx_adc_reinit(void);

void hal_str7xx_rtc_init(void);

void hal_str7xx_rtc_alarm_set(cyg_uint32 secs);

void hal_str7xx_rtc_alarm_cancel(void);

cyg_uint32 hal_str7xx_rtc_counter(void);

cyg_uint32 hal_str7xx_rtc_counter_set(cyg_uint32 secs);

Description

The STR7XX variant HAL provides support for managing the power consumption of the device. This consists of a collection of functions that may be used to adjust clock frequencies, system modes and other aspects of the device. These routines mainly comprise a "kit of parts" from which applications may construct their own power management policy. The reader is referred to the STR7XX hardware documentation for full details of clock and power management.

The main function is hal_str7xx_clocks_setup(index) which controls the frequencies of the main clocks: MCLK, which supplies the CPU and memories; PCLK1, which supplies APB1 including the I²C, SPI and UARTs; and PCLK2, which supplies APB2 including IO ports, Timers, RTC etc. The single argument to this function is an index into a table of hal_str7xx_clock_params structures, which is defined by the platform HAL. Each entry in the table has the following structure:

typedef struct
{
    char        *name;                  // Name string
    cyg_uint8   clk2_divider;           // 1, 2
    cyg_uint8   pll1_multiplier;        // 12, 16, 20, 24
    cyg_uint8   pll1_divider;           // 1..7
    cyg_uint8   rclk_select;            // RCLK_SELECT_* below
    cyg_uint8   mclk_divider;           // 1, 2, 4, 8
    cyg_uint8   pclk1_divider;          // 1, 2, 4, 8
    cyg_uint8   pclk2_divider;          // 1, 2, 4, 8
} hal_str7xx_clock_params;

#define RCLK_SELECT_CLK2        0
#define RCLK_SELECT_CLK2_16     1
#define RCLK_SELECT_PLL1        2
#define RCLK_SELECT_AF          3

__externC cyg_uint32 hal_str7xx_clock_param_index;

Each entry in the table corresponds to a single configuration of the clock hardware. Some care must be taken in specifying these entries, the resulting clocks will depend on the system input clock and the various multipliers and dividers; many configurations will result in out of range or otherwise illegal clock frequencies. See the manuals for the STR7XX variant and the platform for details.

It is recommended that the clk2_divider field is always set to 2. This causes the ocillator input to be divided by 2 and provides a more stable input to the rest of the clock circuity. Also, some registers in the RCCU are only accessible if MCLK is equal to RCLK, so the mclk_divider field should always be 1. These restrictions may be relaxed in special circumstances.

The last entry in this table should be all zeros, to mark the end of the table. A typical table would appear as follows:

const hal_str7xx_clock_params hal_str7xx_clock_param_table[] =
{
    // name               clk/  pll1* pll1/ rclk source          mclk/ pclk1/ pclk2/
    {  "32KHz"          ,   2,     0,    0, RCLK_SELECT_AF     ,    1,     1,     1 },
    {  "500KHz"         ,   2,     0,    0, RCLK_SELECT_CLK2_16,    1,     1,     1 },
    {  "8MHz"           ,   2,     0,    0, RCLK_SELECT_CLK2   ,    1,     1,     1 },
    {  "24/6/3MHz"      ,   2,    12,    4, RCLK_SELECT_PLL1   ,    1,     4,     8 },
    {  "32/32MHz"       ,   2,    16,    4, RCLK_SELECT_PLL1   ,    1,     1,     1 },
    {  "40/10/5MHz"     ,   2,    20,    4, RCLK_SELECT_PLL1   ,    1,     4,     8 },
    {  "40/40MHz"       ,   2,    20,    4, RCLK_SELECT_PLL1   ,    1,     1,     1 },
    {  "48/12/6MHz"     ,   2,    12,    2, RCLK_SELECT_PLL1   ,    1,     4,     8 },
    {  "48/24/12MHz"    ,   2,    12,    2, RCLK_SELECT_PLL1   ,    1,     2,     4 },

    {  0                ,   0,     0,    0,                   0,    0,     0,     0 }
};

cyg_uint32 hal_str7xx_clock_param_index = 5;

The naming convention used above is that a single frequency implies that all 3 clocks (MCLK, PCLK1 and PCLK2) are set to the same value. Two frequencies mean that MCLK is set to the first and both PCLK1 and PCLK2 are set to the second. Three frequencies show the values for MCLK/PCLK1/PCLK2 in order.

The variable hal_str7xx_clock_param_index indicates the table entry of the parameter set that is currently set. This should be initialized by the platform HAL to the index of the default parameter set, which will be used during initialization. hal_str7xx_clocks_setup() also sets a number of other global variables with the clock rates resulting from the parameter set in use:

__externC cyg_uint32 hal_str7xx_pclk1;          // PCLK1 frequency in Hz
__externC cyg_uint32 hal_str7xx_pclk2;          // PCLK2 frequency in Hz
__externC cyg_uint32 hal_str7xx_mclk;           // MCLK  frequency in Hz

Functions to initialize baud rate generators or prescaler dividers for various devices are also present:

hal_str7xx_uart_setbaud(uart, baud) sets the baud rate generator of the given UART to the given baud rate, based on the current value of PCLK1. UARTs are numbered 0 to 3, corresponding to the UARTs available on the device and baud rate is given in Hz. hal_str7xx_uart_reinit() causes all UARTs baud rate generators to be reinitialized using the last baud rate setting and the current PCLK1 value. It is usually called after changing the system clocks.

hal_str7xx_i2c_init(bus, clock) initializes the clock divider of the given I2C bus to the given value based on the current value of PCLK1. The bus numbers are either 0 or 1, and the clock rate is given in Hz. hal_str7xx_i2c_reinit() causes all I2C busses clock dividers to be reinitialized using the last clock rate setting and the current PCLK1 value.

hal_str7xx_watchdog_init(timeout) initializes the watchdog timeout based on the current PCLK2 setting. The timeout is given in microseconds. Some care is needed in setting this value since the resolution of the prescaler and the width of the 16 bit counter mean that certain timeouts may not be achievable at different PCLK2 frequencies.

hal_str7xx_can_init(devno, clock) initializes the clock divider of the given CAN device to the given baud rate based on the current PCLK1 setting. This function sets the entire Bit Timing Register, including the bit segment lengths and the synchronization jump width as well as the clock divider. While this interface is designed to support multiple CAN devices, the current implementation only supports a single CAN bus. The return value from this function indicates whether the requested clock frequency can be supported: zero if it is, -1 if not. hal_str7xx_can_reinit() causes the bit timings for all CAN busses to be reinitialized based on the current value of PCLK1.

hal_str7xx_adc_init( rate ) initializes the prescaler for the ADC device based on the current PCLK2 setting. The rate argument gives the sample rate for each channel in samples per second. All channels share the same sample rate and are sampled on a round-robin basis. Therefore the combined sample rate, and hence maximum interrupt rate, will be four times this frequency. hal_str7xx_adc_reinit() causes the rate to be reinitialized based on the current value of PCLK2.

hal_str7xx_mode_stop() puts the STR7XX into STOP mode. Aside from entering STOP mode, all this routine does is set the WKUP-INT bit in the XTI CTRL register so that any of the external interrupt lines may be used to restart the system from STOP. However, it does not configure or unmask these lines. Instead, they may be unmasked and configured using the standard interrupt control API (cyg_interrupt_unmask(), cyg_interrupt_configure() etc.) It is also possible to configure the RTC to wake the STR7XX from STOP mode. The value returned from this function indicates whether STOP mode was entered: true if it was, false if not. It is usually adequate to just retry in the case of failed entry.

hal_str7xx_mode_standby() puts the STR7XX into STANDBY mode. As with entering STOP mode, it is the responsibility of the caller to configure the external interrupt lines and RTC to bring the system out of STANDBY mode. Exit from STANDBY mode causes the STR7XX to reboot, so if this function returns, then an error has occurred during entry to STANDBY. It is usually adequate to just retry in this case.

[Note]Note

At the time of writing, it has not been possible, at least on the STR710-EVAL board, to test RTC wakeup from STANDBY mode. It is believed that this is due to a silicon bug in the version of the STR710 present on the board.

hal_str7xx_startup_mode() returns the reason for the last restart. It indicates whether the restart was as a result of one of the following events:

  • STARTUP_MODE_RESET: Standard power-on reset.
  • STARTUP_MODE_WAKEUP: External WAKEUP event.
  • STARTUP_MODE_LOW_VOLTAGE: Low voltage detected.
  • STARTUP_MODE_RTC_ALARM: RTC alarm.
  • STARTUP_MODE_WATCHDOG: Watchdog expiry.
  • STARTUP_MODE_SOFTWARE: Software reset.

hal_str7xx_set_clock_speed(index) is a wrapper function that reprograms all the clocks and baud rate generators. The argument is the same index into the platform HAL supplied parameter table as given to hal_str7xx_clocks_setup(). After calling that function it also calls hal_str7xx_uart_reinit(), hal_str7xx_i2c_reinit(), hal_str7xx_can_reinit(), HAL_CLOCK_INITIALIZE() and hal_str7xx_watchdog_init(). Unlike hal_str7xx_clocks_setup(), this function checks that the supplied index is valid, and returns false if it is not.

hal_str7xx_get_clock_speed() returns the parameter table index given to the last call to hal_str7xx_clocks_setup() or hal_str7xx_set_clock_speed().

The HAL also contains functions to control the Real Time Clock, RTC. These are mainly oriented towards using the RTC to resume the system from STOP or STANDBY mode. Before making any other calls to the RTC routines, the application must call hal_str7xx_rtc_init() to initialize the device. Calling hal_str7xx_rtc_alarm_set(secs) sets the alarm to fire after the given number of seconds. After the alarm had fired, or to prevent it firing, call hal_str7xx_rtc_alarm_cancel(). Calling hal_str7xx_rtc_counter() returns the current value of the RTC counter, which counts seconds. Function hal_str7xx_rtc_counter_set( secs ) sets the RTC counter to the given value. These last two function may be used by a wallclock driver to provide time and date functionality.

RedBoot Support

The STR7XX HAL installs a number of RedBoot commands to allow testing of the power management support.

speed [-l] [index]

This command reports and sets the clock speed of the STR7XX. Giving the command on its own, with no arguments, lists the available speed settings:

RedBoot> speed
   0        32KHz
   1       500KHz
   2         8MHz
   3    24/6/3MHz
   4   40/10/5MHz
*  5   48/12/6MHz
   6  48/24/12MHz
RedBoot>

The index numbers on the left are used as arguments to the speed command. The names on the right correspond to the clock parameter set names described before. The parameter set currently in force is indicated by an asterisk in the first column. If the -l option is given, then more details of the parameter sets are given, together with the current settings of MCLK, PCLK1 and PCLK2:

RedBoot> speed -l
MCLK: 48000000, PCLK1 12000000, PCLK2 6000000
C Ix         Name CLK/ PLL1* PLL1/    RCLK MCLK/ PCLK1/ PCLK2/
   0        32KHz   2     0     0       AF   1     1      1
   1       500KHz   2     0     0  CLK2/16   1     1      1
   2         8MHz   2     0     0     CLK2   1     1      1
   3    24/6/3MHz   2    12     4     PLL1   1     4      8
   4   40/10/5MHz   2    20     4     PLL1   1     4      8
*  5   48/12/6MHz   2    12     2     PLL1   1     4      8
   6  48/24/12MHz   2    24     2     PLL1   2     4      8
RedBoot>

Supplying the speed command with the index number of a parameter set will change the STR7XX to use that set of clock parameters:

RedBoot> speed 3
Set clock speed 3, please wait...
Now running at new speed
RedBoot> speed -l
MCLK: 32000000, PCLK1 32000000, PCLK2 32000000
C Ix         Name CLK/ PLL1* PLL1/    RCLK MCLK/ PCLK1/ PCLK2/
   0        32KHz   2     0     0       AF   1     1      1
   1       500KHz   2     0     0  CLK2/16   1     1      1
   2         8MHz   2     0     0     CLK2   1     1      1
   3    24/6/3MHz   2    12     4     PLL1   1     4      8
*  4     32/32MHz   2    16     4     PLL1   1     1      1
   5   40/10/5MHz   2    20     4     PLL1   1     4      8
   6     40/40MHz   2    20     4     PLL1   1     1      1
   7   48/12/6MHz   2    12     2     PLL1   1     4      8
   8  48/24/12MHz   2    12     2     PLL1   1     2      4
RedBoot>

Note that setting too low a speed may result in RedBoot not being able to program the serial baud rate generator to maintain the current speed.

stop

The stop command puts the STR7XX into STOP mode. The RTC will be programmed to wake the system up after 5 seconds. The device may also be woken up before that timeout using the WAKEUP line, if it is connected to a switch (as it is on the STR710-EVAL board).

standby

The standby command puts the STR7XX into STANDBY mode. The RTC will be programmed to wake the system up after 5 seconds. The device may also be woken up before that timeout using the WAKEUP line, if it is connected to a switch (as it is on the STR710-EVAL board).