Skip to content

Commit

Permalink
Merge #1987
Browse files Browse the repository at this point in the history
1987: Added support for external clock source and systick user-defined clock value for ARM r=hudson-ayers a=valexandru

### Pull Request Overview

This pull request adds support for setting external clock source for systick
and extends the support for setting a user-defined clock speed for the 
systick.

This pull request is needed for [#1918](#1918) to work because for the i.MX RT 1052 EVKB 
board, even though syst_calib.SKEW = 0 and syst.calib.NOREF = 0, the 
calibration value is not correct and causes thesystick to overflow too fast. 

Also, if I select external clock source in syst_csr, which causes an external 
24 MHz clock source to be prescaled to 100KHz and used as systick, the 
system will work.

### Testing Strategy

This pull request was tested using the i.MX RT 1052 EVKB Board.

### Documentation Updated

- [x] No updates are required.

### Formatting

- [x] Ran `make prepush`.


Co-authored-by: Vochescu Alexandru <alexvochescu@gmail.com>
  • Loading branch information
bors[bot] and valexandru committed Jul 1, 2020
2 parents 10be569 + cc0e646 commit 709a33c
Showing 1 changed file with 38 additions and 11 deletions.
49 changes: 38 additions & 11 deletions arch/cortex-m/src/systick.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! ARM Cortex-M SysTick peripheral.

use kernel::common::registers::{register_bitfields, ReadOnly, ReadWrite};
use kernel::common::registers::{register_bitfields, FieldValue, ReadOnly, ReadWrite};
use kernel::common::StaticRef;

#[repr(C)]
Expand Down Expand Up @@ -53,6 +53,7 @@ register_bitfields![u32,
/// Documented in the Cortex-MX Devices Generic User Guide, Chapter 4.4
pub struct SysTick {
hertz: u32,
external_clock: bool,
}

const BASE_ADDR: *const SystickRegisters = 0xE000E010 as *const SystickRegisters;
Expand All @@ -65,7 +66,10 @@ impl SysTick {
/// Use this constructor if the core implementation has a pre-calibration
/// value in hardware.
pub unsafe fn new() -> SysTick {
SysTick { hertz: 0 }
SysTick {
hertz: 0,
external_clock: false,
}
}

/// Initialize the `SysTick` with an explicit clock speed
Expand All @@ -81,16 +85,32 @@ impl SysTick {
res
}

// Return the tic frequency in hertz. If the calibration value is set in
// hardware, use `self.hertz`, which is set in the `new_with_calibration`
// constructor.
/// Initialize the `SysTick` with an explicit clock speed and external source
///
/// Use this constructor if the core implementation does not have a
/// pre-calibration value and you need an external clock source for
/// the Systick.
///
/// * `clock_speed` - the frequency of SysTick tics in Hertz. For example,
/// if the SysTick is driven by the CPU clock, it is simply the CPU speed.
pub unsafe fn new_with_calibration_and_external_clock(clock_speed: u32) -> SysTick {
let mut res = SysTick::new();
res.hertz = clock_speed;
res.external_clock = true;
res
}

// Return the tic frequency in hertz. If the value is configured by the
// user using the `new_with_calibration` constructor return `self.hertz`.
// Otherwise, compute the frequncy using the calibration value that is set
// in hardware.
fn hertz(&self) -> u32 {
let tenms = SYSTICK_BASE.syst_calib.read(CalibrationValue::TENMS);
if tenms == 0 {
if self.hertz != 0 {
self.hertz
} else {
// The `tenms` register is the reload value for 10ms, so
// Hertz = number of tics in 1 second = tenms * 100
let tenms = SYSTICK_BASE.syst_calib.read(CalibrationValue::TENMS);
tenms * 100
}
}
Expand Down Expand Up @@ -143,16 +163,23 @@ impl kernel::SysTick for SysTick {
}

fn enable(&self, with_interrupt: bool) {
let clock_source: FieldValue<u32, self::ControlAndStatus::Register> = if self.external_clock
{
// CLKSOURCE 0 --> external clock
ControlAndStatus::CLKSOURCE::CLEAR
} else {
// CLKSOURCE 1 --> internal clock
ControlAndStatus::CLKSOURCE::SET
};

if with_interrupt {
SYSTICK_BASE.syst_csr.write(
ControlAndStatus::ENABLE::SET
+ ControlAndStatus::TICKINT::SET
+ ControlAndStatus::CLKSOURCE::SET,
ControlAndStatus::ENABLE::SET + ControlAndStatus::TICKINT::SET + clock_source,
);
} else {
SYSTICK_BASE
.syst_csr
.write(ControlAndStatus::ENABLE::SET + ControlAndStatus::CLKSOURCE::SET);
.write(ControlAndStatus::ENABLE::SET + clock_source);
}
}
}

0 comments on commit 709a33c

Please sign in to comment.