Skip to content
GitLab
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
46791795
Commit
46791795
authored
Sep 17, 2021
by
Rahix
Browse files
Merge 'pycardium: Use sleep API call while sleeping'
See merge request
!480
parents
77bd73ba
09e61d97
Pipeline
#5261
passed with stages
in 1 minute and 45 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
epicardium/drivers/sleep.c
View file @
46791795
...
...
@@ -15,6 +15,7 @@
#include
"mxc_pins.h"
#include
<stdint.h>
#include
<limits.h>
/* Most code is taken and adapted rom EvKitExamples/LP/main.c */
...
...
@@ -207,3 +208,16 @@ void sleep_deepsleep(void)
SystemCoreClockUpdate
();
MAX77650_setEN_SBB2
(
0
b110
);
}
int
epic_sleep
(
uint32_t
ms
)
{
/* Allow the interrupt module to break us out of a call to
* epic_sleep() */
uint32_t
count
=
ulTaskNotifyTake
(
pdTRUE
,
pdMS_TO_TICKS
(
ms
));
if
(
count
==
0
)
{
return
0
;
}
else
{
return
INT_MAX
;
}
}
epicardium/epicardium.h
View file @
46791795
...
...
@@ -33,6 +33,7 @@ typedef _Bool bool;
#define API_SYSTEM_EXEC 0x2
#define API_SYSTEM_RESET 0x3
#define API_BATTERY_VOLTAGE 0x4
#define API_SLEEP 0x5
#define API_INTERRUPT_ENABLE 0xA
#define API_INTERRUPT_DISABLE 0xB
...
...
@@ -335,6 +336,25 @@ API(API_SYSTEM_EXEC, int __epic_exec(char *name));
*/
API
(
API_SYSTEM_RESET
,
void
epic_system_reset
(
void
));
/**
* Sleep for the specified amount of time.
*
* This call will block for at most the specified amount of time. It allows epicardium to
* reduce clock speed of the system until this call is finished.
*
* This call returns early if an interrupt is signaled from epicardium.
*
* The clock source of epicardium has a limited amount of accuracy. Tolerances
* of +- 10% have been observed. This means that the sleep time also has a
* tolarance of at least +- 10%. The exact amount varies from device to device and
* also with temperature. You should take this into consideration when selecting
* the time you want to sleep.
*
* :param ms: Time to wait in milliseconds
* :returns: 0 if no interrupt happened, ``INT_MAX`` if an interrupt happened and the sleep ended early.
*/
API
(
API_SLEEP
,
int
epic_sleep
(
uint32_t
ms
));
/**
* PMIC API
* ===============
...
...
epicardium/user_core/interrupts.c
View file @
46791795
...
...
@@ -2,6 +2,7 @@
#include
"os/core.h"
#include
"epicardium.h"
#include
"api/interrupt-sender.h"
#include
"user_core/user_core.h"
#include
<assert.h>
struct
interrupt_priv
{
...
...
@@ -45,6 +46,10 @@ void interrupt_trigger_sync(api_int_id_t id)
;
api_interrupt_trigger
(
id
);
/* Break the dispatcher task out of a potential call
* to epic_sleep() */
xTaskNotifyGive
(
dispatcher_task_id
);
out:
mutex_unlock
(
&
interrupt_mutex
);
}
...
...
@@ -171,6 +176,10 @@ void vInterruptsTask(void *pvParameters)
interrupt_data
.
has_pending
=
false
;
}
else
if
(
interrupt_data
.
int_enabled
[
current_irq
])
{
api_interrupt_trigger
(
current_irq
);
/* Break the dispatcher task out of a potential call
* to epic_sleep() */
xTaskNotifyGive
(
dispatcher_task_id
);
}
mutex_unlock
(
&
interrupt_mutex
);
...
...
pycardium/mphalport.c
View file @
46791795
...
...
@@ -20,9 +20,13 @@
#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)
/* Smallest integer us interval which can be reached exactly due
* to the 32768 Hz systick frequency */
#define SYSTICK_INTERVAL_US_MIN 15625
/* Target systick interval is 1 second */
#define SYSTICK_INTERVAL_US \
(SYSTICK_INTERVAL_US_MIN * (1000000 / SYSTICK_INTERVAL_US_MIN))
/*
* Copied from core_cm4.h and modified to select the
...
...
@@ -59,7 +63,7 @@ void pycardium_hal_init(void)
/*
* Configure SysTick timer for SYSTICK_INTERVAL_US period.
*/
systick_config
(
32768
/
SYSTICK_FREQ_HZ
);
systick_config
(
SYSTICK_INTERVAL_US
*
32768LL
/
1000000
);
}
/******************************************************************************
...
...
@@ -153,7 +157,7 @@ void mp_hal_set_interrupt_char(char c)
* SysTick timer at 1000 Hz
*/
static
volatile
u
int64_t
systick_count
=
0
;
static
volatile
int64_t
systick_count
=
0
;
void
SysTick_Handler
(
void
)
{
...
...
@@ -163,7 +167,7 @@ void SysTick_Handler(void)
/*
* Get an absolute "timestamp" in microseconds.
*/
static
u
int64_t
systick_get_us
()
static
int64_t
systick_get_us
()
{
uint32_t
val
,
count
;
uint32_t
irqsaved
=
__get_PRIMASK
();
...
...
@@ -178,8 +182,8 @@ static uint64_t systick_get_us()
__set_PRIMASK
(
irqsaved
);
}
while
(
val
==
0
);
u
int64_t
us
=
count
*
SYSTICK_INTERVAL_US
+
(
SysTick
->
LOAD
-
val
)
*
1000000
U
LL
/
32768
;
int64_t
us
=
count
*
SYSTICK_INTERVAL_US
+
(
SysTick
->
LOAD
-
val
)
*
1000000LL
/
32768
;
return
us
;
}
...
...
@@ -225,51 +229,6 @@ static void systick_delay_precise(uint32_t us)
}
}
static
void
systick_delay_sleep
(
uint32_t
us
)
{
uint64_t
final_time
=
systick_get_us
()
+
(
uint64_t
)
us
-
2
;
while
(
1
)
{
uint64_t
now
=
systick_get_us
();
if
((
now
+
SYSTICK_INTERVAL_US
)
>
final_time
)
{
break
;
}
/*
* 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
* just in between the check and WFI.
*/
uint32_t
irqsaved
=
__get_PRIMASK
();
__set_PRIMASK
(
0
);
if
((
now
+
SYSTICK_INTERVAL_US
)
<
final_time
)
{
__WFI
();
}
__set_PRIMASK
(
irqsaved
);
/*
* Handle pending MicroPython 'interrupts'. This call could
* potentially not return here when a handler raises an
* exception. Those will propagate outwards and thus make the
* delay return early.
*
* One example of this happeing is the KeyboardInterrupt
* (CTRL+C) which will abort the running code and exit to REPL.
*/
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
)
{
if
(
us
==
0
)
...
...
@@ -277,15 +236,42 @@ 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 >
SYSTICK_INTERVAL_US
, use
* delays with a microsecond accuracy. For anything >
10 ms
, 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
<
SYSTICK_INTERVAL_US
)
{
if
(
us
<
10000
)
{
systick_delay_precise
(
us
);
}
else
{
systick_delay_sleep
(
us
);
int64_t
now
=
systick_get_us
();
int64_t
final_time
=
now
+
us
;
while
(
final_time
-
systick_get_us
()
>
10000
)
{
uint32_t
sleep_time
=
(
final_time
-
systick_get_us
())
/
1000
;
/* We need to wake up at least in SYSTICK_INTERVAL_US to make
* sure we serve the systick interrupt. */
if
(
sleep_time
>
SYSTICK_INTERVAL_US
/
1000
)
{
sleep_time
=
SYSTICK_INTERVAL_US
/
1000
;
}
/* Add some error margin to avoid issues with the clock accuracy
* of epicardium. We will account for the actual time via our
* (accurate) systick */
epic_sleep
(
sleep_time
*
8
/
10
);
/* epic_sleep() can return early if there was an interrupt
* coming from epicardium side.
* Give MP a chance to handle them. */
mp_handle_pending
(
true
);
}
now
=
systick_get_us
();
if
(
final_time
>
now
)
{
systick_delay_precise
(
final_time
-
now
);
}
}
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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