Skip to content

MSP432P4xx System Controller

Location

peripherals

Type

Implementation

Background

The following internal oscillators are available in the clock system module:

  1. Low-frequency oscillator (LFXT).
  2. High-frequency oscillator (HFXT).
  3. Digitally controlled oscillator (DCO).
  4. Very low-power low-frequency oscillator (VLO).
  5. Low-power low-frequency oscillator (REFO).
  6. Low-power oscillator (MODOSC).
  7. System oscillator (SYSOSC).

The MSP432P4xx MCUs have five primary clock signals which can be driven by the oscillators mentioned above to drive the individual peripheral modules:

  1. Auxiliary clock (ACLK).
  2. Master clock (MCLK) which drives the CPU.
  3. Subsystem clock (HSMCLK).
  4. Low-speed subsystem clock (SMCLK).
  5. Low-speed backup domain clock (BCLK).

More information regarding the clock system module can be found in the Ti MSP432P4xx Technical Reference Manual.

Overview

The system controller allows the configuration of the clock system module. By default the Master clock and subsequently the CPU clock, shall be driven by the digitally controlled oscillator (DCOCLK). The DCOCLK can be configured to produce a target nominal frequency between 1 MHz and 48 MHz. For the SJSU-Dev2 platform, a default CPU clock rate of 48 MHz is used.

Detailed Design

API

class SystemController : public sjsu::SystemController
{
 public:
  enum class Oscillator : uint8_t;
  enum class Clock : uint8_t;
  enum class ClockDivider : uint8_t;

  struct ClockConfiguration_t;

  explicit constexpr SystemController(
      ClockConfiguration_t & clock_configuration);

  void Initialize() override;
  void * GetClockConfiguration() override;
  units::frequency::hertz_t GetClockRate(
     ResourceID peripheral) const override;
  void SetClockDivider(Clock clock, ClockDivider divider) const;

  bool IsPeripheralPoweredUp(ResourceID) const override;
  void PowerUpPeripheral(ResourceID) const override;
  void PowerDownPeripheral(ResourceID) const override;

 private:
  void UnlockClockSystemRegisters() const;
  void LockClockSystemRegisters() const;
  void WaitForClockReadyStatus(Clock clock) const;
  void SetClockSource(Clock clock, Oscillator source) const;
  units::frequency::hertz_t ConfigureDcoClock() const;
  units::frequency::hertz_t ConfigureReferenceClock() const;
};

Clock System on Reset

See 6.2 Clock System Operation.

Writing Changes to the Clock System registers

The clock system registers are locked and a 16-bit key, 0x695A, must be written to the Clock System Key register (CSKEY) to unlock the registers before any configurations can be made. The registers can be locked again by writing any other value after the desired configurations are set.

void UnlockClockSystemRegister() const

Unlocks the clock system registers by writing 0x0695A.

void LockClockSystemRegister() const

Locks the clock system registers by writing 0x0000.

Initialization

Returns<void> Initialize() override

Performs the following sequence to configure various clock modules:

  1. Configure the DCO clock and reference clock by invoking ConfigureDcoClock() and ConfigureReferenceClock().
  2. Set then clock divider for each of the primary clocks.
  3. Set the clock source for the available primary clocks.
  4. Determine and store the running clock rates for the primary clocks and the reference clock.

An Error_t is returned if:

  1. ConfigureDcoClock() returns an error.
  2. ConfigureReferenceClock() returns an error.
  3. The configured clock source for the auxiliary clock is not Oscillator::kLowFrequency, Oscillator::kVeryLowFrequency, or Oscillator::kReference.
  4. The configured clock source for the backup clock is not Oscillator::kLowFrequency or Oscillator::kReference.

Returns<units::frequency::hertz_t> ConfigureDcoClock() const

Performs the following sequence to configure the DCO clock:

  1. Ensure the target frequency is between 1 MHz and 48 MHz.
  2. Determine the DCO tuning configuration values by finding the DCO frequency range, DCO constant, and DCO calibration values based on the desired target frequency.
  3. Calculate the signed 10-bit tuning value.
  4. Write the configurations to the CSCTL0 register.

See 6.2.8.3 DCO Ranges and Tuning for more information regarding configuring the DCO clock.

An Error_t is returned if the target frequency is not between 1 MHz and 48 MHz.

Returns<units::frequency::hertz_t> ConfigureReferenceClock() const

Configures the reference clock to run at 32.768 kHz or 128 kHz.

An Error_t is returned if the frequency select value in the clock configuration for the reference clock is not 0b0 or 0b1.

Returns<void> SetClockSource(Clock clock, Oscillator oscillator) const

Sets the desired clock source to drive a primary clock signal.

An Error_t is returned if clock is not one of the primary clocks.

