Browse Source

Add Vcc Messung

master
Ralf Behrens 4 years ago
parent
commit
b48c76f83a
  1. 299
      include/ATSAMD21_ADC.h
  2. 2
      include/MessenSensoren.h
  3. 29
      src/MessenSensoren.cpp
  4. 1
      src/main.cpp

299
include/ATSAMD21_ADC.h

@ -0,0 +1,299 @@ @@ -0,0 +1,299 @@
// Blake Felt
// ATSAMD21_ADC.h
// Adds some extra functions to the ADC, such as
// 16 bit and differential mode
#ifndef ATSAMD21_ADC_H
#define ATSAMD21_ADC_H
#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus
#ifndef ADC_CTRLB_RESSEL_12BIT_Val
#define ADC_CTRLB_RESSEL_8BIT_Val 0x03
#define ADC_CTRLB_RESSEL_10BIT_Val 0x02 // default by Arduino
#define ADC_CTRLB_RESSEL_12BIT_Val 0x00
#endif
#define ADC_CTRLB_RESSEL_16BIT_Val 0x01 // used for averaging mode output
#define ADC_PIN_TEMP 0x18 // positive mux, pg 870
#define ADC_PIN_BANDGAP 0x19
#define ADC_PIN_SCALEDCOREVCC 0x1A
#define ADC_PIN_SCALEDIOVCC 0x1B
#define ADC_PIN_DAC 0x1C
#define ADC_PIN_GND 0x18 // negative mux, pg 869
#define ADC_PIN_IOGND 0x19
#define ADC_GAIN_1 0x00 // pg 868
#define ADC_GAIN_2 0x01
#define ADC_GAIN_4 0x02
#define ADC_GAIN_8 0x03
#define ADC_GAIN_16 0x04
#define ADC_GAIN1_DIV2 0x0F // default by Arduino
#define ADC_REF_INT1V 0x00 // 1.0V reference, pg 861
#define ADC_REF_INTVCC0 0x01 // 1/1.48 VDDANA
#define ADC_REF_INTVCC1 0x02 // 1/2 VDDANA (only for VDDANA > 2.0V) // default
#define ADC_REF_VREFA 0x03 // external reference
#define ADC_REF_VREFB 0x04 // external reference
#define ADC_PRESCALER_DIV4 0x00 // pg 864
#define ADC_PRESCALER_DIV8 0x01
#define ADC_PRESCALER_DIV16 0x02
#define ADC_PRESCALER_DIV32 0x03
#define ADC_PRESCALER_DIV64 0x04
#define ADC_PRESCALER_DIV128 0x05
#define ADC_PRESCALER_DIV256 0x06
#define ADC_PRESCALER_DIV512 0x07 // Arduino default
// NVM Software Calibration Area Mapping, pg 32. Address starting at NVMCTRL_OTP4.
// NVM register access code modified from https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/USB/samd21_host.c
// ADC Linearity Calibration value. Should be written to the CALIB register.
#define NVM_ADC_LINEARITY_POS 27
#define NVM_ADC_LINEARITY_SIZE 8
// ADC Bias Calibration value. Should be written to the CALIB register.
#define NVM_ADC_BIASCAL_POS 35
#define NVM_ADC_BIASCAL_SIZE 3
// Taken from Arduino IDE:
// Wait for synchronization of registers between the clock domains
static __inline__ void syncADC() __attribute__((always_inline, unused));
static void syncADC() {
while(ADC->STATUS.bit.SYNCBUSY == 1);
}
// Taken from Arduino IDE:
// Wait for synchronization of registers between the clock domains
static __inline__ void syncDAC() __attribute__((always_inline, unused));
static void syncDAC() {
while (DAC->STATUS.bit.SYNCBUSY == 1);
}
// taken from Arduino IDE, changes the pin to an input:
int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral );
uint8_t analogReadExtended(uint8_t bits) {
/*
* Allows for adc to read 8, 10, or 12 bits normally or 13-16 bits using oversampling and decimation.
* See pages 853 & 862
* 8,10,12 bit = 1 sample ~ 436 microseconds
* 13 bit = 4 samples ~ 1668 microseconds
* 14 bit = 16 samples ~ 6595 microseconds
* 15 bit = 64 samples ~ 26308 microseconds
* 16 bit = 256 samples ~ 105156 microseconds
*/
switch(bits) {
case 8:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x0;
ADC->AVGCTRL.bit.SAMPLENUM = 0x0;
return 0;
break;
case 10:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x0;
ADC->AVGCTRL.bit.SAMPLENUM = 0x0;
return 0;
break;
case 12:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x0;
ADC->AVGCTRL.bit.SAMPLENUM = 0x0;
return 0;
break;
case 13:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x1;
ADC->AVGCTRL.bit.SAMPLENUM = 0x2;
return 0;
break;
case 14:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x2;
ADC->AVGCTRL.bit.SAMPLENUM = 0x4;
return 0;
break;
case 15:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x1;
ADC->AVGCTRL.bit.SAMPLENUM = 0x6;
return 0;
break;
case 16:
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;
ADC->AVGCTRL.bit.ADJRES = 0x0;
ADC->AVGCTRL.bit.SAMPLENUM = 0x8;
return 0;
break;
default:
return -1;
break;
}
}
// returns the internal pin value of the specified pin, useful
// for analogDifferentialRaw function
uint8_t internalPinValue(uint8_t pin) {
return g_APinDescription[pin].ulADCChannelNumber;
}
// modified from Arduino analogRead, can be used in conjunction with analogRead:
int16_t analogDifferential(uint8_t pin_pos,uint8_t pin_neg) {
if(pin_pos<A0) pin_pos += A0;
if(pin_neg<A0) pin_neg += A0;
if((g_APinDescription[pin_neg].ulADCChannelNumber>0x07) && (pin_neg<ADC_PIN_GND)) { // if the negative pin is out of bounds
return 0;
}
uint32_t value_read = 0;
pinPeripheral(pin_pos,PIO_ANALOG); // set pins to analog mode
pinPeripheral(pin_neg,PIO_ANALOG);
if((pin_pos == A0) || (pin_neg == A0)) { // Disable DAC
syncDAC();
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
syncDAC();
}
syncADC();
ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin_pos].ulADCChannelNumber; // Selection for the positive ADC input
ADC->INPUTCTRL.bit.MUXNEG = g_APinDescription[pin_neg].ulADCChannelNumber; // negative ADC input
syncADC();
ADC->CTRLA.bit.ENABLE = 0x01; // enable adc
ADC->CTRLB.bit.DIFFMODE = 1; // set to differential mode
syncADC();
ADC->SWTRIG.bit.START = 1; // start conversion
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; // clear the data ready flag
syncADC();
ADC->SWTRIG.bit.START = 1; // restart conversion, as changing inputs messes up first conversion
while(ADC->INTFLAG.bit.RESRDY == 0); // Wait for conversion to complete
value_read = ADC->RESULT.reg; // read the value
syncADC();
ADC->CTRLA.bit.ENABLE = 0x00; // disable adc
ADC->CTRLB.bit.DIFFMODE = 0; // put back into single-ended mode
ADC->INPUTCTRL.bit.MUXNEG = ADC_PIN_GND; // set back muxneg to internal ground
syncADC();
return value_read;
}
// same as the above function, but no error checking, no pin types are changed, and the positive and negative
// inputs are the raw values being input. The DAC is not automatically shut off either. See datasheet page
int16_t analogDifferentialRaw(uint8_t mux_pos,uint8_t mux_neg) {
uint32_t value_read = 0;
syncADC();
ADC->INPUTCTRL.bit.MUXPOS = mux_pos; // Selection for the positive ADC input
ADC->INPUTCTRL.bit.MUXNEG = mux_neg; // negative ADC input
syncADC();
ADC->CTRLA.bit.ENABLE = 0x01; // enable adc
ADC->CTRLB.bit.DIFFMODE = 1; // set to differential mode
syncADC();
ADC->SWTRIG.bit.START = 1; // start conversion
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; // clear the data ready flag
syncADC();
ADC->SWTRIG.bit.START = 1; // restart conversion, as changing inputs messes up first conversion
while(ADC->INTFLAG.bit.RESRDY == 0); // Wait for conversion to complete
value_read = ADC->RESULT.reg; // read the value
syncADC();
ADC->CTRLA.bit.ENABLE = 0x00; // disable adc
ADC->CTRLB.bit.DIFFMODE = 0; // put back into single-ended mode
ADC->INPUTCTRL.bit.MUXNEG = ADC_PIN_GND; // set back muxneg to internal ground
syncADC();
return value_read;
}
// sets the gain of the ADC. See page 868. All values defined above.
void analogGain(uint8_t gain) {
syncADC();
ADC->INPUTCTRL.bit.GAIN = gain;
syncADC();
}
// calibrates the bias and linearity based on the nvm register.
// NVM register access code modified from https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/USB/samd21_host.c
// datasheet pages 32 and 882
void analogCalibrate() {
syncADC();
// read NVM register
uint32_t adc_linearity = (*((uint32_t *)(NVMCTRL_OTP4) // original position
+ (NVM_ADC_LINEARITY_POS / 32)) // move to the correct 32 bit window, read value
>> (NVM_ADC_LINEARITY_POS % 32)) // shift value to match the desired position
& ((1 << NVM_ADC_LINEARITY_SIZE) - 1); // apply a bitmask for the desired size
uint32_t adc_biascal = (*((uint32_t *)(NVMCTRL_OTP4)
+ (NVM_ADC_BIASCAL_POS / 32))
>> (NVM_ADC_BIASCAL_POS % 32))
& ((1 << NVM_ADC_BIASCAL_SIZE) - 1);
// write values to CALIB register
ADC->CALIB.bit.LINEARITY_CAL = adc_linearity;
ADC->CALIB.bit.BIAS_CAL = adc_biascal;
syncADC();
}
// set the analog reference voltage, but with all available options
// (the Arduino IDE neglects some). The Arduino IDE also changes
// the gain when analogReference() is used, but this won't. pg 861
void analogReference2(uint8_t ref) {
syncADC();
ADC->REFCTRL.bit.REFSEL = ref;
syncADC();
}
// increases accuracy of gain stage by enabling the reference buffer
// offset compensation. Takes longer to start. pg 861
void analogReferenceCompensation(uint8_t val) {
if(val>0) val = 1;
syncADC();
ADC->REFCTRL.bit.REFCOMP = val;
syncADC();
}
// sets the ADC clock relative to the peripheral clock. pg 864
void analogPrescaler(uint8_t val) {
syncADC();
ADC->CTRLB.bit.PRESCALER = val;
syncADC();
}
// resets the ADC. pg 860
// note that this doesn't put back the default values set by the
// Arduino IDE.
void analogReset() {
syncADC();
ADC->CTRLA.bit.SWRST = 1; // set reset bit
while(ADC->CTRLA.bit.SWRST==1); // wait until it's finished
syncADC();
}
#ifdef __cplusplus
}
#endif // ifdef __cplusplus
#endif // ifndef ATSAMD21_ADC_H

