diff --git a/.gitignore b/.gitignore index 2ad1d1f8..77bb5aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,27 @@ +# Compiled Object files +*.o +*.obj + +# Visual Studio Code +**/.vscode/ + +# Executables +*.out +*.app + +*.pyc +/tools/.idea/ +/tools/midi_tests/node_modules + +.DS_Store +*.swp +/Output + +# Ignore local overrides of platform.txt and boards.txt, +/boards.local.txt +/platform.local.txt +/libraries/**/build/ + *.bz2 bootloaders/*/build/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c062452d..e83dfeeb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,37 @@ start: - master - branches +######## PUSH +push: + stage: start + only: ['tags'] + except: ['master', 'branches'] + + allow_failure: true + + variables: + GIT_STRATEGY: clone + + before_script: + - eval `python3 check-version-tag.py ${CI_COMMIT_TAG}` + + script: + #- apk add git + - git remote add github https://$GITHUB_BOT_USERNAME:$GITHUB_ACCESS_TOKEN@github.com/$GITHUB_DEST_REPO + #- git remote show github + #- git remote show origin + #- git branch -a + - git checkout $CI_COMMIT_TAG + - git fetch github + #- git push github $CI_COMMIT_REF_NAME --force + - > + if [[ ${PRE_RELEASE} == "test" ]]; then + echo "not performing TAG push"; + else + git push github ${CI_COMMIT_TAG} + fi + - git push github --all --force + ################################# ####### PACKAGE ####### ################################# @@ -57,6 +88,24 @@ package_release: - sed -i "s:\(version\)=.*:\1=$CI_COMMIT_TAG:" ./platform.txt - jq --arg tag_ver ${CI_COMMIT_TAG} '.version = $tag_ver' package.json|sponge package.json + # adding Arduino-FreeRTOS-SAMD21 into core + - git clone $REPO_LIB_FREERTOS_URL -b v2.3.0-smartmeio.1 libraries/FreeRTOS-SAMD21 + + # adding ArduinoJson into core + - git clone $REPO_LIB_ARDUINOJSON_URL -b v6.18.0 libraries/ArduinoJson + + # adding MsgPack into core + - git clone $REPO_LIB_MSGPACK_URL -b 0.3.8 libraries/MsgPack + + # adding MsgPacketizer into core + - git clone $REPO_LIB_MSGPACKETIZER_URL -b 0.3.0 libraries/MsgPacketizer + + # adding Microcontroller ID into core + - git clone $REPO_LIB_MICROCONTROLLER_ID_URL -b 1.0.0 libraries/Microcontroller-id + + # adding PubSubClient into core + - git clone $REPO_LIB_PUBSUBCLIENT_URL -b v2.8 libraries/PubSubClient + - cd .. # tar files and move temp folder back - tar --exclude=tmp --exclude=.git* --exclude=*.DS_Store* -cvjf $PKG_NAME.tar.bz2 $CI_PROJECT_NAME diff --git a/CHANGELOG b/CHANGELOG index a16f16b1..a340e271 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +#### v 1.3.0 - 2021.11.16 + +* added FreeRTOS-SAMD21 library tag 2.3.0 that include freeRtos core version 10.2.1 [#nt82u1](https://app.clickup.com/t/nt82u1) +* enabled atomic mode for analogRead and analogWrite function [#kd95qa](https://app.clickup.com/t/kd95qa) +* definition of a new variable `MCU_FAMILY`[#1nf8f15](#https://app.clickup.com/t/1nf8f15) +* moved the libraries used by arancino-library into the core + #### v 1.2.2 - 2021.03.11 * main features of previous release diff --git a/README.md b/README.md index 20744d73..b2b225d9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ for Atmel's SAMD21 processor (used on the Arancino and Arancino Mignon boards). This core is available as a package in the Arduino IDE cores manager. If you want to install it: 1. Open the **Preferences** of the Arduino IDE. - 2. Add this URL `https://git.smartme.io/smartme.io/arancino/arduino/smartmeio-package-index/raw/master/package_smartmeio_index.json` in the **Additional Boards Manager URLs** field, and click OK. + 2. Add this URL `https://raw.githubusercontent.com/smartmeio/arancino-boards/master/package_smartmeio_index.json` in the **Additional Boards Manager URLs** field, and click OK. 3. Open the **Boards Manager** (menu Tools->Board->Board Manager...) 4. Install **Arancino Boards** 5. Select one of the boards under **Arancino Boards** in Tools->Board menu @@ -43,4 +43,4 @@ and customized by smartme.IO s.r.l. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ``` -Arduino and Atmel are trademarks of their respective owners. \ No newline at end of file +Arduino and Atmel are trademarks of their respective owners. diff --git a/boards.txt b/boards.txt index b2a272c0..46e86a3d 100644 --- a/boards.txt +++ b/boards.txt @@ -31,11 +31,6 @@ arancino_mignon.menu.UploadTool.ArancinoOTA.upload.tool=ArancinoOTA arancino_mignon.menu.UploadTool.bossac=Serial arancino_mignon.menu.UploadTool.bossac.upload.tool=bossac -arancino_mignon.menu.freertos.no=No -arancino_mignon.menu.freertos.yes=Yes -arancino_mignon.menu.freertos.no.build.arancino_extra_flags= -arancino_mignon.menu.freertos.yes.build.arancino_extra_flags=-DUSEFREERTOS - arancino_mignon.upload.protocol=sam-ba arancino_mignon.upload.maximum_size=262144 arancino_mignon.upload.use_1200bps_touch=true @@ -47,7 +42,7 @@ arancino_mignon.build.usb_product="Arancino Mignon" arancino_mignon.build.usb_manufacturer="smartme.IO" arancino_mignon.build.board=SAMD_ZERO arancino_mignon.build.core=arancino -arancino_mignon.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +arancino_mignon.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} -DUSEFREERTOS -DENABLE_CALLOC_REALLOC=1 arancino_mignon.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld arancino_mignon.build.openocdscript=openocd_scripts/arancino.cfg arancino_mignon.build.variant=arancino @@ -63,11 +58,6 @@ arancino.name=Arancino arancino.vid.0=0x04D8 arancino.pid.0=0xECDA -arancino.menu.freertos.no=No -arancino.menu.freertos.yes=Yes -arancino.menu.freertos.no.build.arancino_extra_flags= -arancino.menu.freertos.yes.build.arancino_extra_flags=-DUSEFREERTOS - arancino.upload.tool=ArancinoOTA arancino.upload.protocol=sam-ba arancino.upload.maximum_size=262144 @@ -80,7 +70,7 @@ arancino.build.usb_product="Arancino" arancino.build.usb_manufacturer="smartme.IO" arancino.build.board=SAMD_ZERO arancino.build.core=arancino -arancino.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} +arancino.build.extra_flags=-D__SAMD21G18A__ {build.usb_flags} -DUSEFREERTOS -DENABLE_CALLOC_REALLOC=1 arancino.build.ldscript=linker_scripts/gcc/flash_with_bootloader.ld arancino.build.openocdscript=openocd_scripts/arancino.cfg arancino.build.variant=arancino diff --git a/cores/arancino/Arduino.h b/cores/arancino/Arduino.h index 9165cd8e..c499ff8c 100644 --- a/cores/arancino/Arduino.h +++ b/cores/arancino/Arduino.h @@ -135,6 +135,10 @@ void loop( void ) ; #define ARANCINO_CORE_VERSION "0.0.0" #endif +#ifndef MCU_FAMILY +#define MCU_FAMILY "SAMD21" +#endif + // USB Device #include "USB/USBDesc.h" #include "USB/USBCore.h" diff --git a/cores/arancino/wiring_analog.c b/cores/arancino/wiring_analog.c index 8655f6ec..5bc8c063 100644 --- a/cores/arancino/wiring_analog.c +++ b/cores/arancino/wiring_analog.c @@ -127,6 +127,10 @@ void analogReference(eAnalogReference mode) uint32_t analogRead(uint32_t pin) { + //noInterrupts(); + #if defined(USEFREERTOS) + noInterrupts(); + #endif uint32_t valueRead = 0; if (pin < A0) { @@ -182,7 +186,11 @@ uint32_t analogRead(uint32_t pin) syncADC(); ADC->CTRLA.bit.ENABLE = 0x00; // Disable ADC syncADC(); - + + #if defined(USEFREERTOS) + interrupts(); + #endif + //interrupts(); return mapResolution(valueRead, _ADCResolution, _readResolution); } @@ -195,6 +203,9 @@ void analogWrite(uint32_t pin, uint32_t value) { PinDescription pinDesc = g_APinDescription[pin]; uint32_t attr = pinDesc.ulPinAttribute; + #if defined(USEFREERTOS) + noInterrupts(); + #endif if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG) { @@ -303,6 +314,9 @@ void analogWrite(uint32_t pin, uint32_t value) syncTCC(TCCx); } } + #if defined(USEFREERTOS) + interrupts(); + #endif return; } diff --git a/libraries/ElectronicCats_InternalTemperatureZero/.github/workflows/LibraryBuild.yml b/libraries/ElectronicCats_InternalTemperatureZero/.github/workflows/LibraryBuild.yml new file mode 100644 index 00000000..c3adad2d --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/.github/workflows/LibraryBuild.yml @@ -0,0 +1,66 @@ +# LibraryBuild.yml +# Github workflow script to test compile all examples of an Arduino library repository. +# +# Copyright (C) 2020 Armin Joachimsmeyer +# https://github.com/ArminJo/Github-Actions +# + +# This is the name of the workflow, visible on GitHub UI. +name: LibraryBuild +on: [push, pull_request] # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request + +jobs: + build: + name: ${{ matrix.arduino-boards-fqbn }} - test compiling examples + + runs-on: ubuntu-latest # I picked Ubuntu to use shell scripts. + env: + PLATFORM_DEFAULT_URL: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json + strategy: + matrix: + # The matrix will produce one job for each configuration parameter of type `arduino-boards-fqbn` + # In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command + # + # Examples: arduino:avr:uno, arduino:avr:leonardo, arduino:avr:nano, arduino:avr:mega + # arduino:sam:arduino_due_x, arduino:samd:arduino_zero_native" + # ATTinyCore:avr:attinyx5:chip=85,clock=1internal, digistump:avr:digispark-tiny, digistump:avr:digispark-pro + # STM32:stm32:GenF1:pnum=BLUEPILL_F103C8 + # esp8266:esp8266:huzzah:eesz=4M3M,xtal=80, esp32:esp32:featheresp32:FlashFreq=80 + # You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace + ############################################################################################################# + arduino-boards-fqbn: + - arduino:samd:nano_33_iot + - arduino:samd:arduino_zero_native + - arduino:samd:mkrwan1300 + - arduino:samd:mkrzero + - adafruit:samd:adafruit_itsybitsy_m4 + + # Specify parameters for each board. + # Parameters can be: platform-url, examples-exclude and examples-build-properties + # With examples-exclude you may exclude specific examples for a board. Use a space separated list. + ############################################################################################################# + include: + - arduino-boards-fqbn: arduino:samd:nano_33_iot + - arduino-boards-fqbn: arduino:samd:arduino_zero_native + - arduino-boards-fqbn: arduino:samd:mkrwan1300 + - arduino-boards-fqbn: arduino:samd:mkrzero + - arduino-boards-fqbn: adafruit:samd:adafruit_itsybitsy_m4 + sketches-exclude: Example4_BasicTemperatureReadingSleep + + # Do not cancel all jobs / architectures if one job fails + fail-fast: false + + # This is the list of steps this job will run. + steps: + + # First of all, we clone the repo using the `checkout` action. + - name: Checkout + uses: actions/checkout@master + + - name: Compile all examples + uses: ArminJo/arduino-test-compile@v3 + with: + arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} + platform-default-url: ${{ env.PLATFORM_DEFAULT_URL }} + required-libraries: RTCZero + sketches-exclude: ${{ matrix.sketches-exclude }} diff --git a/libraries/ElectronicCats_InternalTemperatureZero/.github/workflows/arduino-lint.yml b/libraries/ElectronicCats_InternalTemperatureZero/.github/workflows/arduino-lint.yml new file mode 100644 index 00000000..997a112b --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/.github/workflows/arduino-lint.yml @@ -0,0 +1,17 @@ +name: arduino-lint +on: [push, pull_request] +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: arduino/arduino-lint-action@v1 + with: + # path: ./ + version: 1.x + compliance: strict + library-manager: update + project-type: library + recursive: true + # report-file: + verbose: false diff --git a/libraries/ElectronicCats_InternalTemperatureZero/LICENSE b/libraries/ElectronicCats_InternalTemperatureZero/LICENSE new file mode 100644 index 00000000..eb66f084 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 ElectronicCats + +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. diff --git a/libraries/ElectronicCats_InternalTemperatureZero/README.md b/libraries/ElectronicCats_InternalTemperatureZero/README.md new file mode 100644 index 00000000..92d81f67 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/README.md @@ -0,0 +1,37 @@ +# ElectronicCats Internal Temperature Zero + +Arduino library for internal temperature of the family SAMD21 and SAMD51 + +### Quick Installing + +To install, use the Arduino Library Manager and search for "Electronic Cats Internal Temperature Zero Library" and install the library. + +### Manual Installing +To install this library: + + - install it using the Arduino Library manager ("Sketch" -> "Include + Library" -> "Manage Libraries..."), or + - download a zipfile from github using the "Download ZIP" button and + install it using the IDE ("Sketch" -> "Include Library" -> "Add .ZIP + Library..." + - clone this git repository into your sketchbook/libraries folder. + +For more info, see https://www.arduino.cc/en/Guide/Libraries + +## Features of this version + +- Support for SAMD21 and SAMD51 + +### Maintainer + + + + + + +Electronic Cats invests time and resources providing this open source design, please support Electronic Cats and open-source hardware by purchasing products from Electronic Cats! + +### License + +MIT + diff --git a/libraries/ElectronicCats_InternalTemperatureZero/examples/Example1_BasicTemperatureReading/Example1_BasicTemperatureReading.ino b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example1_BasicTemperatureReading/Example1_BasicTemperatureReading.ino new file mode 100644 index 00000000..b7941e42 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example1_BasicTemperatureReading/Example1_BasicTemperatureReading.ino @@ -0,0 +1,31 @@ +/*************************************************************************** + This is a library for internal temperature of the family SAMD + + Electronic Cats invests time and resources providing this open source code, + please support Electronic Cats and open-source hardware by purchasing products + from Electronic Cats! + + Written by Andrés Sabas Electronic Cats. + This code is beerware; if you see me (or any other Electronic Cats + member) at the local, and you've found our code helpful, + please buy us a round! + Distributed as-is; no warranty is given. + ***************************************************************************/ + +#include + +TemperatureZero TempZero = TemperatureZero(); + +void setup() { + // put your setup code here, to run once: + Serial.begin(9600); + TempZero.init(); +} + +void loop() { + // put your main code here, to run repeatedly: + float temperature = TempZero.readInternalTemperature(); + Serial.print("Internal Temperature is : "); + Serial.println(temperature); + delay(500); +} diff --git a/libraries/ElectronicCats_InternalTemperatureZero/examples/Example2_UserCalibration/Example2_UserCalibration.ino b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example2_UserCalibration/Example2_UserCalibration.ino new file mode 100644 index 00000000..73d90c64 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example2_UserCalibration/Example2_UserCalibration.ino @@ -0,0 +1,51 @@ +#include + +TemperatureZero TempZero = TemperatureZero(); + +void setup() { + // put your setup code here, to run once: + Serial.begin(9600); + TempZero.init(); + + // Correct the output using a 2-point measurement. That is, a measurement at a known cold + // and at a known hot temperature. Ideally, at the edges of the range-of-interest. + // In order to provide a clear example, we'll setup a case where the sensor mistakenly shifts + // down by one degree and halves the temperature: + // Real cold temp = 10 degres, TempZero indicates (10 - 1) / 2 = 4.5 + // Real hot temp = 100 degrees, TempZero indicates (100 - 1) / 2 = 49.5 + // We would now expect the user correction to double the temperature and shift it up 1 degree + TempZero.setUserCalibration2P(10.0, 4.5, 100.0, 49.5, false); + + // As an alternative to the setup of a 2-point calibration measurement, + // we could create a table with two temperature columns in a spreadsheet. One column for + // a known temperature, from a 'trusted' temperature sensor. and one for the measured + // TempZero temperature. Ideally this table would cover the range of interest evenly. + // Then, using a spreadsheet program, we could create a 'linear fit' between both columns. + // Search for the function LINEST. This fit yields two numbers: A and B. These numbers + // are the best values for using the following formula: + // = A * + B + // These A and B values could be used directly in TempZero as follows: + // TempZero.setUserCalibration(A, -B/A); +} + +void loop() { + // put your main code here, to run repeatedly: + + Serial.println("\nUser calibration evaluation, expectation T x 2 + 1: "); + + // Below code takes two measurements. + // One is displayed without user calibration and the other with it. + // Since there are two separate measurements, the measured temperature could vary between measurements. + // As the temperature sensor is a bit noisy, this effect means the the user calibration may not seem 100% + // accurate all the time. This could be resolved using a higher level of averaging (separate example) + + TempZero.disableUserCalibration(); + float temp = TempZero.readInternalTemperature(); + Serial.print("Internal Temperature is : "); + Serial.print(temp, 1); + + TempZero.enableUserCalibration(); + float userTemp = TempZero.readInternalTemperature(); + Serial.print(", user corrected : "); + Serial.println(userTemp, 1); +} diff --git a/libraries/ElectronicCats_InternalTemperatureZero/examples/Example3_Averaging/Example3_Averaging.ino b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example3_Averaging/Example3_Averaging.ino new file mode 100644 index 00000000..e79cc306 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example3_Averaging/Example3_Averaging.ino @@ -0,0 +1,93 @@ +#include + +TemperatureZero TempZero = TemperatureZero(); + +void setup() { + // put your setup code here, to run once: + Serial.begin(9600); + TempZero.init(); +} + +// The internal temperature sensor is a bit noisy. This means that it benefits from +// taking an average over a number of samples. Per default this is already setup, +// using 64 samples per measurement. However, this could be changed sing the following +// call: +// +// TempZero.setAveraging(TZ_AVERAGING_256); +// +// Let's evaluate the effect of varying the averaging mode from 1 to 256 samples +// This influences the measurement speed, as well as the variance in the results +// Below example measures the effectiveness of each averaging mode. + +#define NR_AVG_MODES 9 +#define MEASUREMENTS_PER_MODE 100 + +const char * average_mode_desc[] = {"1 ", "2 ", "4 ", "8 ", "16 ", "32 ", "64 ", "128", "256"}; + +uint16_t averaging_mode[] = { + TZ_AVERAGING_1, + TZ_AVERAGING_2, + TZ_AVERAGING_4, + TZ_AVERAGING_8, + TZ_AVERAGING_16, + TZ_AVERAGING_32, + TZ_AVERAGING_64, + TZ_AVERAGING_128, + TZ_AVERAGING_256, +}; + +struct { + uint16_t delay_avg; + float temp_min; + float temp_max; + float temp_avg; + float temp_var; +} stats_avg_mode; + +void loop() { + // put your main code here, to run repeatedly: + + Serial.print("\nAveraging mode evaluation ("); + Serial.print(MEASUREMENTS_PER_MODE); + Serial.println(" measurements per mode):"); + + for (int i=0; i stats_avg_mode.temp_max ? temp : stats_avg_mode.temp_max; + stats_avg_mode.temp_min = temp < stats_avg_mode.temp_min ? temp : stats_avg_mode.temp_min; + stat_temp_sum += temp; + stat_temp_var_Ex += stat_temp_var_shift - temp; + stat_temp_var_Ex2 += (stat_temp_var_shift - temp) * (stat_temp_var_shift - temp); + } + stats_avg_mode.delay_avg = float(stat_time_sum) / MEASUREMENTS_PER_MODE; + stats_avg_mode.temp_avg = stat_temp_sum / MEASUREMENTS_PER_MODE; + stats_avg_mode.temp_var = (stat_temp_var_Ex2 - (stat_temp_var_Ex * stat_temp_var_Ex)/MEASUREMENTS_PER_MODE)/(MEASUREMENTS_PER_MODE - 1); + + Serial.print("Mode : "); + Serial.print(average_mode_desc[i]); + Serial.print(" - delay : "); + Serial.print(stats_avg_mode.delay_avg); + Serial.print(" ms, temp (max-min) / avg / var : "); + Serial.print(stats_avg_mode.temp_max - stats_avg_mode.temp_min, 1); + Serial.print(" / "); + Serial.print(stats_avg_mode.temp_avg, 1); + Serial.print(" / "); + Serial.println(stats_avg_mode.temp_var, 4); + } +} diff --git a/libraries/ElectronicCats_InternalTemperatureZero/examples/Example4_BasicTemperatureReadingSleep/Example4_BasicTemperatureReadingSleep.ino b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example4_BasicTemperatureReadingSleep/Example4_BasicTemperatureReadingSleep.ino new file mode 100644 index 00000000..f2d14b58 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/examples/Example4_BasicTemperatureReadingSleep/Example4_BasicTemperatureReadingSleep.ino @@ -0,0 +1,42 @@ +#include +#include + +TemperatureZero TempZero = TemperatureZero(); +RTCZero rtc; + +void setup() { + // put your setup code here, to run once: + + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + Serial.begin(115200); + + rtc.begin(); + rtc.setTime(0, 0, 0); + rtc.setDate(1, 1, 20); + rtc.setAlarmTime(00, 00, 00); + rtc.enableAlarm(rtc.MATCH_SS); // Raise alarm every minute + + delay(5000); //Delay for programming before sleep +} + +void loop() { + // put your main code here, to run repeatedly: + digitalWrite(LED_BUILTIN, HIGH); + + TempZero.init(); + delay(500); + printTemp(); + delay(500); + TempZero.disable(); //saves ~60uA in standby + + digitalWrite(LED_BUILTIN, LOW); + rtc.standbyMode(); // Sleep until next alarm match +} + +void printTemp() { + float temperature = TempZero.readInternalTemperature(); + Serial.print("Internal Temperature is : "); + Serial.println(temperature); +} diff --git a/libraries/ElectronicCats_InternalTemperatureZero/keywords.txt b/libraries/ElectronicCats_InternalTemperatureZero/keywords.txt new file mode 100644 index 00000000..8ee85513 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map For Test +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +TemperatureZero KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +init KEYWORD2 +readInternalTemperature KEYWORD2 +wakeup KEYWORD2 +disable KEYWORD2 +setAveraging KEYWORD2 +setUserCalibration2P KEYWORD2 +setUserCalibration KEYWORD2 +enableUserCalibration KEYWORD2 +disableUserCalibration KEYWORD2 +readInternalTemperatureRaw KEYWORD2 +raw2temp KEYWORD2 +readInternalTemperature KEYWORD2 +enableDebugging KEYWORD2 +disableDebugging KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/ElectronicCats_InternalTemperatureZero/library.properties b/libraries/ElectronicCats_InternalTemperatureZero/library.properties new file mode 100644 index 00000000..857e09c4 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/library.properties @@ -0,0 +1,9 @@ +name=TemperatureZero +version=1.2.0 +author=Electronic Cats +maintainer=Electronic Cats +sentence=Arduino library for internal temperature of the family SAMD21 and SAM51 +paragraph=Arduino library for internal temperature of the family SAMD21 and SAMD51 +category=Device Control +url=https://github.com/ElectronicCats/ElectronicCats_InternalTemperatureZero +architectures=samd diff --git a/libraries/ElectronicCats_InternalTemperatureZero/src/TemperatureZero.cpp b/libraries/ElectronicCats_InternalTemperatureZero/src/TemperatureZero.cpp new file mode 100755 index 00000000..330939bf --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/src/TemperatureZero.cpp @@ -0,0 +1,420 @@ +/* + TemperatureZero.h - Arduino library for internal temperature of the family SAMD21 and SAMD51 - + Copyright (c) 2018 Electronic Cats. All right reserved. + Based in the work of Mitchell Pontague https://github.com/arduino/ArduinoCore-samd/pull/277 + Based in the work of @manitou48 for SAMD51 https://github.com/manitou48/samd51/blob/master/m4temp.ino + and CircuitPython https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/common-hal/microcontroller/Processor.c + Thanks! +*/ + +#include "Arduino.h" +#include "TemperatureZero.h" + +#ifdef __SAMD51__ // M4 +// m4 SAMD51 chip temperature sensor on ADC +// Decimal to fraction conversion. (adapted from ASF sample). +//#define NVMCTRL_TEMP_LOG (0x00800100) // ref pg 59 +#define NVMCTRL_TEMP_LOG NVMCTRL_TEMP_LOG_W0 + +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); + } +} +#endif + +#ifdef _SAMD21_ // M0 +// Convert raw 12 bit adc reading into temperature float. +// uses factory calibration data and, only when set and enabled, user calibration data +float TemperatureZero::raw2temp (uint16_t adcReading) { + // Get course temperature first, in order to estimate the internal 1V reference voltage level at this temperature + float meaurementVoltage = ((float)adcReading)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + float coarse_temp = _roomTemperature + (((_hotTemperature - _roomTemperature)/(_hotVoltageCompensated - _roomVoltageCompensated)) * (meaurementVoltage - _roomVoltageCompensated)); + // Estimate the reference voltage using the course temperature + float ref1VAtMeasurement = _roomInt1vRef + (((_hotInt1vRef - _roomInt1vRef) * (coarse_temp - _roomTemperature))/(_hotTemperature - _roomTemperature)); + // Now first compensate the raw adc reading using the estimation of the 1V reference output at current temperature + float measureVoltageCompensated = ((float)adcReading * ref1VAtMeasurement)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + // Repeat the temperature interpolation using the compensated measurement voltage + float refinedTemp = _roomTemperature + (((_hotTemperature - _roomTemperature)/(_hotVoltageCompensated - _roomVoltageCompensated)) * (measureVoltageCompensated - _roomVoltageCompensated)); + float result = refinedTemp; + if (_isUserCalEnabled) { + result = (refinedTemp - _userCalOffsetCorrection) * _userCalGainCorrection; + } + #ifdef TZ_WITH_DEBUG_CODE + if (_debug) { + _debugSerial->println(F("\n+++ Temperature calculation:")); + _debugSerial->print(F("raw adc reading : ")); + _debugSerial->println(adcReading); + _debugSerial->print(F("Course temperature : ")); + _debugSerial->println(coarse_temp, 1); + _debugSerial->print(F("Estimated 1V ref @Course temperature : ")); + _debugSerial->println(ref1VAtMeasurement, 4); + _debugSerial->print(F("Temperature compensated measurement voltage : ")); + _debugSerial->println(measureVoltageCompensated, 4); + _debugSerial->print(F("Refined temperature : ")); + _debugSerial->println(refinedTemp, 1); + _debugSerial->print(F("User calibration post processing is : ")); + if (_isUserCalEnabled) { + _debugSerial->println(F("Enabled")); + _debugSerial->print(F("User calibration offset correction : ")); + _debugSerial->println(_userCalOffsetCorrection, 4); + _debugSerial->print(F("User calibration gain correction : ")); + _debugSerial->println(_userCalGainCorrection, 4); + _debugSerial->print(F("User calibration corrected temperature = ")); + _debugSerial->println(result, 2); + } else { + _debugSerial->println(F("Disabled")); + } + } +#endif + return result; +} +#endif + +#ifdef __SAMD51__ // M4 +float TemperatureZero::raw2temp(uint16_t TP, uint16_t TC) { + uint32_t TLI = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos; + uint32_t TLD = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_DEC_ADDR & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos; + float TL = TLI + convert_dec_to_frac(TLD); + + uint32_t THI = (*(uint32_t *)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos; + uint32_t THD = (*(uint32_t *)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos; + float TH = THI + convert_dec_to_frac(THD); + + uint16_t VPL = (*(uint32_t *)FUSES_ROOM_ADC_VAL_PTAT_ADDR & FUSES_ROOM_ADC_VAL_PTAT_Msk) >> FUSES_ROOM_ADC_VAL_PTAT_Pos; + uint16_t VPH = (*(uint32_t *)FUSES_HOT_ADC_VAL_PTAT_ADDR & FUSES_HOT_ADC_VAL_PTAT_Msk) >> FUSES_HOT_ADC_VAL_PTAT_Pos; + + uint16_t VCL = (*(uint32_t *)FUSES_ROOM_ADC_VAL_CTAT_ADDR & FUSES_ROOM_ADC_VAL_CTAT_Msk) >> FUSES_ROOM_ADC_VAL_CTAT_Pos; + uint16_t VCH = (*(uint32_t *)FUSES_HOT_ADC_VAL_CTAT_ADDR & FUSES_HOT_ADC_VAL_CTAT_Msk) >> FUSES_HOT_ADC_VAL_CTAT_Pos; + + // From SAMD51 datasheet: section 45.6.3.1 (page 1327). + return (TL*VPH*TC - VPL*TH*TC - TL*VCH*TP + TH*VCL*TP) / (VCL*TP - VCH*TP - VPL*TC + VPH*TC); +} +#endif + +TemperatureZero::TemperatureZero() { +} + +void TemperatureZero::init() { +#ifdef TZ_WITH_DEBUG_CODE + _debug = false; +#endif + _averaging = TZ_AVERAGING_64; // on 48Mhz takes approx 26 ms + _isUserCalEnabled = false; + getFactoryCalibration(); + wakeup(); +} + + +// After sleeping, the temperature sensor seems disabled. So, let's re-enable it. +void TemperatureZero::wakeup() { + #ifdef _SAMD21_ + SYSCTRL->VREF.reg |= SYSCTRL_VREF_TSEN; // Enable the temperature sensor + while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains + #endif + #ifdef __SAMD51__ + SUPC->VREF.reg |= SUPC_VREF_TSEN | SUPC_VREF_ONDEMAND; // Enable the temperature sensor + while( ADC0->SYNCBUSY.reg == 1 ); // Wait for synchronization of registers between the clock domains + #endif +} + + + +void TemperatureZero::disable() { + #ifdef _SAMD21_ + SYSCTRL->VREF.reg &= ~SYSCTRL_VREF_TSEN; // Disable the temperature sensor + while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains + #endif + #ifdef __SAMD51__ + SUPC->VREF.reg &= ~SUPC_VREF_TSEN | SUPC_VREF_ONDEMAND; // Disable the temperature sensor + while( ADC0->SYNCBUSY.reg == 1 ); // Wait for synchronization of registers between the clock domains + #endif +} + + +// Set the sample averaging as the internal sensor is somewhat noisy +// Default value is TZ_AVERAGING_64 which takes approx 26 ms at 48 Mhz clock +void TemperatureZero::setAveraging(uint8_t averaging) { + _averaging = averaging; +} + +// Reads temperature using internal ADC channel +// Datasheet chapter 37.10.8 - Temperature Sensor Characteristics +float TemperatureZero::readInternalTemperature() { + #ifdef _SAMD21_ // M0 + uint16_t adcReading = readInternalTemperatureRaw(); + return raw2temp(adcReading); + #endif + #ifdef __SAMD51__ // M4 + return readInternalTemperatureRaw(); + #endif +} + +#ifdef TZ_WITH_DEBUG_CODE +// To follow along, the detailed temperature calculation, enable library debugging +void TemperatureZero::enableDebugging(Stream &debugPort) { + _debugSerial = &debugPort; + _debug = true; +} + +// Disable library debugging +void TemperatureZero::disableDebugging(void) { + _debug = false; +} +#endif + + +// Get all factory calibration parameters and process them +// This includes both the temperature sensor calibration as well as the 1v reference calibration +void TemperatureZero::getFactoryCalibration() { + #ifdef _SAMD21_ // M0 + // Factory room temperature readings + uint8_t roomInteger = (*(uint32_t*)FUSES_ROOM_TEMP_VAL_INT_ADDR & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos; + uint8_t roomDecimal = (*(uint32_t*)FUSES_ROOM_TEMP_VAL_DEC_ADDR & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos; + _roomTemperature = roomInteger + convertDecToFrac(roomDecimal); + _roomReading = ((*(uint32_t*)FUSES_ROOM_ADC_VAL_ADDR & FUSES_ROOM_ADC_VAL_Msk) >> FUSES_ROOM_ADC_VAL_Pos); + // Factory hot temperature readings + uint8_t hotInteger = (*(uint32_t*)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos; + uint8_t hotDecimal = (*(uint32_t*)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos; + _hotTemperature = hotInteger + convertDecToFrac(hotDecimal); + _hotReading = ((*(uint32_t*)FUSES_HOT_ADC_VAL_ADDR & FUSES_HOT_ADC_VAL_Msk) >> FUSES_HOT_ADC_VAL_Pos); + // Factory internal 1V voltage reference readings at both room and hot temperatures + int8_t roomInt1vRefRaw = (int8_t)((*(uint32_t*)FUSES_ROOM_INT1V_VAL_ADDR & FUSES_ROOM_INT1V_VAL_Msk) >> FUSES_ROOM_INT1V_VAL_Pos); + int8_t hotInt1vRefRaw = (int8_t)((*(uint32_t*)FUSES_HOT_INT1V_VAL_ADDR & FUSES_HOT_INT1V_VAL_Msk) >> FUSES_HOT_INT1V_VAL_Pos); + _roomInt1vRef = 1 - ((float)roomInt1vRefRaw/INT1V_DIVIDER_1000); + _hotInt1vRef = 1 - ((float)hotInt1vRefRaw/INT1V_DIVIDER_1000); + // Combining the temperature dependent 1v reference with the ADC readings + _roomVoltageCompensated = ((float)_roomReading * _roomInt1vRef)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + _hotVoltageCompensated = ((float)_hotReading * _hotInt1vRef)/ADC_12BIT_FULL_SCALE_VALUE_FLOAT; + #endif + #ifdef __SAMD51__ + uint32_t TLI = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR & FUSES_ROOM_TEMP_VAL_INT_Msk) >> FUSES_ROOM_TEMP_VAL_INT_Pos; + uint32_t TLD = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_DEC_ADDR & FUSES_ROOM_TEMP_VAL_DEC_Msk) >> FUSES_ROOM_TEMP_VAL_DEC_Pos; + float TL = TLI + convert_dec_to_frac(TLD); + + uint32_t THI = (*(uint32_t *)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk) >> FUSES_HOT_TEMP_VAL_INT_Pos; + uint32_t THD = (*(uint32_t *)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk) >> FUSES_HOT_TEMP_VAL_DEC_Pos; + float TH = THI + convert_dec_to_frac(THD); + + uint16_t VPL = (*(uint32_t *)FUSES_ROOM_ADC_VAL_PTAT_ADDR & FUSES_ROOM_ADC_VAL_PTAT_Msk) >> FUSES_ROOM_ADC_VAL_PTAT_Pos; + uint16_t VPH = (*(uint32_t *)FUSES_HOT_ADC_VAL_PTAT_ADDR & FUSES_HOT_ADC_VAL_PTAT_Msk) >> FUSES_HOT_ADC_VAL_PTAT_Pos; + uint16_t VCL = (*(uint32_t *)FUSES_ROOM_ADC_VAL_CTAT_ADDR & FUSES_ROOM_ADC_VAL_CTAT_Msk) >> FUSES_ROOM_ADC_VAL_CTAT_Pos; + uint16_t VCH = (*(uint32_t *)FUSES_HOT_ADC_VAL_CTAT_ADDR & FUSES_HOT_ADC_VAL_CTAT_Msk) >> FUSES_HOT_ADC_VAL_CTAT_Pos; + + #endif +#ifdef TZ_WITH_DEBUG_CODE + if (_debug) { + _debugSerial->println(F("\n+++ Factory calibration parameters:")); + _debugSerial->print(F("Room Temperature : ")); + _debugSerial->println(_roomTemperature, 1); + _debugSerial->print(F("Hot Temperature : ")); + _debugSerial->println(_hotTemperature, 1); + _debugSerial->print(F("Room Reading : ")); + _debugSerial->println(_roomReading); + _debugSerial->print(F("Hot Reading : ")); + _debugSerial->println(_hotReading); + _debugSerial->print(F("Room Voltage ref raw / interpreted : ")); + _debugSerial->print(roomInt1vRefRaw); + _debugSerial->print(F(" / ")); + _debugSerial->println(_roomInt1vRef, 4); + _debugSerial->print(F("Hot Voltage ref raw / interpreted : ")); + _debugSerial->print(hotInt1vRefRaw); + _debugSerial->print(F(" / ")); + _debugSerial->println(_hotInt1vRef, 4); + _debugSerial->print(F("Room Reading compensated : ")); + _debugSerial->println(_roomVoltageCompensated, 4); + _debugSerial->print(F("Hot Reading compensated : ")); + _debugSerial->println(_hotVoltageCompensated, 4); + } +#endif +} + + +// Extra safe decimal to fractional conversion +float TemperatureZero::convertDecToFrac(uint8_t val) { + if (val < 10) { + return ((float)val/10.0); + } else if (val <100) { + return ((float)val/100.0); + } else { + return ((float)val/1000.0); + } +} + +// Set user calibration params, using two point linear interpolation for hot and cold measurements +void TemperatureZero::setUserCalibration2P(float userCalColdGroundTruth, + float userCalColdMeasurement, + float userCalHotGroundTruth, + float userCalHotMeasurement, + bool isEnabled) { + _userCalOffsetCorrection = userCalColdMeasurement - userCalColdGroundTruth * (userCalHotMeasurement - userCalColdMeasurement) / (userCalHotGroundTruth - userCalColdGroundTruth); + _userCalGainCorrection = userCalHotGroundTruth / (userCalHotMeasurement - _userCalOffsetCorrection); + _isUserCalEnabled = isEnabled; +} + +// Set user calibration params explixitly +void TemperatureZero::setUserCalibration(float userCalGainCorrection, + float userCalOffsetCorrection, + bool isEnabled) { + _userCalOffsetCorrection = userCalOffsetCorrection; + _userCalGainCorrection = userCalGainCorrection; + _isUserCalEnabled = isEnabled; +} + +void TemperatureZero::enableUserCalibration() { + _isUserCalEnabled = true; +} + +void TemperatureZero::disableUserCalibration() { + _isUserCalEnabled = false; +} + +// Get raw 12 bit adc reading +uint16_t TemperatureZero::readInternalTemperatureRaw() { + +#ifdef _SAMD21_ // M0 + // Save ADC settings + uint16_t oldReadResolution = ADC->CTRLB.reg; + uint16_t oldSampling = ADC->SAMPCTRL.reg; + uint16_t oldSampleAveraging = ADC->SAMPCTRL.reg; + uint16_t oldReferenceGain = ADC->INPUTCTRL.bit.GAIN; + uint16_t oldReferenceSelect = ADC->REFCTRL.bit.REFSEL; + + // Set to 12 bits resolution + ADC->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | ADC_CTRLB_PRESCALER_DIV256; + // Wait for synchronization of registers between the clock domains + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Ensure we are sampling slowly + ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(0x3f); + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Set ADC reference to internal 1v + ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val; + ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val; + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Select MUXPOS as temperature channel, and MUXNEG as internal ground + ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_TEMP_Val; + ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val; + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Enable ADC + ADC->CTRLA.bit.ENABLE = 1; + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Start ADC conversion & discard the first sample + ADC->SWTRIG.bit.START = 1; + // Wait until ADC conversion is done, prevents the unexpected offset bug + while (!(ADC->INTFLAG.bit.RESRDY)); + // Clear the Data Ready flag + ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; + // perform averaging + switch(_averaging) { + case TZ_AVERAGING_1: + ADC->AVGCTRL.reg = 0; + break; + case TZ_AVERAGING_2: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_2 | ADC_AVGCTRL_ADJRES(0x1); + break; + case TZ_AVERAGING_4: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_4 | ADC_AVGCTRL_ADJRES(0x2); + break; + case TZ_AVERAGING_8: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_8 | ADC_AVGCTRL_ADJRES(0x3); + break; + case TZ_AVERAGING_16: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_16 | ADC_AVGCTRL_ADJRES(0x4); + break; + case TZ_AVERAGING_32: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_32 | ADC_AVGCTRL_ADJRES(0x4); + break; + case TZ_AVERAGING_64: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_64 | ADC_AVGCTRL_ADJRES(0x4); + break; + case TZ_AVERAGING_128: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_128 | ADC_AVGCTRL_ADJRES(0x4); + break; + case TZ_AVERAGING_256: + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_256 | ADC_AVGCTRL_ADJRES(0x4); + break; + } + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Start conversion again, since The first conversion after the reference is changed must not be used. + ADC->SWTRIG.bit.START = 1; + // Wait until ADC conversion is done + while (!(ADC->INTFLAG.bit.RESRDY)); + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Get result + uint16_t adcReading = ADC->RESULT.reg; + // Clear result ready flag + ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Disable ADC + ADC->CTRLA.bit.ENABLE = 0; + while (ADC->STATUS.bit.SYNCBUSY == 1); + // Restore pervious ADC settings + ADC->CTRLB.reg = oldReadResolution; + while (ADC->STATUS.bit.SYNCBUSY == 1); + ADC->SAMPCTRL.reg = oldSampling; + ADC->SAMPCTRL.reg = oldSampleAveraging; + while (ADC->STATUS.bit.SYNCBUSY == 1); + ADC->INPUTCTRL.bit.GAIN = oldReferenceGain; + ADC->REFCTRL.bit.REFSEL = oldReferenceSelect; + while (ADC->STATUS.bit.SYNCBUSY == 1); + + return adcReading; + #endif + + #ifdef __SAMD51__ // M4 + // enable and read 2 ADC temp sensors, 12-bit res + volatile uint16_t ptat; + volatile uint16_t ctat; + + SUPC->VREF.reg |= SUPC_VREF_TSEN | SUPC_VREF_ONDEMAND; // activate temperature sensor + ADC0->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val; + while (ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_CTRLB); //wait for sync + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync + ADC0->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_PTAT; + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync + ADC0->CTRLA.bit.ENABLE = 0x01; // Enable ADC + + // Start conversion + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync + + ADC0->SWTRIG.bit.START = 1; + + // Clear the Data Ready flag + ADC0->INTFLAG.reg = ADC_INTFLAG_RESRDY; + + // Start conversion again, since The first conversion after the reference is changed must not be used. + ADC0->SWTRIG.bit.START = 1; + + while (ADC0->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete + ptat = ADC0->RESULT.reg; + + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_INPUTCTRL ); //wait for sync + ADC0->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_CTAT; + // Start conversion + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync + + ADC0->SWTRIG.bit.START = 1; + + // Clear the Data Ready flag + ADC0->INTFLAG.reg = ADC_INTFLAG_RESRDY; + + // Start conversion again, since The first conversion after the reference is changed must not be used. + ADC0->SWTRIG.bit.START = 1; + + while (ADC0->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete + ctat = ADC0->RESULT.reg; + + + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync + ADC0->CTRLA.bit.ENABLE = 0x00; // Disable ADC + while ( ADC0->SYNCBUSY.reg & ADC_SYNCBUSY_ENABLE ); //wait for sync + + return raw2temp(ptat, ctat); + + #endif +} \ No newline at end of file diff --git a/libraries/ElectronicCats_InternalTemperatureZero/src/TemperatureZero.h b/libraries/ElectronicCats_InternalTemperatureZero/src/TemperatureZero.h new file mode 100755 index 00000000..b9b04815 --- /dev/null +++ b/libraries/ElectronicCats_InternalTemperatureZero/src/TemperatureZero.h @@ -0,0 +1,93 @@ +/* + TemperatureZero.h - Arduino library for internal temperature of the family SAMD21 and SAMD51 - + Copyright (c) 2018 Electronic Cats. All right reserved. + Based in the work of Mitchell Pontague https://github.com/arduino/ArduinoCore-samd/pull/277 + Based in the work of @manitou48 for SAMD51 https://github.com/manitou48/samd51/blob/master/m4temp.ino + and CircuitPython https://github.com/adafruit/circuitpython/blob/master/ports/atmel-samd/common-hal/microcontroller/Processor.c + Thanks! +*/ + +#ifndef TEMPERATUREZERO_h +#define TEMPERATUREZERO_h + +#define TZ_AVERAGING_1 0 +#define TZ_AVERAGING_2 1 +#define TZ_AVERAGING_4 2 +#define TZ_AVERAGING_8 3 +#define TZ_AVERAGING_16 4 +#define TZ_AVERAGING_32 5 +#define TZ_AVERAGING_64 6 +#define TZ_AVERAGING_128 7 +#define TZ_AVERAGING_256 8 + +#define INT1V_DIVIDER_1000 1000.0 +#define ADC_12BIT_FULL_SCALE_VALUE_FLOAT 4095.0 + +class TemperatureZero +{ + public: + TemperatureZero(); + void init(); + void wakeup(); + void disable(); + void setAveraging(uint8_t averaging); + void setUserCalibration2P(float userCalColdGroundTruth, + float userCalColdMeasurement, + float userCalHotGroundTruth, + float userCalHotMeasurement, + bool isEnabled); + void setUserCalibration(float userCalGainCorrection, + float userCalOffsetCorrection, + bool isEnabled); + void enableUserCalibration(); + void disableUserCalibration(); + uint16_t readInternalTemperatureRaw(); +#ifdef _SAMD21_ + float raw2temp (uint16_t adcReading); +#endif +#ifdef __SAMD51__ + float raw2temp(uint16_t TP, uint16_t TC); +#endif + float readInternalTemperature(); +#ifdef TZ_WITH_DEBUG_CODE + void enableDebugging(Stream &debugPort); + void disableDebugging(void); +#endif + + private: +#ifdef TZ_WITH_DEBUG_CODE + bool _debug; + Stream * _debugSerial; +#endif + uint8_t _averaging; + + float _roomTemperature; + uint16_t _roomReading; + float _hotTemperature; + uint16_t _hotReading; + float _roomInt1vRef; + float _hotInt1vRef; + float _roomVoltageCompensated; + float _hotVoltageCompensated; + + uint32_t TLI; + uint32_t TLD; + float TL; + uint32_t THI; + uint32_t THD; + float TH; + uint16_t VPL; + uint16_t VPH; + uint16_t VCL; + uint16_t VCH; + + bool _isUserCalEnabled; + float _userCalGainCorrection; + float _userCalOffsetCorrection; + + void getFactoryCalibration(); + float convertDecToFrac(uint8_t); +}; + +#endif + diff --git a/package.json b/package.json index 78ba9d5f..b8cb9149 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "framework-arduino-samd-arancino", - "version": "1.2.1", + "version": "1.3.0", "description": "The official SmartME Wiring-based Framework for Microchip SAM D microcontrollers", "keywords": [ "framework", diff --git a/platform.txt b/platform.txt index c07fe09a..d301b525 100644 --- a/platform.txt +++ b/platform.txt @@ -19,8 +19,8 @@ # For more info: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification -name=Arancino Boards -version=1.2.0 +name=Arancino SAMD Boards +version=1.3.0 # Compile variables # ----------------- @@ -87,13 +87,13 @@ build.usb_manufacturer="Unknown" # ---------------- ## Compile c files -recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.arancino_extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile c++ files -recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.arancino_extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" ## Compile S files -recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.arancino_extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" +recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}" ## Create archives # archive_file_path is needed for backwards compatibility with IDE 1.6.5 or older, IDE 1.6.6 or newer overrides this value