summaryrefslogtreecommitdiff
path: root/ports/stm32/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ports/stm32/adc.c')
-rw-r--r--ports/stm32/adc.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c
index 3f00ad875..ba1ca5ce5 100644
--- a/ports/stm32/adc.c
+++ b/ports/stm32/adc.c
@@ -450,9 +450,116 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
+// read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer)
+//
+// Read analog values from multiple ADC's into buffers at a rate set by the
+// timer. The ADC values have 12-bit resolution and are stored directly into
+// the corresponding buffer if its element size is 16 bits or greater, otherwise
+// the sample resolution will be reduced to 8 bits.
+//
+// This function should not allocate any heap memory.
+STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_in, mp_obj_t tim_in) {
+ size_t nadcs, nbufs;
+ mp_obj_t *adc_array, *buf_array;
+ mp_obj_get_array(adc_array_in, &nadcs, &adc_array);
+ mp_obj_get_array(buf_array_in, &nbufs, &buf_array);
+
+ if (nadcs < 1) {
+ mp_raise_ValueError("need at least 1 ADC");
+ }
+ if (nadcs != nbufs) {
+ mp_raise_ValueError("length of ADC and buffer lists differ");
+ }
+
+ // Get buf for first ADC, get word size, check other buffers match in type
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_array[0], &bufinfo, MP_BUFFER_WRITE);
+ size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
+ for (uint array_index = 0; array_index < nbufs; array_index++) {
+ mp_buffer_info_t bufinfo_curr;
+ mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE);
+ if ((bufinfo.len != bufinfo_curr.len) || (bufinfo.typecode != bufinfo_curr.typecode)) {
+ mp_raise_ValueError("size and type of buffers must match");
+ }
+ }
+
+ // Use the supplied timer object as the sampling time base
+ TIM_HandleTypeDef *tim;
+ tim = pyb_timer_get_handle(tim_in);
+
+ // Start adc; this is slow so wait for it to start
+ pyb_obj_adc_t *adc0 = adc_array[0];
+ adc_config_channel(&adc0->handle, adc0->channel);
+ HAL_ADC_Start(&adc0->handle);
+ // Wait for sample to complete and discard
+ #define READ_TIMED_TIMEOUT (10) // in ms
+ adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT);
+ // Read (and discard) value
+ uint value = ADCx->DR;
+
+ // Ensure first sample is on a timer tick
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+ while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
+ }
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+
+ // Overrun check: assume success
+ bool success = true;
+ size_t nelems = bufinfo.len / typesize;
+ for (size_t elem_index = 0; elem_index < nelems; elem_index++) {
+ if (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) != RESET) {
+ // Timer has already triggered
+ success = false;
+ } else {
+ // Wait for the timer to trigger so we sample at the correct frequency
+ while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
+ }
+ }
+ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
+
+ for (size_t array_index = 0; array_index < nadcs; array_index++) {
+ pyb_obj_adc_t *adc = adc_array[array_index];
+ // configure the ADC channel
+ adc_config_channel(&adc->handle, adc->channel);
+ // for the first sample we need to turn the ADC on
+ // ADC is started: set the "start sample" bit
+ #if defined(STM32F4) || defined(STM32F7)
+ ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
+ #elif defined(STM32L4)
+ SET_BIT(ADCx->CR, ADC_CR_ADSTART);
+ #else
+ #error Unsupported processor
+ #endif
+ // wait for sample to complete
+ #define READ_TIMED_TIMEOUT (10) // in ms
+ adc_wait_for_eoc_or_timeout(READ_TIMED_TIMEOUT);
+
+ // read value
+ value = ADCx->DR;
+
+ // store values in buffer
+ if (typesize == 1) {
+ value >>= 4;
+ }
+ mp_buffer_info_t bufinfo_curr; // Get buf for current ADC
+ mp_get_buffer_raise(buf_array[array_index], &bufinfo_curr, MP_BUFFER_WRITE);
+ mp_binary_set_val_array_from_int(bufinfo_curr.typecode, bufinfo_curr.buf, elem_index, value);
+ }
+ }
+
+ // Turn the ADC off
+ adc0 = adc_array[0];
+ HAL_ADC_Stop(&adc0->handle);
+
+ return mp_obj_new_bool(success);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_multi_fun_obj, adc_read_timed_multi);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(adc_read_timed_multi_obj, MP_ROM_PTR(&adc_read_timed_multi_fun_obj));
+
STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&adc_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_read_timed), MP_ROM_PTR(&adc_read_timed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_timed_multi), MP_ROM_PTR(&adc_read_timed_multi_obj) },
};
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);