2
include/MessenSensoren.h

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
#define h_messenSensoren
int16_t readVcc(void);
void init_Messen(void);
void MessenSensoren(void);

29
src/MessenSensoren.cpp

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
#include "bme280.h"
#include "BH1750.h"
#include "hseSensorProtocol.h"
#include "ATSAMD21_ADC.h"
#define I2C_POWER 5 // bei Feather M0
@ -15,6 +16,23 @@ @@ -15,6 +16,23 @@
HseSP hse(2, 60);
//--------------------------------------------------------------------------------------------------
// Read current supply voltage
//--------------------------------------------------------------------------------------------------
int16_t readVcc(void)
{
int result;
analogReference2(ADC_REF_INT1V);
analogReadExtended(12); // 12bit
// lese Vdd io zu GND mit Vorteiler 1/4
result = 1000.0*analogDifferentialRaw(ADC_PIN_SCALEDIOVCC, ADC_PIN_IOGND)/256.0;
return result;
}
void init_Messen() {
int i;
@ -62,7 +80,7 @@ void init_Messen() { @@ -62,7 +80,7 @@ void init_Messen() {
//--------------------------
void MessenSensoren() {
int i;
float t, p, h;
float t, p, h, fUb;
unsigned int lVisLux;
@ -101,7 +119,6 @@ void MessenSensoren() { @@ -101,7 +119,6 @@ void MessenSensoren() {
if (lVisLux > 65535) lVisLux = 654321;
Serial.print(F("Temp = "));
Serial.println(t);
Serial.print(F("Druck = "));
@ -113,6 +130,12 @@ void MessenSensoren() { @@ -113,6 +130,12 @@ void MessenSensoren() {
Serial.println(lVisLux);
Serial.print(F("Ubatt = "));
fUb = readVcc(); // T3 und T5
Serial.print( fUb );
Serial.println(F("mV "));
hse.reset();
//Ein Klimasensor hinzufügen
HseSP::ClimateSensor_t cs;
@ -122,6 +145,6 @@ void MessenSensoren() { @@ -122,6 +145,6 @@ void MessenSensoren() {
cs.Illuminance = lVisLux; //lux
hse.addClimateSensor(&cs);
// hse.addVoltage(fUb/1000.0); // in Volt
hse.addVoltage(fUb/1000.0); // in Volt
// hse.addCounter(uiOnStd); // Zeit On
}

1
src/main.cpp

@ -61,7 +61,6 @@ static const u1_t PROGMEM APPKEY[16] = {0xca, 0x96, 0x9a, 0x15, 0x76, 0x5d, 0xaf @@ -61,7 +61,6 @@ static const u1_t PROGMEM APPKEY[16] = {0xca, 0x96, 0x9a, 0x15, 0x76, 0x5d, 0xaf
void os_getDevKey(u1_t *buf) { memcpy_P(buf, APPKEY, 16); }
static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;
// Schedule TX every this many seconds (might become longer due to duty

Loading…
Cancel
Save