diff options
| author | Dan Halbert <halbert@halwitz.org> | 2017-08-31 13:48:30 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-08-31 13:48:30 -0400 |
| commit | fdb97eda09ca1968df8a919d15ebd1fe191fb57e (patch) | |
| tree | 600ed31b4d8e7223719a6099fd862c11b9b73e9e /atmel-samd/common-hal/microcontroller | |
| parent | f3cd6b0232ababc573ebfb13de12c197e0be6b4d (diff) | |
Add microcontroller.cpu.temperature, for use as a simple sensor on minimal boards. (#211)
* Add microcontroller.cpu, the sole instance of microcontroller.Processor.
microcontroller.cpu.frequency is the clock frequency, in Hz.
microcontroller.cpu.temperature is the reading from the internal temperature sensor, in Celsius. None if not available.
* Squeeze firmware size by using -finline-limit. Otherwise non-Express builds were slightly too big.
* Update submodules.
* Fix documentation glitches
Diffstat (limited to 'atmel-samd/common-hal/microcontroller')
| -rw-r--r-- | atmel-samd/common-hal/microcontroller/Processor.c | 235 | ||||
| -rw-r--r-- | atmel-samd/common-hal/microcontroller/Processor.h | 37 | ||||
| -rw-r--r-- | atmel-samd/common-hal/microcontroller/__init__.c | 10 |
3 files changed, 282 insertions, 0 deletions
diff --git a/atmel-samd/common-hal/microcontroller/Processor.c b/atmel-samd/common-hal/microcontroller/Processor.c new file mode 100644 index 000000000..a1d5e8c12 --- /dev/null +++ b/atmel-samd/common-hal/microcontroller/Processor.c @@ -0,0 +1,235 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Dan Halbert for Adafruit Industries + * + * 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. + */ + +/* + * Includes code from ASF sample code adc_temp.h and adc_temp.c, + * and so includes this license: + * + * Copyright (C) 2015 Atmel Corporation. All rights reserved. + * + * License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common-hal/microcontroller/Processor.h" + +// Don't reorder these includes because they are dependencies of adc_feature.h. +// They should really be included by adc_feature.h. +#include <compiler.h> +#include "asf/sam0/drivers/system/clock/gclk.h" +#include "asf/sam0/utils/cmsis/samd21/include/component/adc.h" + +#include "asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h" +#include "asf/sam0/drivers/adc/adc.h" + +#define ADC_TEMP_SAMPLE_LENGTH 4 +#define INT1V_VALUE_FLOAT 1.0 +#define INT1V_DIVIDER_1000 1000.0 +#define ADC_12BIT_FULL_SCALE_VALUE_FLOAT 4095.0 + +typedef struct nvm_calibration_data_t { + float tempR; // Production Room temperature + float tempH; // Production Hot temperature + float INT1VR; // Room temp 2's complement of the internal 1V reference value + float INT1VH; // Hot temp 2's complement of the internal 1V reference value + uint16_t ADCR; // Production Room temperature ADC value + uint16_t ADCH; // Production Hot temperature ADC value + float VADCR; // Room temperature ADC voltage + float VADCH; // Hot temperature ADC voltage +} nvm_calibration_data_t; + + +// Decimal to fraction conversion. (adapted from ASF sample). +STATIC float convert_dec_to_frac(uint8_t val) { + float float_val = (float)val; + if (val < 10) { + return (float_val/10.0); + } else if (val < 100) { + return (float_val/100.0); + } else { + return (float_val/1000.0); + } +} + +STATIC void configure_adc_temp(struct adc_module *adc_instance) { + struct adc_config config_adc; + adc_get_config_defaults(&config_adc); + + // The parameters chosen here are from the temperature example in: + // http://www.atmel.com/images/Atmel-42645-ADC-Configurations-with-Examples_ApplicationNote_AT11481.pdf + // That note also recommends in general: + // "Discard the first conversion result whenever there is a change + // in ADC configuration like voltage reference / ADC channel change." + + config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV16; + config_adc.reference = ADC_REFERENCE_INT1V; + config_adc.positive_input = ADC_POSITIVE_INPUT_TEMP; + config_adc.negative_input = ADC_NEGATIVE_INPUT_GND; + config_adc.sample_length = ADC_TEMP_SAMPLE_LENGTH; + + adc_init(adc_instance, ADC, &config_adc); + + // Oversample and decimate. A higher samplenum produces a more stable result. + ADC->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(2) | ADC_AVGCTRL_SAMPLENUM_4; + //ADC->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(4) | ADC_AVGCTRL_SAMPLENUM_16; +} + +// Extract the production calibration data information from NVM (adapted from ASF sample). +// +STATIC void load_calibration_data(nvm_calibration_data_t *cal) { + volatile uint32_t val1; /* Temperature Log Row Content first 32 bits */ + volatile uint32_t val2; /* Temperature Log Row Content another 32 bits */ + uint8_t room_temp_val_int; /* Integer part of room temperature in °C */ + uint8_t room_temp_val_dec; /* Decimal part of room temperature in °C */ + uint8_t hot_temp_val_int; /* Integer part of hot temperature in °C */ + uint8_t hot_temp_val_dec; /* Decimal part of hot temperature in °C */ + int8_t room_int1v_val; /* internal 1V reference drift at room temperature */ + int8_t hot_int1v_val; /* internal 1V reference drift at hot temperature*/ + + uint32_t *temp_log_row_ptr = (uint32_t *)NVMCTRL_TEMP_LOG; + + val1 = *temp_log_row_ptr; + temp_log_row_ptr++; + val2 = *temp_log_row_ptr; + + room_temp_val_int = (uint8_t)((val1 & NVMCTRL_FUSES_ROOM_TEMP_VAL_INT_Msk) >> NVMCTRL_FUSES_ROOM_TEMP_VAL_INT_Pos); + room_temp_val_dec = (uint8_t)((val1 & NVMCTRL_FUSES_ROOM_TEMP_VAL_DEC_Msk) >> NVMCTRL_FUSES_ROOM_TEMP_VAL_DEC_Pos); + + hot_temp_val_int = (uint8_t)((val1 & NVMCTRL_FUSES_HOT_TEMP_VAL_INT_Msk) >> NVMCTRL_FUSES_HOT_TEMP_VAL_INT_Pos); + hot_temp_val_dec = (uint8_t)((val1 & NVMCTRL_FUSES_HOT_TEMP_VAL_DEC_Msk) >> NVMCTRL_FUSES_HOT_TEMP_VAL_DEC_Pos); + + room_int1v_val = (int8_t)((val1 & NVMCTRL_FUSES_ROOM_INT1V_VAL_Msk) >> NVMCTRL_FUSES_ROOM_INT1V_VAL_Pos); + hot_int1v_val = (int8_t)((val2 & NVMCTRL_FUSES_HOT_INT1V_VAL_Msk) >> NVMCTRL_FUSES_HOT_INT1V_VAL_Pos); + + cal->ADCR = (uint16_t)((val2 & NVMCTRL_FUSES_ROOM_ADC_VAL_Msk) >> NVMCTRL_FUSES_ROOM_ADC_VAL_Pos); + + cal->ADCH = (uint16_t)((val2 & NVMCTRL_FUSES_HOT_ADC_VAL_Msk) >> NVMCTRL_FUSES_HOT_ADC_VAL_Pos); + + cal->tempR = room_temp_val_int + convert_dec_to_frac(room_temp_val_dec); + cal->tempH = hot_temp_val_int + convert_dec_to_frac(hot_temp_val_dec); + + cal->INT1VR = 1 - ((float)room_int1v_val/INT1V_DIVIDER_1000); + cal->INT1VH = 1 - ((float)hot_int1v_val/INT1V_DIVIDER_1000); + + cal->VADCR = ((float)cal->ADCR * cal->INT1VR)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + cal->VADCH = ((float)cal->ADCH * cal->INT1VH)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; +} + +/* + * Calculate fine temperature using Equation1 and Equation + * 1b as mentioned in data sheet section "Temperature Sensor Characteristics" + * of Electrical Characteristics. (adapted from ASF sample code). + */ +STATIC float calculate_temperature(uint16_t raw_code, nvm_calibration_data_t *cal) +{ + float VADC; /* Voltage calculation using ADC result for Coarse Temp calculation */ + float VADCM; /* Voltage calculation using ADC result for Fine Temp calculation. */ + float INT1VM; /* Voltage calculation for reality INT1V value during the ADC conversion */ + + VADC = ((float)raw_code * INT1V_VALUE_FLOAT)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + + // Hopefully compiler will remove common subepxressions here. + + /* Coarse Temp Calculation by assume INT1V=1V for this ADC conversion */ + float coarse_temp = cal->tempR + (((cal->tempH - cal->tempR)/(cal->VADCH - cal->VADCR)) * (VADC - cal->VADCR)); + + /* Calculation to find the real INT1V value during the ADC conversion */ + INT1VM = cal->INT1VR + (((cal->INT1VH - cal->INT1VR) * (coarse_temp - cal->tempR))/(cal->tempH - cal->tempR)); + + VADCM = ((float)raw_code * INT1VM)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + + /* Fine Temp Calculation by replace INT1V=1V by INT1V = INT1Vm for ADC conversion */ + float fine_temp = cal->tempR + (((cal->tempH - cal->tempR)/(cal->VADCH - cal->VADCR)) * (VADCM - cal->VADCR)); + + return fine_temp; +} + + +// External interface. +// +float common_hal_mcu_processor_get_temperature(void) { + struct adc_module adc_instance_struct; + + system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE); + configure_adc_temp(&adc_instance_struct); + nvm_calibration_data_t nvm_calibration_data; + load_calibration_data(&nvm_calibration_data); + + adc_enable(&adc_instance_struct); + + uint16_t data; + enum status_code status; + + // Read twice and discard first result, as recommended in section 14 of + // http://www.atmel.com/images/Atmel-42645-ADC-Configurations-with-Examples_ApplicationNote_AT11481.pdf + // "Discard the first conversion result whenever there is a change in ADC configuration + // like voltage reference / ADC channel change" + // Empirical observation shows the first reading is quite different than subsequent ones. + + adc_start_conversion(&adc_instance_struct); + do { + status = adc_read(&adc_instance_struct, &data); + } while (status == STATUS_BUSY); + + adc_start_conversion(&adc_instance_struct); + do { + status = adc_read(&adc_instance_struct, &data); + } while (status == STATUS_BUSY); + + return calculate_temperature(data, &nvm_calibration_data); +} + + +uint32_t common_hal_mcu_processor_get_frequency(void) { + return system_cpu_clock_get_hz(); +} diff --git a/atmel-samd/common-hal/microcontroller/Processor.h b/atmel-samd/common-hal/microcontroller/Processor.h new file mode 100644 index 000000000..81f92bb0f --- /dev/null +++ b/atmel-samd/common-hal/microcontroller/Processor.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // Stores no state currently. +} mcu_processor_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H diff --git a/atmel-samd/common-hal/microcontroller/__init__.c b/atmel-samd/common-hal/microcontroller/__init__.c index 2b9cc8bfc..84cea008b 100644 --- a/atmel-samd/common-hal/microcontroller/__init__.c +++ b/atmel-samd/common-hal/microcontroller/__init__.c @@ -30,6 +30,7 @@ #include "samd21_pins.h" #include "shared-bindings/nvm/ByteArray.h" +#include "shared-bindings/microcontroller/Processor.h" void common_hal_mcu_delay_us(uint32_t delay) { mp_hal_delay_us(delay); @@ -50,8 +51,17 @@ void common_hal_mcu_enable_interrupts(void) { cpu_irq_restore(irq_flags); } +// The singleton microcontroller.Processor object, bound to microcontroller.cpu +// It currently only has properties, and no state. +mcu_processor_obj_t common_hal_mcu_processor_obj = { + .base = { + .type = &mcu_processor_type, + }, +}; + // NVM is only available on Express boards for now. #if CIRCUITPY_INTERNAL_NVM_SIZE > 0 +// The singleton nvm.ByteArray object. nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { .base = { .type = &nvm_bytearray_type, |
