Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
card10
firmware
Commits
77bd73ba
Commit
77bd73ba
authored
Sep 16, 2021
by
Rahix
Browse files
Merge 'Switch systick to 32 kHz clock source'
See merge request
!475
parents
e99885b5
e524d839
Pipeline
#5255
passed with stages
in 1 minute and 47 seconds
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
pycardium/mphalport.c
View file @
77bd73ba
...
...
@@ -20,6 +20,30 @@
#include
<stdio.h>
#include
<string.h>
// Smallest interval which can be reached exactly
#define SYSTICK_INTERVAL_US 15625ULL
#define SYSTICK_FREQ_HZ (1000000 / SYSTICK_INTERVAL_US)
/*
* Copied from core_cm4.h and modified to select the
* 32768 Hz RTC crystal as the clock source */
static
uint32_t
systick_config
(
uint32_t
ticks
)
{
if
((
ticks
-
1
)
>
SysTick_LOAD_RELOAD_Msk
)
return
(
1
);
/* Reload value impossible */
SysTick
->
LOAD
=
ticks
-
1
;
/* set reload register */
NVIC_SetPriority
(
SysTick_IRQn
,
(
1
<<
__NVIC_PRIO_BITS
)
-
1
);
/* set Priority for Systick Interrupt */
SysTick
->
VAL
=
0
;
/* Load the SysTick Counter Value */
SysTick
->
CTRL
=
SysTick_CTRL_TICKINT_Msk
|
SysTick_CTRL_ENABLE_Msk
;
/* Enable SysTick IRQ and SysTick Timer */
return
(
0
);
/* Function successful */
}
/* Initialize everything for MicroPython */
void
pycardium_hal_init
(
void
)
{
...
...
@@ -33,9 +57,9 @@ void pycardium_hal_init(void)
epic_interrupt_enable
(
EPIC_INT_UART_RX
);
/*
* Configure SysTick timer for
1ms
period.
* Configure SysTick timer for
SYSTICK_INTERVAL_US
period.
*/
S
ys
T
ick_
C
onfig
(
SystemCoreClock
/
1000
);
s
ys
t
ick_
c
onfig
(
32768
/
SYSTICK_FREQ_HZ
);
}
/******************************************************************************
...
...
@@ -141,14 +165,21 @@ void SysTick_Handler(void)
*/
static
uint64_t
systick_get_us
()
{
uint32_t
val
,
count
;
uint32_t
irqsaved
=
__get_PRIMASK
();
__set_PRIMASK
(
0
);
uint64_t
counts_per_us
=
SystemCoreClock
/
1000000
;
uint64_t
us
=
systick_count
*
1000
+
(
SysTick
->
LOAD
-
SysTick
->
VAL
)
/
counts_per_us
;
/* The asynchronous/slow clocking of the systick means that
* its value can jump to 0 before the interrupt is triggered.
* Simply wait until it is not 0 and then read the count. */
do
{
__set_PRIMASK
(
0
);
val
=
SysTick
->
VAL
;
count
=
systick_count
;
__set_PRIMASK
(
irqsaved
);
}
while
(
val
==
0
);
__set_PRIMASK
(
irqsaved
);
uint64_t
us
=
count
*
SYSTICK_INTERVAL_US
+
(
SysTick
->
LOAD
-
val
)
*
1000000ULL
/
32768
;
return
us
;
}
...
...
@@ -160,14 +191,12 @@ static void systick_delay_precise(uint32_t us)
* instruction, read the current timer value to ensure as little skew as
* possible.
*
* Subtract 0.3us (constant_offset) to account for the duration of the
* calculations.
* Accuracy is about 30 us (due to the 32 kHz systick)
*/
uint32_t
count_to_overflow
=
SysTick
->
VAL
;
uint32_t
count_reload
=
SysTick
->
LOAD
;
uint32_t
clocks_per_us
=
SystemCoreClock
/
1000000
;
uint32_t
constant_offset
=
clocks_per_us
*
3
/
10
;
uint32_t
delay_count
=
us
*
clocks_per_us
-
constant_offset
;
uint32_t
delay_count
=
us
*
32768
/
1000000
;
/*
* Calculate the final count for both paths. Marked as volatile so the
...
...
@@ -203,14 +232,14 @@ static void systick_delay_sleep(uint32_t us)
while
(
1
)
{
uint64_t
now
=
systick_get_us
();
if
(
now
>
=
final_time
)
{
if
(
(
now
+
SYSTICK_INTERVAL_US
)
>
final_time
)
{
break
;
}
/*
* Sleep with WFI if more than
1ms of delay is remaining. The
* SysTick interrupt is guaranteed to
happen within any timespan
*
of 1ms
.
* Sleep with WFI if more than
SYSTICK_INTERVAL_US of delay
*
is remaining. The
SysTick interrupt is guaranteed to
*
happen within any timespan of SYSTICK_INTERVAL_US
.
*
* Use a critical section encompassing both the check and the
* WFI to prevent a race-condition where the interrupt happens
...
...
@@ -218,7 +247,7 @@ static void systick_delay_sleep(uint32_t us)
*/
uint32_t
irqsaved
=
__get_PRIMASK
();
__set_PRIMASK
(
0
);
if
((
now
+
1000
)
<
final_time
)
{
if
((
now
+
SYSTICK_INTERVAL_US
)
<
final_time
)
{
__WFI
();
}
__set_PRIMASK
(
irqsaved
);
...
...
@@ -234,6 +263,11 @@ static void systick_delay_sleep(uint32_t us)
*/
mp_handle_pending
(
true
);
}
uint64_t
now
=
systick_get_us
();
if
(
now
<
final_time
)
{
systick_delay_precise
(
final_time
-
now
);
}
}
static
void
systick_delay
(
uint32_t
us
)
...
...
@@ -243,12 +277,12 @@ static void systick_delay(uint32_t us)
/*
* For very short delays, use the systick_delay_precise() function which
* delays with a microsecond accuracy. For anything >
1ms
, use
* delays with a microsecond accuracy. For anything >
SYSTICK_INTERVAL_US
, use
* systick_delay_sleep() which puts the CPU to sleep when nothing is
* happening and also checks for MicroPython interrupts every now and
* then.
*/
if
(
us
<
1000
)
{
if
(
us
<
SYSTICK_INTERVAL_US
)
{
systick_delay_precise
(
us
);
}
else
{
systick_delay_sleep
(
us
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment