mirror of
https://github.com/m5stack/M5Stack_MicroPython.git
synced 2026-05-20 10:14:44 -07:00
685 lines
23 KiB
C
685 lines
23 KiB
C
/*
|
|
* This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Based on original 'machine-timer.c' from https://github.com/micropython/micropython-esp32
|
|
* completely rewritten and many new functions and features added
|
|
*
|
|
* Copyright (c) 2017 Boris Lovosevic (https://github.com/loboris)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "driver/timer.h"
|
|
#include "py/runtime.h"
|
|
#include "modmachine.h"
|
|
|
|
#define TIMER_INTR_SEL TIMER_INTR_LEVEL
|
|
#define TIMER_DIVIDER_KHZ 40000 // 500 us per tick, 1 kHz
|
|
#define TIMER_DIVIDER_MHZ 80 // 1 us per tick, 1 MHz
|
|
#define TIMER_SCALE_KHZ 2
|
|
#define TIMER_SCALE_MHZ 100
|
|
|
|
#define TIMER_RUNNING 1
|
|
#define TIMER_PAUSED 0
|
|
|
|
#define TIMER_TYPE_ONESHOT 0
|
|
#define TIMER_TYPE_PERIODIC 1
|
|
#define TIMER_TYPE_CHRONO 2
|
|
#define TIMER_TYPE_EXTBASE 3
|
|
#define TIMER_TYPE_EXT 4
|
|
#define TIMER_TYPE_MAX 5
|
|
|
|
#define TIMER_EXT_NUM 8
|
|
#define TIMER_FLAGS 0
|
|
|
|
|
|
const mp_obj_type_t machine_timer_type;
|
|
|
|
machine_timer_obj_t * mpy_timers_used[4] = {NULL};
|
|
static machine_timer_obj_t * ext_timers[TIMER_EXT_NUM] = {NULL};
|
|
|
|
|
|
//----------------------------------------------
|
|
STATIC esp_err_t check_esp_err(esp_err_t code) {
|
|
if (code) {
|
|
mp_raise_OSError(code);
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------
|
|
STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
|
|
mp_printf(print, "Timer(%d) ", self->id);
|
|
|
|
if (self->type >= TIMER_TYPE_MAX) {
|
|
mp_printf(print, "Not initialized");
|
|
return;
|
|
}
|
|
|
|
char stype[16];
|
|
if (self->type == TIMER_TYPE_PERIODIC) sprintf(stype, "Periodic");
|
|
else if (self->type == TIMER_TYPE_ONESHOT) sprintf(stype, "One shot");
|
|
else if (self->type == TIMER_TYPE_CHRONO) sprintf(stype, "Chrono");
|
|
else if (self->type == TIMER_TYPE_EXTBASE) sprintf(stype, "Extended base");
|
|
else if (self->type == TIMER_TYPE_EXT) sprintf(stype, "Extended");
|
|
else sprintf(stype, "Unknown");
|
|
|
|
if (self->type == TIMER_TYPE_CHRONO) {
|
|
mp_printf(print, "Period: 1 us; ");
|
|
}
|
|
else if (self->type == TIMER_TYPE_EXT) {
|
|
mp_printf(print, "Period: %d ms; ", self->period);
|
|
}
|
|
else {
|
|
mp_printf(print, "Period: %d ms; ", self->period / 2);
|
|
}
|
|
if (self->type != TIMER_TYPE_CHRONO) {
|
|
mp_printf(print, "Repeat: %s; ", (self->repeat ? "True" : "False"));
|
|
}
|
|
mp_printf(print, "Type: %s; ", stype);
|
|
mp_printf(print, "Running: %s\n", (self->state == TIMER_RUNNING) ? "yes" : "no");
|
|
if ((self->type != TIMER_TYPE_CHRONO) && (self->type != TIMER_TYPE_EXTBASE)) {
|
|
mp_printf(print, " Events: %lu", self->event_num);
|
|
mp_printf(print, "; Callbacks: %lu; ", self->cb_num);
|
|
mp_printf(print, "Missed: %lu", self->event_num - self->cb_num);
|
|
}
|
|
if (self->debug_pin >= 0) {
|
|
mp_printf(print, "\n Debug output on gpio %d, ", self->debug_pin);
|
|
}
|
|
if (self->type == TIMER_TYPE_EXTBASE) {
|
|
machine_timer_obj_t *extmr;
|
|
mp_printf(print, " Handled extended timers:\n");
|
|
for (int i=0; i < TIMER_EXT_NUM; i++) {
|
|
extmr = ext_timers[i];
|
|
if (extmr) {
|
|
mp_printf(print, " %2d: Period: %d ms, %s", i+4, extmr->period, (extmr->state == TIMER_RUNNING) ? "Running" : "Paused");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
|
|
{
|
|
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
|
machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t);
|
|
self->base.type = &machine_timer_type;
|
|
|
|
self->callback = NULL;
|
|
self->handle = NULL;
|
|
self->event_num = 0;
|
|
self->cb_num = 0;
|
|
self->debug_pin = -1;
|
|
self->state = TIMER_PAUSED;
|
|
self->type = TIMER_TYPE_MAX;
|
|
|
|
int tmr = mp_obj_get_int(args[0]);
|
|
if ((tmr < 0) || (tmr > 11)) {
|
|
mp_raise_ValueError("Only base timers 0~3 and extended timers 4~11 can be used.");
|
|
}
|
|
if (tmr < 4) {
|
|
// Base hardware timer
|
|
if ((tmr == ADC_TIMER_NUM) && (adc_timer_active)) {
|
|
mp_raise_ValueError("Timer used by ADC module.");
|
|
}
|
|
if (mpy_timers_used[tmr] != NULL) {
|
|
mp_raise_ValueError("Timer already in use.");
|
|
}
|
|
mpy_timers_used[tmr] = self;
|
|
}
|
|
else {
|
|
// Extended timer
|
|
if ((mpy_timers_used[0] == NULL) || (mpy_timers_used[0]->type != TIMER_TYPE_EXTBASE)) {
|
|
mp_raise_ValueError("Timer 0 not configured as extended timer.");
|
|
}
|
|
if (ext_timers[(tmr-4)] != NULL) {
|
|
mp_raise_ValueError("Extended Timer already in use.");
|
|
}
|
|
ext_timers[(tmr-4)] = self;
|
|
}
|
|
self->id = tmr;
|
|
|
|
return self;
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
STATIC void machine_timer_disable(machine_timer_obj_t *self)
|
|
{
|
|
if ((self->id < 4) && (self->handle)) {
|
|
timer_pause((self->id >> 1) & 1, self->id & 1);
|
|
if (self->type != TIMER_TYPE_CHRONO) esp_intr_free(self->handle);
|
|
mpy_timers_used[self->id] = NULL;
|
|
}
|
|
else ext_timers[(self->id-4)] = NULL;
|
|
self->callback = NULL;
|
|
self->handle = NULL;
|
|
self->event_num = 0;
|
|
self->cb_num = 0;
|
|
self->debug_pin = -1;
|
|
self->state = TIMER_PAUSED;
|
|
self->type = TIMER_TYPE_MAX;
|
|
}
|
|
|
|
//------------------------------------------
|
|
STATIC void machine_timer_isr(void *self_in)
|
|
{
|
|
machine_timer_obj_t *self = (machine_timer_obj_t *)self_in;
|
|
|
|
if (self->id & 2) {
|
|
if (self->id & 1) TIMERG1.int_clr_timers.t1 = 1;
|
|
else TIMERG1.int_clr_timers.t0 = 1;
|
|
TIMERG1.hw_timer[self->id & 1].config.alarm_en = self->repeat;
|
|
}
|
|
else {
|
|
if (self->id & 1) TIMERG0.int_clr_timers.t1 = 1;
|
|
else TIMERG0.int_clr_timers.t0 = 1;
|
|
TIMERG0.hw_timer[self->id & 1].config.alarm_en = self->repeat;
|
|
}
|
|
|
|
if (self->debug_pin >= 0) {
|
|
if (self->debug_pin_mode >= 0) gpio_set_level(self->debug_pin, (self->debug_pin_mode & 1));
|
|
else gpio_set_level(self->debug_pin, (self->event_num & 1));
|
|
}
|
|
self->event_num++;
|
|
|
|
if ((self->callback) && (mp_sched_schedule(self->callback, self, NULL))) self->cb_num++;
|
|
}
|
|
|
|
//----------------------------------------------
|
|
STATIC void machine_ext_timer_isr(void *self_in)
|
|
{
|
|
// extended timer interrupt is fired every 1 ms
|
|
machine_timer_obj_t *self = (machine_timer_obj_t *)self_in;
|
|
machine_timer_obj_t *extmr;
|
|
|
|
TIMERG0.int_clr_timers.t0 = 1;
|
|
TIMERG0.hw_timer[0].config.alarm_en = 1;
|
|
|
|
self->event_num++;
|
|
// test extended timers
|
|
for (int i=0; i < TIMER_EXT_NUM; i++) {
|
|
extmr = ext_timers[i];
|
|
if (extmr) {
|
|
// Extended timer exists
|
|
if (extmr->state == TIMER_RUNNING) {
|
|
// Timer is running, increment extended timer's counter
|
|
extmr->counter++;
|
|
if ((extmr->counter % extmr->period) == 0) {
|
|
// Extended timer's period elapsed, increment events number
|
|
extmr->event_num++;
|
|
if (extmr->counter == extmr->alarm) {
|
|
// Schedule the callback execution
|
|
if ((extmr->callback) && (mp_sched_schedule(extmr->callback, extmr, NULL))) {
|
|
extmr->cb_num++;
|
|
self->cb_num++;
|
|
}
|
|
if (extmr->repeat) extmr->counter = 0x00000000ULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
STATIC void machine_timer_enable(machine_timer_obj_t *self)
|
|
{
|
|
if (self->id >= 4) {
|
|
ext_timers[(self->id-4)] = self;
|
|
return;
|
|
}
|
|
|
|
timer_config_t config;
|
|
config.counter_dir = TIMER_COUNT_UP;
|
|
config.intr_type = TIMER_INTR_LEVEL;
|
|
config.counter_en = TIMER_PAUSE;
|
|
|
|
if (self->type == TIMER_TYPE_CHRONO) {
|
|
config.alarm_en = TIMER_ALARM_DIS;
|
|
config.auto_reload = TIMER_AUTORELOAD_DIS;
|
|
config.divider = TIMER_DIVIDER_MHZ;
|
|
}
|
|
else {
|
|
config.alarm_en = TIMER_ALARM_EN;
|
|
config.auto_reload = self->repeat;
|
|
config.divider = TIMER_DIVIDER_KHZ;
|
|
}
|
|
|
|
check_esp_err(timer_init((self->id >> 1) & 1, self->id & 1, &config));
|
|
|
|
// Timer's counter will initially start from value below.
|
|
// Also, if auto_reload is set, this value will be automatically reload on alarm
|
|
|
|
check_esp_err(timer_set_counter_value((self->id >> 1) & 1, self->id & 1, 0x00000000ULL));
|
|
|
|
if (self->type != TIMER_TYPE_CHRONO) {
|
|
// Configure the alarm value and the interrupt on alarm.
|
|
check_esp_err(timer_set_alarm_value((self->id >> 1) & 1, self->id & 1, self->period));
|
|
// Enable timer interrupt
|
|
check_esp_err(timer_enable_intr((self->id >> 1) & 1, self->id & 1));
|
|
// Register interrupt callback
|
|
if (self->type == TIMER_TYPE_EXTBASE) {
|
|
check_esp_err(timer_isr_register((self->id >> 1) & 1, self->id & 1, machine_ext_timer_isr, (void*)self, TIMER_FLAGS, &self->handle));
|
|
}
|
|
else {
|
|
check_esp_err(timer_isr_register((self->id >> 1) & 1, self->id & 1, machine_timer_isr, (void*)self, TIMER_FLAGS, &self->handle));
|
|
}
|
|
check_esp_err(timer_start((self->id >> 1) & 1, self->id & 1));
|
|
}
|
|
mpy_timers_used[self->id] = self;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
|
{
|
|
static const mp_arg_t allowed_args[] = {
|
|
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 10} },
|
|
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_TYPE_PERIODIC} },
|
|
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
|
{ MP_QSTR_dbgpin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
|
{ MP_QSTR_dbgpinmode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
|
};
|
|
|
|
machine_timer_disable(self);
|
|
|
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
|
|
|
self->handle = NULL;
|
|
self->event_num = 0;
|
|
self->cb_num = 0;
|
|
self->debug_pin = -1;
|
|
|
|
if (self->id < 4) {
|
|
// Base hardware timer
|
|
self->type = args[1].u_int & 3;
|
|
|
|
if (self->type == TIMER_TYPE_EXTBASE) {
|
|
if (self->id != 0) {
|
|
mp_raise_ValueError("Only timer 0 can be used as extended timer.");
|
|
}
|
|
// Extended base timer types use an 2 kHz clock
|
|
// set the period to 1 ms, repeat mode, no callback
|
|
self->period = 2;
|
|
self->repeat = 1;
|
|
self->callback = NULL;
|
|
}
|
|
else if (self->type == TIMER_TYPE_CHRONO) {
|
|
// Chrono Timer uses an 1 MHz clock, no callback
|
|
// set period in us
|
|
self->period = 1;
|
|
self->repeat = 0;
|
|
self->callback = NULL;
|
|
}
|
|
else {
|
|
// Other timer types use an 2 kHz clock, convert period to ms.
|
|
if (args[0].u_int < 1) self->period = 2;
|
|
else self->period = args[0].u_int * 2;
|
|
self->repeat = args[1].u_int & 1;
|
|
if (args[2].u_obj != mp_const_none) self->callback = args[2].u_obj;
|
|
// set the debug gpio if used
|
|
if ((args[3].u_int >= 0) && (args[3].u_int < 34)) {
|
|
self->debug_pin = args[3].u_int;
|
|
self->debug_pin_mode = args[4].u_int;
|
|
gpio_pad_select_gpio(self->debug_pin);
|
|
gpio_set_direction(self->debug_pin, GPIO_MODE_OUTPUT);
|
|
gpio_set_level(self->debug_pin, 0);
|
|
}
|
|
}
|
|
// enable and start the timer
|
|
machine_timer_enable(self);
|
|
|
|
if (self->type != TIMER_TYPE_CHRONO) self->state = TIMER_RUNNING;
|
|
else self->state = TIMER_PAUSED;
|
|
}
|
|
else {
|
|
// Extended timer
|
|
uint8_t mode = args[1].u_int & 3;
|
|
if ((mode != TIMER_TYPE_PERIODIC) && (mode != TIMER_TYPE_ONESHOT)) {
|
|
mp_raise_ValueError("Wrong mode for extended timer.");
|
|
}
|
|
self->type = TIMER_TYPE_EXT;
|
|
if (args[0].u_int < 1) self->period = 1;
|
|
else self->period = args[0].u_int;
|
|
self->repeat = args[1].u_int & 1;
|
|
if (args[2].u_obj != mp_const_none) self->callback = args[2].u_obj;
|
|
self->counter = 0x00000000ULL;
|
|
self->alarm = self->period;
|
|
self->state = TIMER_RUNNING;
|
|
|
|
machine_timer_enable(self);
|
|
}
|
|
|
|
return mp_const_none;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
|
{
|
|
return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
|
|
|
|
//----------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
if ((self->id < 4) && (self->type == TIMER_TYPE_EXTBASE)) {
|
|
// Check if any extended timer exists
|
|
uint8_t num_ext = 0;
|
|
for (int i=0; i < TIMER_EXT_NUM; i++) {
|
|
if (ext_timers[i] != NULL) num_ext++;
|
|
}
|
|
if (num_ext) {
|
|
mp_raise_msg(&mp_type_OSError, "Can't deinit extended base timer, some timers running.");
|
|
}
|
|
}
|
|
machine_timer_disable(self_in);
|
|
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
|
|
|
|
//---------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_value(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
uint64_t result;
|
|
|
|
if (self->id < 4) {
|
|
// Base hardware timer
|
|
if (self->type == TIMER_TYPE_EXTBASE) result = self->event_num; // value in ms
|
|
else {
|
|
timer_get_counter_value((self->id >> 1) & 1, self->id & 1, &result);
|
|
if (self->type != TIMER_TYPE_CHRONO) result *= (self->period / 2); // value in us
|
|
}
|
|
}
|
|
else {
|
|
// Extended timer
|
|
result = self->counter; // value in ms
|
|
}
|
|
return mp_obj_new_int_from_ull(result);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
|
|
|
|
//---------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_pause(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
|
|
if (self->id < 4) {
|
|
// Base hardware timer
|
|
if (self->type == TIMER_TYPE_EXTBASE) {
|
|
// Check if any extended timer is running
|
|
uint8_t num_ext = 0;
|
|
for (int i=0; i < TIMER_EXT_NUM; i++) {
|
|
if ((ext_timers[i] != NULL) && (ext_timers[i]->state == TIMER_RUNNING)) num_ext++;
|
|
}
|
|
if (num_ext) {
|
|
mp_raise_msg(&mp_type_OSError, "Can't pause extended base timer, some timers running.");
|
|
}
|
|
}
|
|
if (self->state == TIMER_RUNNING) {
|
|
check_esp_err(timer_pause((self->id >> 1) & 1, self->id & 1));
|
|
self->state = TIMER_PAUSED;
|
|
}
|
|
}
|
|
else self->state = TIMER_PAUSED;
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_pause_obj, machine_timer_pause);
|
|
|
|
//----------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_resume(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
|
|
if (self->id < 4) {
|
|
// Base hardware timer
|
|
if (self->state == TIMER_PAUSED) {
|
|
check_esp_err(timer_start((self->id >> 1) & 1, self->id & 1));
|
|
self->state = TIMER_RUNNING;
|
|
}
|
|
}
|
|
else {
|
|
if ((mpy_timers_used[0] != NULL) && (mpy_timers_used[0]->state == TIMER_RUNNING)) self->state = TIMER_RUNNING;
|
|
else self->state = TIMER_PAUSED;
|
|
}
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_resume_obj, machine_timer_resume);
|
|
|
|
//---------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_start(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
|
|
if (self->type == TIMER_TYPE_CHRONO) {
|
|
if (self->state == TIMER_RUNNING) {
|
|
check_esp_err(timer_pause((self->id >> 1) & 1, self->id & 1));
|
|
}
|
|
self->event_num = 0;
|
|
check_esp_err(timer_set_counter_value((self->id >> 1) & 1, self->id & 1, 0x00000000ULL));
|
|
check_esp_err(timer_start((self->id >> 1) & 1, self->id & 1));
|
|
self->state = TIMER_RUNNING;
|
|
}
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_start_obj, machine_timer_start);
|
|
|
|
//---------------------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_shot(size_t n_args, const mp_obj_t *args)
|
|
{
|
|
machine_timer_obj_t *self = args[0];
|
|
|
|
if (self->type != TIMER_TYPE_ONESHOT) {
|
|
mp_raise_ValueError("Timer is not one_shot timer.");
|
|
}
|
|
|
|
int tmo = self->period;
|
|
if (n_args > 1) tmo = mp_obj_get_int(args[1]) * 2;
|
|
if (tmo < 1) tmo = self->period;
|
|
uint64_t cnt_val;
|
|
|
|
check_esp_err(timer_pause((self->id >> 1) & 1, self->id & 1));
|
|
check_esp_err(timer_get_counter_value((self->id >> 1) & 1, self->id & 1, &cnt_val));
|
|
check_esp_err(timer_set_alarm_value((self->id >> 1) & 1, self->id & 1, cnt_val+tmo));
|
|
check_esp_err(timer_start((self->id >> 1) & 1, self->id & 1));
|
|
if (self->id & 2) {
|
|
TIMERG1.hw_timer[self->id & 1].config.alarm_en = 1;
|
|
}
|
|
else {
|
|
TIMERG0.hw_timer[self->id & 1].config.alarm_en = 1;
|
|
}
|
|
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_timer_shot_obj, 1, 2, machine_timer_shot);
|
|
|
|
//------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_id(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
|
|
return MP_OBJ_NEW_SMALL_INT(self->id);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_id_obj, machine_timer_id);
|
|
|
|
//----------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_events(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
mp_obj_t tuple[2];
|
|
tuple[0] = mp_obj_new_int_from_ull(self->event_num);
|
|
tuple[1] = mp_obj_new_int_from_ull(self->cb_num);
|
|
|
|
return mp_obj_new_tuple(2, tuple);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_events_obj, machine_timer_events);
|
|
|
|
//-------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_isrunning(mp_obj_t self_in)
|
|
{
|
|
machine_timer_obj_t *self = self_in;
|
|
|
|
if (self->state == TIMER_RUNNING) return mp_const_true;
|
|
return mp_const_false;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_isrunning_obj, machine_timer_isrunning);
|
|
|
|
//-----------------------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_period(size_t n_args, const mp_obj_t *args)
|
|
{
|
|
machine_timer_obj_t *self = args[0];
|
|
uint32_t period = 1;
|
|
|
|
if (n_args > 1) {
|
|
if (self->type == TIMER_TYPE_EXTBASE) return MP_OBJ_NEW_SMALL_INT(1);
|
|
|
|
uint8_t old_state = self->state;
|
|
// Pause timer
|
|
if (self->id < 4) {
|
|
// Base hardware timer
|
|
if (self->state == TIMER_RUNNING) {
|
|
check_esp_err(timer_pause((self->id >> 1) & 1, self->id & 1));
|
|
}
|
|
}
|
|
self->state = TIMER_PAUSED;
|
|
|
|
// Set new period
|
|
period = mp_obj_get_int(args[1]);
|
|
if (self->type == TIMER_TYPE_CHRONO) {
|
|
if (period < 10) period = 1;
|
|
else period /= 10;
|
|
}
|
|
else if (self->type == TIMER_TYPE_EXT) {
|
|
if (period < 1) period = 1;
|
|
self->counter = 0x00000000ULL;
|
|
self->alarm = period;
|
|
}
|
|
else {
|
|
if (period < 1) period = 2;
|
|
else period *= 2;
|
|
}
|
|
self->period = period;
|
|
if (self->id < 4) {
|
|
check_esp_err(timer_set_counter_value((self->id >> 1) & 1, self->id & 1, 0x00000000ULL));
|
|
check_esp_err(timer_set_alarm_value((self->id >> 1) & 1, self->id & 1, self->period));
|
|
}
|
|
|
|
if ((self->id < 4) && (old_state == TIMER_RUNNING)){
|
|
// Base hardware timer
|
|
check_esp_err(timer_start((self->id >> 1) & 1, self->id & 1));
|
|
}
|
|
self->state = old_state;
|
|
}
|
|
|
|
if (self->type == TIMER_TYPE_CHRONO) period = self->period * 10;
|
|
else if (self->type == TIMER_TYPE_EXT) period = self->period;
|
|
else period = self->period / 2;
|
|
|
|
return MP_OBJ_NEW_SMALL_INT(period);
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_timer_period_obj, 1, 2, machine_timer_period);
|
|
|
|
//-------------------------------------------------------------------------
|
|
STATIC mp_obj_t machine_timer_callback(size_t n_args, const mp_obj_t *args)
|
|
{
|
|
machine_timer_obj_t *self = args[0];
|
|
|
|
if (n_args == 1) {
|
|
if (self->callback == NULL) return mp_const_false;
|
|
return mp_const_true;
|
|
}
|
|
|
|
if ((self->type == TIMER_TYPE_EXTBASE) || (self->type == TIMER_TYPE_CHRONO)) return mp_const_false;
|
|
|
|
uint8_t old_state = self->state;
|
|
// Pause timer
|
|
if (self->id < 4) {
|
|
// Base hardware timer
|
|
if (self->state == TIMER_RUNNING) {
|
|
check_esp_err(timer_pause((self->id >> 1) & 1, self->id & 1));
|
|
}
|
|
}
|
|
self->state = TIMER_PAUSED;
|
|
|
|
if ((MP_OBJ_IS_FUN(args[1])) || (MP_OBJ_IS_METH(args[1]))) {
|
|
// Set new callback
|
|
self->counter = 0x00000000ULL;
|
|
self->alarm = self->period;
|
|
self->callback = args[1];
|
|
}
|
|
else self->callback = NULL;
|
|
|
|
|
|
if ((self->id < 4) && (old_state == TIMER_RUNNING)){
|
|
// Base hardware timer
|
|
check_esp_err(timer_start((self->id >> 1) & 1, self->id & 1));
|
|
}
|
|
self->state = old_state;
|
|
|
|
return mp_const_none;
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_timer_callback_obj, 1, 2, machine_timer_callback);
|
|
|
|
//==============================================================
|
|
STATIC const mp_map_elem_t machine_timer_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___del__), (mp_obj_t)&machine_timer_deinit_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_deinit), (mp_obj_t)&machine_timer_deinit_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_init), (mp_obj_t)&machine_timer_init_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_value), (mp_obj_t)&machine_timer_value_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_events), (mp_obj_t)&machine_timer_events_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_reshoot), (mp_obj_t)&machine_timer_shot_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_start), (mp_obj_t)&machine_timer_start_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_stop), (mp_obj_t)&machine_timer_pause_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_pause), (mp_obj_t)&machine_timer_pause_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_resume), (mp_obj_t)&machine_timer_resume_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_timernum), (mp_obj_t)&machine_timer_id_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_period), (mp_obj_t)&machine_timer_period_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_callback), (mp_obj_t)&machine_timer_callback_obj },
|
|
{ MP_ROM_QSTR(MP_QSTR_isrunning), (mp_obj_t)&machine_timer_isrunning_obj },
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_TYPE_ONESHOT) },
|
|
{ MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_TYPE_PERIODIC) },
|
|
{ MP_ROM_QSTR(MP_QSTR_CHRONO), MP_ROM_INT(TIMER_TYPE_CHRONO) },
|
|
{ MP_ROM_QSTR(MP_QSTR_EXTBASE), MP_ROM_INT(TIMER_TYPE_EXTBASE) },
|
|
{ MP_ROM_QSTR(MP_QSTR_EXTENDED), MP_ROM_INT(TIMER_TYPE_EXTBASE) },
|
|
};
|
|
STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
|
|
|
|
//========================================
|
|
const mp_obj_type_t machine_timer_type = {
|
|
{ &mp_type_type },
|
|
.name = MP_QSTR_Timer,
|
|
.print = machine_timer_print,
|
|
.make_new = machine_timer_make_new,
|
|
.locals_dict = (mp_obj_t)&machine_timer_locals_dict,
|
|
};
|