blob: 9c05dd803ea152a5792df2017f2113b24c394a16 [file] [log] [blame]
Anthony DiGirolamo5828d032022-05-18 13:07:56 -07001// Copyright 2022 The Pigweed Authors
Anthony DiGirolamofb41f922021-03-02 14:32:01 -08002//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#include "pw_spin_delay/delay.h"
16
17#include <cstddef>
18#include <cstdint>
19
20namespace pw::spin_delay {
21
22// !!!WARNING!!!: This delay is not truly accurate! It's mostly just a rough
23// estimate! Also, it only works in a baremetal context with no interrupts
24// getting in the way or threads getting CPU time.
25//
26// TODO(amontanez): Replace this implementation with a loop checking a
27// pw_chrono clock.
28void WaitMillis(size_t delay_ms) {
29 // Default core clock. This is technically not a constant, but since Pigweed
30 // doesn't change the system clock a constant will suffice.
31 constexpr uint32_t kSystemCoreClock = 16000000;
32 constexpr uint32_t kCyclesPerMs = kSystemCoreClock / 1000;
33
34 // This is not totally accurate, but is close enough.
35 for (size_t i = 0; i < delay_ms; i++) {
36 // Do a 4 instruction loop enough times to be running for a millisecond.
37 // This is set up with assembly rather than a regular loop to make the
38 // instruction count predictable (no compiler variation).
39 uint32_t cycles = kCyclesPerMs;
40 asm volatile(
41 " mov r0, %[cycles] \n"
42 " mov r1, #0 \n"
43 "loop: \n"
44 " cmp r1, r0 \n"
45 " itt lt \n"
46 " addlt r1, r1, #4 \n"
47 " blt loop \n"
48 // clang-format off
49 : /*output=*/
50 : /*input=*/[cycles]"r"(cycles)
51 : /*clobbers=*/"r0", "r1"
52 // clang-format on
53 );
54 }
55}
56
57} // namespace pw::spin_delay