From 4d7f4eb6a924f4df458eda2e624f429d67ef2248 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 15 Apr 2014 19:52:56 +0100 Subject: [PATCH] stmhal: Add ADC function to read data at a given frequency. Reads ADC values into a bytearray (or similar) at a fixed rate. Needs a better name and improved API. Also fix up DAC dma function (which also needs a better name and API). --- stmhal/adc.c | 32 ++++++++++++++++++++++++++++++++ stmhal/dac.c | 42 ++++++++++++++++++++---------------------- stmhal/qstrdefsport.h | 1 + stmhal/timer.c | 27 +++++++++++++++++++++++++++ stmhal/timer.h | 2 ++ 5 files changed, 82 insertions(+), 22 deletions(-) diff --git a/stmhal/adc.c b/stmhal/adc.c index 8a1c23c4f6..dafa3f7bce 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -11,6 +11,7 @@ #include "adc.h" #include "pin.h" #include "build/pins.h" +#include "timer.h" // Usage Model: // @@ -162,8 +163,39 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); +STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) { + pyb_obj_adc_t *self = self_in; + + buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo); + + // Init TIM6 at the required frequency (in Hz) + timer_tim6_init(mp_obj_get_int(freq_in)); + + // Start timer + HAL_TIM_Base_Start(&TIM6_Handle); + + // This uses the timer in polling mode to do the sampling + // TODO use DMA + for (uint i = 0; i < bufinfo.len; i++) { + // Wait for the timer to trigger + while (__HAL_TIM_GET_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE) == RESET) { + } + __HAL_TIM_CLEAR_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE); + ((byte*)bufinfo.buf)[i] = adc_read_channel(&self->handle) >> 4; + } + + // Stop timer + HAL_TIM_Base_Stop(&TIM6_Handle); + + return mp_obj_new_int(bufinfo.len); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); + STATIC const mp_map_elem_t adc_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_read_timed), (mp_obj_t)&adc_read_timed_obj}, }; STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); diff --git a/stmhal/dac.c b/stmhal/dac.c index 5e809412e9..c018a4046a 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -10,9 +10,9 @@ #include "parse.h" #include "obj.h" #include "runtime.h" +#include "timer.h" #include "dac.h" -TIM_HandleTypeDef TIM6_Handle; STATIC DAC_HandleTypeDef DAC_Handle; void dac_init(void) { @@ -22,19 +22,8 @@ void dac_init(void) { } STATIC void TIM6_Config(uint freq) { - // TIM6 clock enable - __TIM6_CLK_ENABLE(); - - // Compute the prescaler value so TIM6 triggers at freq-Hz - uint16_t period = (uint16_t) ((SystemCoreClock / 2) / freq) - 1; - - // time base clock configuration - TIM6_Handle.Instance = TIM6; - TIM6_Handle.Init.Period = period; - TIM6_Handle.Init.Prescaler = 0; // timer runs at SystemCoreClock / 2 - TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6 - TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6 - HAL_TIM_Base_Init(&TIM6_Handle); + // Init TIM6 at the required frequency (in Hz) + timer_tim6_init(freq); // TIM6 TRGO selection TIM_MasterConfigTypeDef config; @@ -203,17 +192,14 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { DAC_Init(self->dac_channel, &DAC_InitStructure); */ - if (self->state != 3) { - DAC_ChannelConfTypeDef config; - config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; - config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; - HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); - self->state = 3; - } - // DMA1_Stream[67] channel7 configuration DMA_HandleTypeDef DMA_Handle; DMA_Handle.Instance = self->dma_stream; + + // Need to deinit DMA first + DMA_Handle.State = HAL_DMA_STATE_READY; + HAL_DMA_DeInit(&DMA_Handle); + DMA_Handle.Init.Channel = DMA_CHANNEL_7; DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH; DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE; @@ -231,6 +217,18 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { __HAL_LINKDMA(&DAC_Handle, DMA_Handle1, DMA_Handle); + DAC_Handle.Instance = DAC; + DAC_Handle.State = HAL_DAC_STATE_RESET; + HAL_DAC_Init(&DAC_Handle); + + if (self->state != 3) { + DAC_ChannelConfTypeDef config; + config.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel); + self->state = 3; + } + HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R); /* diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index ab59699d7d..68b91c3d8d 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -97,6 +97,7 @@ Q(filtered_xyz) // for ADC object Q(ADC) Q(ADC_all) +Q(read_timed) Q(read_channel) Q(read_core_temp) Q(read_core_vbat) diff --git a/stmhal/timer.c b/stmhal/timer.c index 1e77f0fea3..5ea605039d 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -27,6 +27,7 @@ TIM_HandleTypeDef TIM3_Handle; TIM_HandleTypeDef TIM5_Handle; +TIM_HandleTypeDef TIM6_Handle; // TIM3 is set-up for the USB CDC interface void timer_tim3_init(void) { @@ -57,6 +58,7 @@ void timer_tim3_deinit(void) { */ // TIM5 is set-up for the servo controller +// This function inits but does not start the timer void timer_tim5_init(void) { // TIM5 clock enable __TIM5_CLK_ENABLE(); @@ -74,6 +76,31 @@ void timer_tim5_init(void) { HAL_TIM_PWM_Init(&TIM5_Handle); } +// Init TIM6 with a counter-overflow at the given frequency (given in Hz) +// TIM6 is used by the DAC and ADC for auto sampling at a given frequency +// This function inits but does not start the timer +void timer_tim6_init(uint freq) { + // TIM6 clock enable + __TIM6_CLK_ENABLE(); + + // Timer runs at SystemCoreClock / 2 + // Compute the prescaler value so TIM6 triggers at freq-Hz + uint32_t period = (SystemCoreClock / 2) / freq; + uint32_t prescaler = 1; + while (period > 0xffff) { + period >>= 1; + prescaler <<= 1; + } + + // Time base clock configuration + TIM6_Handle.Instance = TIM6; + TIM6_Handle.Init.Period = period - 1; + TIM6_Handle.Init.Prescaler = prescaler - 1; + TIM6_Handle.Init.ClockDivision = 0; // unused for TIM6 + TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6 + HAL_TIM_Base_Init(&TIM6_Handle); +} + // Interrupt dispatch void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &TIM3_Handle) { diff --git a/stmhal/timer.h b/stmhal/timer.h index 317b39b3f7..06e19bcc8b 100644 --- a/stmhal/timer.h +++ b/stmhal/timer.h @@ -5,6 +5,8 @@ extern TIM_HandleTypeDef TIM3_Handle; extern TIM_HandleTypeDef TIM5_Handle; +extern TIM_HandleTypeDef TIM6_Handle; void timer_tim3_init(void); void timer_tim5_init(void); +void timer_tim6_init(uint freq);