d99b05282d
A big change. Micro Python objects are allocated as individual structs with the first element being a pointer to the type information (which is itself an object). This scheme follows CPython. Much more flexible, not necessarily slower, uses same heap memory, and can allocate objects statically. Also change name prefix, from py_ to mp_ (mp for Micro Python).
98 lines
3.0 KiB
C
98 lines
3.0 KiB
C
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "stm_misc.h"
|
|
#include "stm32f4xx_rcc.h"
|
|
#include "stm32f4xx_tim.h"
|
|
|
|
#include "nlr.h"
|
|
#include "misc.h"
|
|
#include "mpconfig.h"
|
|
#include "parse.h"
|
|
#include "compile.h"
|
|
#include "obj.h"
|
|
#include "runtime.h"
|
|
|
|
#include "timer.h"
|
|
|
|
// TIM6 is used as an internal interrup to schedule something at a specific rate
|
|
mp_obj_t timer_py_callback;
|
|
|
|
mp_obj_t timer_py_set_callback(mp_obj_t f) {
|
|
timer_py_callback = f;
|
|
return mp_const_none;
|
|
}
|
|
|
|
mp_obj_t timer_py_set_period(mp_obj_t period) {
|
|
TIM6->ARR = mp_obj_get_int(period) & 0xffff;
|
|
return mp_const_none;
|
|
}
|
|
|
|
mp_obj_t timer_py_set_prescaler(mp_obj_t prescaler) {
|
|
TIM6->PSC = mp_obj_get_int(prescaler) & 0xffff;
|
|
return mp_const_none;
|
|
}
|
|
|
|
mp_obj_t timer_py_get_value(void) {
|
|
return mp_obj_new_int(TIM6->CNT & 0xfffff);
|
|
}
|
|
|
|
void timer_init(void) {
|
|
timer_py_callback = mp_const_none;
|
|
|
|
// TIM6 clock enable
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
|
|
|
|
// Compute the prescaler value so TIM6 runs at 20kHz
|
|
uint16_t PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 20000) - 1;
|
|
|
|
// Time base configuration
|
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
|
TIM_TimeBaseStructure.TIM_Period = 20000; // timer cycles at 1Hz
|
|
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
|
|
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // unused for TIM6
|
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // unused for TIM6
|
|
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
|
|
|
|
// enable perhipheral preload register
|
|
TIM_ARRPreloadConfig(TIM6, ENABLE);
|
|
|
|
// enable interrupt when counter overflows
|
|
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
|
|
|
|
// set up interrupt
|
|
NVIC_InitTypeDef NVIC_InitStructure;
|
|
NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;
|
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0f; // lowest priority
|
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0f; // lowest priority
|
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
|
NVIC_Init(&NVIC_InitStructure);
|
|
|
|
// TIM6 enable counter
|
|
TIM_Cmd(TIM6, ENABLE);
|
|
|
|
// Python interface
|
|
mp_obj_t m = mp_module_new();
|
|
rt_store_attr(m, qstr_from_str_static("callback"), rt_make_function_1(timer_py_set_callback));
|
|
rt_store_attr(m, qstr_from_str_static("period"), rt_make_function_1(timer_py_set_period));
|
|
rt_store_attr(m, qstr_from_str_static("prescaler"), rt_make_function_1(timer_py_set_prescaler));
|
|
rt_store_attr(m, qstr_from_str_static("value"), rt_make_function_0(timer_py_get_value));
|
|
rt_store_name(qstr_from_str_static("timer"), m);
|
|
}
|
|
|
|
void timer_interrupt(void) {
|
|
if (timer_py_callback != mp_const_none) {
|
|
nlr_buf_t nlr;
|
|
if (nlr_push(&nlr) == 0) {
|
|
// XXX what to do if the GC is in the middle of running??
|
|
rt_call_function_0(timer_py_callback);
|
|
nlr_pop();
|
|
} else {
|
|
// uncaught exception
|
|
printf("exception in timer interrupt\n");
|
|
mp_obj_print((mp_obj_t)nlr.ret_val);
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|