Returns<void> SetClockDivider(Clock clock, ClockDivider divider) const

Sets the desired clock divider for a primary clock signal.

An Error_t is returned if clock is not one of the primary clocks (excluding the backup clock).

void WaitForClockReadyStatus(Clock clock) const

Checks and waits for the specified primary clock signal to become stable before proceeding. This is necessary when changing the a clock signal's frequency or divider.

Getting the Clock Rate of a Clock Signal

Returns<units::frequency::hertz_t> GetClockRate(ResourceID peripheral) const override

Gets the clock rate of one of the 10 available clock modules.

An Error_t is returned if peripheral is not one of the defined peripherals in the Modules namespace.

Unused Functions

The following functions are not implemented or used:

bool IsPeripheralPoweredUp(const ResourceID &) const override
void PowerUpPeripheral(const ResourceID &) const override
void PowerDownPeripheral(const ResourceID &) const override

Caveats

N/A

Future Advancements

N/A

Testing Plan

Unit Testing Scheme

The following functions shall be tested:

Initialize()

Each of the internal oscillators shall be used as a clock source to configure each primary clock. Additionally, clock divider values of 1, 2, 4, 8, 16, 32, 64, and 128 shall be set for each configuration:

  1. Configure auxiliary clock:
  2. The function should:
    • Set the selected auxiliary clock source select value in the CSCTL1 register.
    • Set the selected auxiliary clock divider select value in the CSCTL1 register.
    • Have a running auxiliary clock frequency that is equivalent of the selected clock source divided by the selected clock divider.
  3. The function should return an error if the clock source is not Oscillator::kLowFrequency, Oscillator::kVeryLowFrequency, or Oscillator::kReference.
  4. Configure master clock:
  5. The function should:
    • Set the selected master clock source select value in the CSCTL1 register.
    • Set the selected master clock divider select value in the CSCTL1 register.
    • Have a running master clock frequency that is equivalent of the selected clock source divided by the selected clock divider.
  6. Configure subsystem master clocks:
  7. The function should:
    • Set the selected subsystem master clock source select value in the CSCTL1 register.
    • Set the selected subsystem master clock divider select value in the CSCTL1 register.
    • Have a running subsystem master clock frequency that is equivalent of the selected clock source divided by the selected clock divider.
    • Set the selected low-speed subsystem master clock source select value in the CSCTL1 register.
    • Set the selected low-speed subsystem master clock divider select value in the CSCTL1 register.
    • Have a running low-speed subsystem master clock frequency that is equivalent of the selected clock source divided by the selected clock divider.
  8. Configure backup clock:
  9. The function should:
    • Set the selected backup clock source select value in the CSCTL1 register.
    • Have a running backup clock frequency that is equivalent of the select clock source.
  10. The function should return an error if the clock source is not Oscillator::kLowFrequency, or Oscillator::kReference.

GetClockRate(ResourceID peripheral)

The clock rates of clock signals that have a fixed frequency are verified.

  1. When peripheral = Modules::kLowFrequencyClock
  2. The function should return 32,768 Hz.
  3. When peripheral = Modules::kVeryLowFrequencyClock
  4. The function should return 9,400 Hz.
  5. When peripheral = Modules::kReferenceClock and reference clock is configured for 32.768 kHz
  6. The function should return 32,768 Hz.
  7. When peripheral = Modules::kReferenceClock and reference clock is configured for 128 kHz
  8. The function should return 128,000 Hz.
  9. When peripheral = Modules::kModuleClock
  10. The function should return 25,000,000 Hz.
  11. When peripheral = Modules::kSystemClock
  12. The function should return 5,000,000 Hz.

SetClockDivider(Clock clock, ClockDivider divider)

Clock divider values of 1, 2, 4, 8, 16, 32, 64, and 128 shall be set for each of the available primary clocks except for the backup clock.

  1. When divider = ClockDivider::kDivideBy1
  2. The function should set a clock divider select value of 0b000.
  3. When divider = ClockDivider::kDivideBy2
  4. The function should set a clock divider select value of 0b001.
  5. When divider = ClockDivider::kDivideBy4
  6. The function should set a clock divider select value of 0b010.
  7. When divider = ClockDivider::kDivideBy8
  8. The function should set a clock divider select value of 0b011.
  9. When divider = ClockDivider::kDivideBy16
  10. The function should set a clock divider select value of 0b100.
  11. When divider = ClockDivider::kDivideBy32
  12. The function should set a clock divider select value of 0b101.
  13. When divider = ClockDivider::kDivideBy64
  14. The function should set a clock divider select value of 0b110.
  15. When divider = ClockDivider::kDivideBy128
  16. The function should set a clock divider select value of 0b111.

IsPeripheralPoweredUp()

  • Should always return false.

Demonstration Project

An example project using the system controller can be found here.