12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415 |
- #define NEXTION_SUPPORT
- #define PLATFORM_IO
- // CurrentRanger(TM) stock firmware
- // https://lowpowerlab.com/CurrentRanger
- // CurrentRanger is a *high-side* precision current meter featuring:
- // - fast autoranging
- // - uni/bi-directional modes (ie. DC/AC measurements)
- // - ultra low burden voltage
- // - 1mV per nA/uA/mA measurements with DMM/scope
- // - OLED standalone readings
- // - serial data logging option via 3.3v/RX/TX header or USB (must use isolation, read guide!)
- // - full digital control for power/switching
- // - LiPo powered with auto power-off feature (0.6uA quiescent current)
- // *************************************************************************************************************
- #ifndef CURRENT_RANGER_NEXTION
- //#error CurrentRanger target board required, see guide on how to add it to the IDE: lowpowerlab.com/currentranger
- #endif
- //***********************************************************************************************************
- #include <FlashStorage.h> //for emulated EEPROM - https://github.com/cmaglie/FlashStorage
- #include <Adafruit_FreeTouch.h> //https://github.com/adafruit/Adafruit_FreeTouch
- #ifdef OLED_SUPPORT
- #include <U8g2lib.h> //https://github.com/olikraus/u8g2/wiki/u8g2reference fonts:https://github.com/olikraus/u8g2/wiki/fntlistall
- #endif
- //#include <ATSAMD21_ADC.h>
- #ifdef NEXTION_SUPPORT
- #include "EasyNextionLibrary.h"
- #endif
- // CurrentRanger Firmware Version
- #define FW_VERSION "1.1.0c"
- //***********************************************************************************************************
- #define BIAS_LED 11
- #define LPFPIN 4
- #define LPFLED LED_BUILTIN
- #define AUTOFF PIN_AUTO_OFF
- //***********************************************************************************************************
- #define MA_PIN PIN_PA13 //#define MA 38
- #define UA_PIN PIN_PA14 //#define UA 2
- #define NA_PIN PIN_PA15 //#define NA 5
- #define MA_GPIO_PIN PIN_PB11
- #define UA_GPIO_PIN PIN_PA12
- #define NA_GPIO_PIN PIN_PB10
- #define PINOP(pin, OP) (PORT->Group[(pin) / 32].OP.reg = (1 << ((pin) % 32)))
- #define PIN_OFF(THE_PIN) PINOP(THE_PIN, OUTCLR)
- #define PIN_ON(THE_PIN) PINOP(THE_PIN, OUTSET)
- #define PIN_TGL(THE_PIN) PINOP(THE_PIN, OUTTGL)
- //***********************************************************************************************************
- #define SENSE_OUTPUT A3
- #define SENSE_GNDISO A2
- #define SENSE_VIN A5
- #define ADC_PRESCALER ADC_CTRLB_PRESCALER_DIV16
- //#define ADC_AVGCTRL ADC_AVGCTRL_SAMPLENUM_128 | ADC_AVGCTRL_ADJRES(0x4ul)
- //ADC_AVGCTRL_SAMPLENUM_1 | ADC_AVGCTRL_ADJRES(0x00ul); // take 1 sample, adjusting result by 0
- //ADC_AVGCTRL_SAMPLENUM_16 | ADC_AVGCTRL_ADJRES(0x4ul); //take 16 samples adjust by 4
- //ADC_AVGCTRL_SAMPLENUM_256 | ADC_AVGCTRL_ADJRES(0x4ul); //take 256 samples adjust by 4
- //ADC_AVGCTRL_SAMPLENUM_512 | ADC_AVGCTRL_ADJRES(0x4ul); //take 512 samples adjust by 4
- //ADC_AVGCTRL_SAMPLENUM_1024 | ADC_AVGCTRL_ADJRES(0x4ul); //take 1024 samples adjust by 4
- #define ADC_SAMPCTRL 0b111 //sample timing [fast 0..0b111 slow]
- #define ADCFULLRANGE 4095.0
- #define VBAT_REFRESH_INTERVAL 5000 //ms
- #define LOBAT_THRESHOLD 3.40 //volts
- #define DAC_GND_ISO_OFFSET 10
- #define DAC_HALF_SUPPLY_OFFSET 512
- #define OUTPUT_CALIB_FACTOR 1.00 //calibrate final VOUT value
- #define ADC_OVERLOAD 3900 //assuming GNDISO DAC output is very close to 0, this is max value less ground offset (varies from unit to unit, 3900 is a safe value)
- //***********************************************************************************************************
- //#define ADC_CALIBRATE_FORCED
- #define ADC_CALIBRATE_FORCED_OFFSET 0
- #define ADC_CALIBRATE_FORCED_GAIN 2048
- #define LDO_DEFAULT 3.300 //volts, change to actual LDO output (measure GND-3V on OLED header)
- //***********************************************************************************************************
- #define BUZZER 1 // BUZZER pin
- #define NOTE_C5 523
- #define NOTE_D5 587
- #define NOTE_E5 659
- #define NOTE_F5 698
- #define NOTE_G5 784
- #define NOTE_B5 988
- #define NOTE_C6 1047
- #define TONE_BEEP 4200
- //***********************************************************************************************************
- #define MODE_MANUAL 0
- #define MODE_AUTORANGE 1
- #define STARTUP_MODE MODE_MANUAL //or: MODE_AUTORANGE
- #define SWITCHDELAY_UP 8 //ms
- #define SWITCHDELAY_DOWN 8 //ms
- #define RANGE_SWITCH_THRESHOLD_HIGH ADC_OVERLOAD //ADC's 12bit value
- #define RANGE_SWITCH_THRESHOLD_LOW 6 //6*0.4xA ~ 2.4xA - range down below this value
- //***********************************************************************************************************
- #ifdef OLED_SUPPORT
- #include <Wire.h> //i2c scanner: https://playground.arduino.cc/Main/I2cScanner
- #define OLED_BAUD 1600000 //fast i2c clock
- #define OLED_ADDRESS 0x3C //i2c address on most small OLEDs
- #define OLED_REFRESH_INTERVAL 180 //ms
- U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
- #endif
- //***********************************************************************************************************
- #define TOUCH_N 8
- #define TOUCH_U 9
- #define TOUCH_M A4
- Adafruit_FreeTouch qt[3] = {
- Adafruit_FreeTouch( TOUCH_N, OVERSAMPLE_1, RESISTOR_50K, FREQ_MODE_NONE ),
- Adafruit_FreeTouch( TOUCH_U, OVERSAMPLE_1, RESISTOR_50K, FREQ_MODE_NONE ),
- Adafruit_FreeTouch( TOUCH_M, OVERSAMPLE_1, RESISTOR_50K, FREQ_MODE_NONE ),
- };
- #define TOUCH_HIGH_THRESHOLD 400 //range is 0..1023
- #define TOUCH_SAMPLE_INTERVAL 50 //ms
- //***********************************************************************************************************
- #define SERIAL_UART_BAUD 230400 //Serial baud for HC-06/bluetooth output
- #define BT_SERIAL_EN
- //#define LOGGER_FORMAT_EXPONENT //ex: 123E-3 = 123mA
- //#define LOGGER_FORMAT_NANOS //ex: 123456 = 123456nA = 123.456uA
- //#define LOGGER_FORMAT_ADC //raw ADC output - note: automatic ADC_REF change
- #define BT_REFRESH_INTERVAL 200 //ms
- //***********************************************************************************************************
- #define AUTOOFF_BUZZ_DELAY 500 //ms
- #define AUTOOFF_DEFAULT 600 //seconds, turn unit off after 10min of inactivity
- #define AUTOOFF_DISABLED 0xFFFF // do not turn off
- #define AUTOOFF_SMART 0xFFFE // turn off only if there is no BT or USB data logging
- //***********************************************************************************************************
- #define LOGGING_FORMAT_EXPONENT 0 //ex: 123E-3 = 123mA
- #define LOGGING_FORMAT_NANOS 1 //ex: 1234 = 1.234uA = 0.001234mA
- #define LOGGING_FORMAT_MICROS 2 //ex: 1234 = 1.234mA = 1234000nA
- #define LOGGING_FORMAT_MILLIS 3 //ex: 1234 = 1.234A = 1234000uA = 1234000000nA
- #define LOGGING_FORMAT_ADC 4 //raw output for each range (0..4095)
- //***********************************************************************************************************
- #define ADC_SAMPLING_SPEED_AVG 0
- #define ADC_SAMPLING_SPEED_FAST 1
- #define ADC_SAMPLING_SPEED_SLOW 2
- //***********************************************************************************************************
- #ifdef NEXTION_SUPPORT
- #define NEX_LIGHT_GREY 50712
- #define NEX_BLUE 1055
- #define NEXTION_REFRESH_INTERVAL 300 //ms
- EasyNex myNex(SerialNextion);
- uint8_t nex_page=0;
- bool nex_timer_run=false;
- bool nex_timerstats_run=false;
- uint8_t nex_timer_range = 0;
- uint8_t nex_timer_d0=0;
- uint8_t nex_timer_d1=0;
- uint8_t nex_timer_d2=0;
- uint8_t nex_timer_d3=0;
- uint8_t nex_timer_set=0;
- uint8_t nex_timer_output=0;
- uint32_t nex_timer_start=0;
- uint32_t nex_timer_stop=0;
- String nex_timer_current="";
- bool nex_timer_trigger=false;
- float nex_stats_min = 0;
- float nex_stats_avg = 0;
- uint32_t nex_stats_count=0;
- float nex_stats_max = 0;
- String nex_stats_max_s = "";
- String nex_stats_avg_s = "";
- String nex_stats_min_s = "";
- #endif
- int offsetCorrectionValue = 0;
- uint16_t gainCorrectionValue = 0;
- float ldoValue = 0, ldoOptimized=0;
- uint16_t autooff_interval = 0;
- uint8_t USB_LOGGING_ENABLED = false;
- uint8_t TOUCH_DEBUG_ENABLED = false;
- uint8_t GPIO_HEADER_RANGING = false;
- uint8_t BT_LOGGING_ENABLED = true;
- uint8_t LOGGING_FORMAT = LOGGING_FORMAT_EXPONENT;
- uint16_t ADC_SAMPLING_SPEED = ADC_SAMPLING_SPEED_AVG;
- uint32_t ADC_AVGCTRL;
- uint8_t calibrationPerformed=false;
- uint8_t analog_ref_half=true;
- char rangeUnit = 'm';
- uint8_t OLED_found=false;
- uint8_t autoffWarning=false;
- uint8_t autoffBuzz=0;
- #ifdef BT_SERIAL_EN
- uint8_t BT_found=false;
- #endif
- FlashStorage(eeprom_ADCoffset, int);
- FlashStorage(eeprom_ADCgain, uint16_t);
- FlashStorage(eeprom_LDO, float);
- FlashStorage(eeprom_AUTOFF, uint16_t);
- FlashStorage(eeprom_LOGGINGFORMAT, uint8_t);
- FlashStorage(eeprom_ADCSAMPLINGSPEED, uint8_t);
- //***********************************************************************************************************
- #ifdef PLATFORM_IO
- void WDTclear();
- void analogReadCorrection(int offset, uint16_t gain);
- void analogReferenceHalf(uint8_t half);
- void toggleAutoranging();
- void Beep(byte theDelay, boolean twoSounds);
- void toggleOffset();
- void rangeMA();
- void rangeUA();
- void rangeNA();
- void toggleLPF();
- void rangeBeep(uint16_t switch_delay);
- void handleTouchPads();
- void handleAutoOff();
- int adcRead(byte ADCpin);
- void handleVbatRead();
- void readVOUT();
- void printSerialMenu();
- void refreshADCSamplingSpeed();
- void rebootIntoBootloader();
- void saveLDO(float newLdoValue);
- void analogReadCorrectionForced(int offset, uint16_t gain);
- void WDTset();
- void ldoOptimizeRefresh();
- void chronometer();
- float vbat=0, VOUT=0;
- #endif
- //***********************************************************************************************************
- void setup() {
- /*
- //some buzz
- tone(BUZZER, NOTE_C5); delay(100);
- tone(BUZZER, NOTE_E5); delay(100);
- tone(BUZZER, NOTE_G5); delay(100);
- tone(BUZZER, NOTE_C6); delay(200);
- noTone(BUZZER); delay(50);
- tone(BUZZER, NOTE_G5); delay(100);
- tone(BUZZER, NOTE_C6); delay(400);
- noTone(BUZZER);
- */
- #ifdef NEXTION_SUPPORT
- myNex.begin(115200);
- #endif
- delay(50); //Wire apparently needs this
- #ifdef OLED_SUPPORT
- Wire.begin();
- Wire.beginTransmission(OLED_ADDRESS);
- byte error = Wire.endTransmission();
- if (error == 0)
- {
- Serial.print("OLED FOUND at 0x"); Serial.println(OLED_ADDRESS);
- u8g2.begin();
- //u8g2.setDisplayRotation(U8G2_R2); //if required (inside/custom mount?)
- u8g2.setBusClock(OLED_BAUD);
- OLED_found = true;
- }
- else Serial.println("NO OLED found...");
- #endif
- pinMode(A0, OUTPUT); //DAC/GNDISO
- //DAC->CTRLB.bit.EOEN = 0x00; //enable high drive strength - already done in wiring.c
- pinMode(SENSE_OUTPUT, INPUT);
- pinMode(SENSE_GNDISO, INPUT); //GND-ISO
- pinMode(SENSE_VIN, INPUT); //VIN > 1MEG > SENSE_VIN > 2MEG > GND
- pinMode(AUTOFF, INPUT_PULLUP);
- pinMode(BIAS_LED, OUTPUT);
- pinMode(LPFLED, OUTPUT); //STATUS/LPF-LED
- pinMode(LPFPIN, OUTPUT); //LPF control pin
- pinMode(BUZZER, OUTPUT);
- PINOP(MA_PIN, DIRSET);
- PINOP(UA_PIN, DIRSET);
- PINOP(NA_PIN, DIRSET);
- PINOP(MA_GPIO_PIN, DIRSET);
- PINOP(UA_GPIO_PIN, DIRSET);
- PINOP(NA_GPIO_PIN, DIRSET);
- qt[0].begin(); qt[1].begin(); qt[2].begin(); //touch pads
- analogWriteResolution(10); //DAC resolution
- analogReferenceHalf(true);
- //DAC->CTRLA.bit.RUNSTDBY = 0x01;delay(1);
- //DAC->CTRLB.bit.REFSEL=0;//pick internal reference, skip SYNCDAC (done by analogWrite)
- analogWrite(A0, DAC_GND_ISO_OFFSET); // Initialize Dac to OFFSET
- autooff_interval = eeprom_AUTOFF.read();
- if (autooff_interval==0) {
- autooff_interval = AUTOOFF_DEFAULT;
- eeprom_AUTOFF.write(autooff_interval);
- }
- LOGGING_FORMAT = eeprom_LOGGINGFORMAT.read();
- offsetCorrectionValue = eeprom_ADCoffset.read();
- gainCorrectionValue = eeprom_ADCgain.read();
- ldoValue = eeprom_LDO.read();
- if(ldoValue==0)
- saveLDO(LDO_DEFAULT);
- else ldoOptimizeRefresh();
- ADC_SAMPLING_SPEED = eeprom_ADCSAMPLINGSPEED.read();
- refreshADCSamplingSpeed(); //load correct value into ADC_AVGCTRL
- if (gainCorrectionValue!=0) //check if anything saved in EEPROM (gain changed via SerialUSB +/-)
- analogReadCorrectionForced(offsetCorrectionValue, gainCorrectionValue);
- else {
- analogReadCorrectionForced(ADC_CALIBRATE_FORCED_OFFSET, ADC_CALIBRATE_FORCED_GAIN);
- eeprom_ADCoffset.write(offsetCorrectionValue);
- eeprom_ADCgain.write(gainCorrectionValue);
- //(offset, gain) - gain is 12 bit number (1 bit integer + 11bit fractional, see DS p895)
- // - offset is 12bit 2s complement format (DS p896)
- }
- #ifdef OLED_SUPPORT
- if (OLED_found)
- {
- u8g2.clearBuffer();
- u8g2.setFont(u8g2_font_8x13B_tf);
- u8g2.setCursor(15,10); u8g2.print("CurrentRanger");
- u8g2.setFont(u8g2_font_6x12_tf);
- u8g2.setCursor(0,20); u8g2.print("Offset:");
- u8g2.setCursor(64,20); u8g2.print(offsetCorrectionValue);
- u8g2.setCursor(0,32); u8g2.print("Gain :");
- u8g2.setCursor(64,32); u8g2.print(gainCorrectionValue);
- u8g2.setCursor(0,44); u8g2.print("LDO :");
- u8g2.setCursor(64,44); u8g2.print(ldoValue,3);
- u8g2.setCursor(0, 56); u8g2.print("Firmware:");
- u8g2.setCursor(64,56); u8g2.print(FW_VERSION);
- u8g2.sendBuffer();
- delay(2000);
- }
- #endif
- #ifdef NEXTION_SUPPORT
- if (analog_ref_half)
- {
- analogReferenceHalf(false);
- vbat=adcRead(SENSE_VIN);
- analogReferenceHalf(true);
- }
- else vbat=adcRead(SENSE_VIN);
- vbat=((vbat/ADCFULLRANGE) * ldoValue) * 1.5; //1.5 given by vbat->A5 resistor ratio (1 / (2M * 1/(1M+2M)))
- myNex.writeStr("page page4","cmd");
- delay(2000);
- nex_page=2;
- myNex.writeStr("page page2","cmd");
- myNex.writeStr("offset.txt",(String)offsetCorrectionValue);
- myNex.writeStr("gain.txt",(String)gainCorrectionValue);
- myNex.writeStr("ldo.txt",String(ldoValue,3));
- myNex.writeStr("fw.txt",(String)FW_VERSION);
- myNex.writeStr("bat.txt",(String)vbat);
- delay(2000);
- myNex.writeStr("page page0","cmd");
- myNex.writeNum("b2.bco",NEX_BLUE);
- nex_page=0;
- #endif
- #ifdef BT_SERIAL_EN
- //BT check
- Serial.print("Bluetooth AT check @");Serial.print(SERIAL_UART_BAUD);Serial.print("baud...");
- delay(600);
- SerialBT.begin(SERIAL_UART_BAUD);
- SerialBT.print("AT"); //assuming HC-06, no line ending required
- uint32_t timer=millis();
- while(millis()-timer<1000) //about 1s to respond
- {
- if (SerialBT.available()==2 && SerialBT.read()=='O' && SerialBT.read()=='K')
- {
- BT_found=true;
- break;
- }
- }
- Serial.print(BT_found?"OK!":"No HC-06 response.\r\nChecking for BT v3.0...");
- if (!BT_found)
- {
- SerialBT.print("\r\n"); //assuming HC-06 version 3.0 that requires line ending
- uint32_t timer=millis();
- while(millis()-timer<50) //about 50ms to respond
- {
- if (SerialBT.available()==4 && SerialBT.read()=='O' && SerialBT.read()=='K' && SerialBT.read()=='\r' && SerialBT.read() == '\n')
- {
- BT_found=true;
- break;
- }
- }
-
- Serial.println(BT_found?"OK!":"No response.");
- }
- BT_LOGGING_ENABLED = BT_found;
- #endif
- printSerialMenu();
- WDTset();
- if (STARTUP_MODE == MODE_AUTORANGE) toggleAutoranging();
- }
- uint32_t oledInterval=0, lpfInterval=0, offsetInterval=0, autorangeInterval=0, btInterval=0,
- autoOffBuzzInterval=0, touchSampleInterval=0, lastKeepAlive=0, vbatInterval = VBAT_REFRESH_INTERVAL;
- #ifdef NEXTION_SUPPORT
- uint32_t nextionInterval=0;
- uint32_t nextionIntervalwrite=0;
- #endif
- byte LPF=0, BIAS=0, AUTORANGE=0;
- #ifndef PLATFORMIO
- float vbat=0, VOUT=0;
- #endif
- float read1=0,read2=0,readDiff=0;
- bool rangeSwitched=false;
- #define RANGE_MA rangeUnit=='m'
- #define RANGE_UA rangeUnit=='u'
- #define RANGE_NA rangeUnit=='n'
- void loop() {
- //uint32_t timestamp=micros();
- #ifdef NEXTION_SUPPORT
- if ( millis() - nextionInterval > NEXTION_REFRESH_INTERVAL) //refresh rate (ms)
- {
- myNex.NextionListen();
- nextionInterval = millis();
- }
- #endif
- while (Serial.available()>0) {
- char inByte = Serial.read();
- // tickle the AUTOOFF function so it doesn't shut down when there are commands coming over serial
- lastKeepAlive = millis();
- switch (inByte) {
- case '*':
- eeprom_ADCgain.write(++gainCorrectionValue);
- analogReadCorrection(offsetCorrectionValue,gainCorrectionValue);
- Serial.print("new gainCorrectionValue = ");
- Serial.println(gainCorrectionValue);
- break;
- case '/':
- eeprom_ADCgain.write(--gainCorrectionValue);
- analogReadCorrection(offsetCorrectionValue,gainCorrectionValue);
- Serial.print("new gainCorrectionValue = ");
- Serial.println(gainCorrectionValue);
- break;
- case '+':
- eeprom_ADCoffset.write(++offsetCorrectionValue);
- analogReadCorrection(offsetCorrectionValue,gainCorrectionValue);
- Serial.print("new offsetCorrectionValue = ");
- Serial.println(offsetCorrectionValue);
- break;
- case '-':
- eeprom_ADCoffset.write(--offsetCorrectionValue);
- analogReadCorrection(offsetCorrectionValue,gainCorrectionValue);
- Serial.print("new offsetCorrectionValue = ");
- Serial.println(offsetCorrectionValue);
- break;
- case '<':
- saveLDO(ldoValue-0.001);
- Serial.print("new LDO_Value = ");
- Serial.println(ldoValue, 3);
- break;
- case '>':
- saveLDO(ldoValue+0.001);
- Serial.print("new LDO_Value = ");
- Serial.println(ldoValue, 3);
- break;
- case 'r': //reboot to bootloader
- Serial.print("\nRebooting to bootloader.");
- for (byte i=0;i++<30;) { delay(10); Serial.print('.'); }
- rebootIntoBootloader();
- break;
- case 'u': //toggle USB logging
- USB_LOGGING_ENABLED =! USB_LOGGING_ENABLED;
- Serial.println(USB_LOGGING_ENABLED ? "USB_LOGGING_ENABLED" : "USB_LOGGING_DISABLED");
- #ifdef NEXTION_SUPPORT
- if (USB_LOGGING_ENABLED) myNex.writeNum("usb.pic",10);
- else myNex.writeNum("usb.pic",16);
- #endif
- break;
- case 't': //toggle touchpad serial output debug info
- TOUCH_DEBUG_ENABLED =! TOUCH_DEBUG_ENABLED;
- Serial.println(TOUCH_DEBUG_ENABLED ? "TOUCH_DEBUG_ENABLED" : "TOUCH_DEBUG_DISABLED");
- break;
- case 'g': //toggle GPIOs indicating ranging
- GPIO_HEADER_RANGING =! GPIO_HEADER_RANGING;
- if (GPIO_HEADER_RANGING) {
- if (rangeUnit=='m') PIN_ON(MA_GPIO_PIN); else PIN_OFF(MA_GPIO_PIN);
- if (rangeUnit=='u') PIN_ON(UA_GPIO_PIN); else PIN_OFF(UA_GPIO_PIN);
- if (rangeUnit=='n') PIN_ON(NA_GPIO_PIN); else PIN_OFF(NA_GPIO_PIN);
- }
- Serial.println(GPIO_HEADER_RANGING ? "GPIO_HEADER_RANGING_ENABLED" : "GPIO_HEADER_RANGING_DISABLED");
- break;
- case 'b': //toggle BT/serial logging
- #ifdef BT_SERIAL_EN
- if (BT_found) {
- BT_LOGGING_ENABLED =! BT_LOGGING_ENABLED;
- Serial.println(BT_LOGGING_ENABLED ? "BT_LOGGING_ENABLED" : "BT_LOGGING_DISABLED");
- } else {
- BT_LOGGING_ENABLED = false;
- Serial.println("BT Module not found: cannot enable logging");
- }
- #else
- Serial.println("BT_LOGGING Not Enabled");
- #endif
- break;
- case 'f': //cycle through output logging formats
- if (++LOGGING_FORMAT>LOGGING_FORMAT_ADC) LOGGING_FORMAT=LOGGING_FORMAT_EXPONENT;
- eeprom_LOGGINGFORMAT.write(LOGGING_FORMAT);
- if (LOGGING_FORMAT==LOGGING_FORMAT_EXPONENT) Serial.println("LOGGING_FORMAT_EXPONENT"); else
- if (LOGGING_FORMAT==LOGGING_FORMAT_NANOS) Serial.println("LOGGING_FORMAT_NANOS"); else
- if (LOGGING_FORMAT==LOGGING_FORMAT_MICROS) Serial.println("LOGGING_FORMAT_MICROS"); else
- if (LOGGING_FORMAT==LOGGING_FORMAT_MILLIS) Serial.println("LOGGING_FORMAT_MILLIS"); else
- if (LOGGING_FORMAT==LOGGING_FORMAT_ADC) Serial.println("LOGGING_FORMAT_ADC");
- break;
- case 's':
- if (++ADC_SAMPLING_SPEED>ADC_SAMPLING_SPEED_SLOW) ADC_SAMPLING_SPEED=ADC_SAMPLING_SPEED_AVG;
- if (ADC_SAMPLING_SPEED==ADC_SAMPLING_SPEED_AVG) Serial.println("ADC_SAMPLING_SPEED_AVG"); else
- if (ADC_SAMPLING_SPEED==ADC_SAMPLING_SPEED_FAST) Serial.println("ADC_SAMPLING_SPEED_FAST"); else
- if (ADC_SAMPLING_SPEED==ADC_SAMPLING_SPEED_SLOW) Serial.println("ADC_SAMPLING_SPEED_SLOW");
- eeprom_ADCSAMPLINGSPEED.write(ADC_SAMPLING_SPEED);
- refreshADCSamplingSpeed();
- break;
- case 'a': //toggle autoOff function
- if (autooff_interval == AUTOOFF_DEFAULT)
- {
- Serial.println("AUTOOFF_DISABLED");
- autooff_interval = AUTOOFF_DISABLED;
- }
- else if (autooff_interval == AUTOOFF_SMART) {
- Serial.println("AUTOOFF_DEFAULT");
- autooff_interval = AUTOOFF_DEFAULT;
- lastKeepAlive = millis();
- } else {
- // turn off only when there is no serial or BT data logging
- Serial.println("AUTOOFF_SMART");
- autooff_interval = AUTOOFF_SMART;
- }
- eeprom_AUTOFF.write(autooff_interval);
- break;
- case '?':
- printSerialMenu();
- break;
- default: break;
- }
- }
- if (AUTORANGE) {
- readVOUT();
- //assumes we only auto-range in DC mode (no bias)
- if (readDiff <= RANGE_SWITCH_THRESHOLD_LOW)
- {
- if (RANGE_MA) { rangeUA(); rangeSwitched=true; rangeBeep(SWITCHDELAY_DOWN); }
- else if (RANGE_UA) { rangeNA(); rangeSwitched=true; rangeBeep(SWITCHDELAY_DOWN); }
- }
- else if (readDiff >= RANGE_SWITCH_THRESHOLD_HIGH)
- {
- if (RANGE_NA) { rangeUA(); rangeSwitched=true; rangeBeep(SWITCHDELAY_UP); }
- else if (RANGE_UA) { rangeMA(); rangeSwitched=true; rangeBeep(SWITCHDELAY_UP); }
- }
- if (rangeSwitched) {
- lastKeepAlive=millis();
- rangeSwitched=false;
- return; //!!!
- }
- }
- uint8_t VOUTCalculated=false;
- if (USB_LOGGING_ENABLED)
- {//TODO: refactor
- if (!AUTORANGE) readVOUT();
- VOUT = readDiff*ldoOptimized*(BIAS?1:OUTPUT_CALIB_FACTOR);
- VOUTCalculated=true;
- if(LOGGING_FORMAT == LOGGING_FORMAT_EXPONENT) { Serial.print(VOUT); Serial.print("e"); Serial.println(RANGE_NA ? -9 : RANGE_UA ? -6 : -3); } else
- if(LOGGING_FORMAT == LOGGING_FORMAT_NANOS) Serial.println(VOUT * (RANGE_NA ? 1 : RANGE_UA ? 1000 : 1000000)); else
- if(LOGGING_FORMAT == LOGGING_FORMAT_MICROS) Serial.println(VOUT * (RANGE_NA ? 0.001 : RANGE_UA ? 1 : 1000)); else
- if(LOGGING_FORMAT == LOGGING_FORMAT_MILLIS) Serial.println(VOUT * (RANGE_NA ? 0.000001 : RANGE_UA ? 0.001 : 1)); else
- if(LOGGING_FORMAT == LOGGING_FORMAT_ADC) Serial.println(readDiff,0);
- }
- #ifdef BT_SERIAL_EN
- if (BT_LOGGING_ENABLED) {
- #ifdef OLED_SUPPORT
- if (OLED_found) {
- u8g2.setFont(u8g2_font_siji_t_6x10); //https://github.com/olikraus/u8g2/wiki/fntgrpsiji
- u8g2.drawGlyph(104, 10, 0xE00B); //BT icon
- }
- #endif
- btInterval = millis();
- if (!AUTORANGE) readVOUT();
- if (!VOUTCalculated) {
- VOUT = readDiff*ldoOptimized*(BIAS?1:OUTPUT_CALIB_FACTOR);
- VOUTCalculated=true;
- }
- if(LOGGING_FORMAT == LOGGING_FORMAT_EXPONENT) { SerialBT.print(VOUT); SerialBT.print("e"); SerialBT.println(RANGE_NA ? -9 : RANGE_UA ? -6 : -3); } else
- if(LOGGING_FORMAT == LOGGING_FORMAT_NANOS) SerialBT.println(VOUT * (RANGE_NA ? 1 : RANGE_UA ? 1000 : 1000000)); else
- if(LOGGING_FORMAT == LOGGING_FORMAT_MICROS) SerialBT.println(VOUT * (RANGE_NA ? 0.001 : RANGE_UA ? 1 : 1000)); else
- if(LOGGING_FORMAT == LOGGING_FORMAT_MILLIS) SerialBT.println(VOUT * (RANGE_NA ? 0.000001 : RANGE_UA ? 0.001 : 1)); else
- if(LOGGING_FORMAT == LOGGING_FORMAT_ADC) SerialBT.println(readDiff,0);
- }
- #endif
- //OLED refresh: ~22ms (SCK:1.6mhz, ADC:64samples/DIV16/b111)
- #ifdef OLED_SUPPORT
- if (OLED_found && millis() - oledInterval > OLED_REFRESH_INTERVAL) //refresh rate (ms)
- {
- oledInterval = millis();
- if (!AUTORANGE) readVOUT();
- if (!VOUTCalculated) VOUT = readDiff*ldoOptimized*(BIAS?1:OUTPUT_CALIB_FACTOR);
- u8g2.clearBuffer(); //175us
- u8g2.setFont(u8g2_font_6x12_tf); //7us
- handleVbatRead();
- u8g2.setFont(u8g2_font_siji_t_6x10);
- if (vbat>4.3)
- u8g2.drawGlyph(115, 10, 0xE23A); //charging!
- else if(vbat>4.1)
- u8g2.drawGlyph(115, 10, 0xE24B); //100%
- else if(vbat>3.95)
- u8g2.drawGlyph(115, 10, 0xE249); //80%
- else if(vbat>3.85)
- u8g2.drawGlyph(115, 10, 0xE247); //60%
- else if(vbat>3.75)
- u8g2.drawGlyph(115, 10, 0xE245); //40%
- else if(vbat>3.65)
- u8g2.drawGlyph(115, 10, 0xE244); //20%
- else if(vbat>LOBAT_THRESHOLD)
- u8g2.drawGlyph(115, 10, 0xE243); //5%!
- else u8g2.drawGlyph(115, 10, 0xE242); //u8g2.drawStr(88,12,"LoBat!");
- u8g2.setFont(u8g2_font_6x12_tf); //7us
- if (AUTORANGE) {
- u8g2.drawStr(0,12, analog_ref_half ? "AUTO\xb7\xbd" : "AUTO");
- u8g2.setCursor(42,12); u8g2.print(readDiff,0);
- } else {
- if (analog_ref_half) u8g2.drawStr(0,12,"\xbd");
- u8g2.setCursor(12,12); u8g2.print(readDiff,0);
- }
- if (autoffBuzz) u8g2.drawStr(5,26,"* AUTO OFF! *"); //autoffWarning
- u8g2.setFont(u8g2_font_helvB24_te);
- u8g2.setCursor(RANGE_MA ? 102 : 106, RANGE_UA ? 55:60); u8g2.print(RANGE_UA ? char('µ') : rangeUnit);
- u8g2.setFont(u8g2_font_logisoso32_tr);
- u8g2.setCursor(0,64); u8g2.print((BIAS&&abs(VOUT)>=0.4||!BIAS&&VOUT>=0.4)?VOUT:0, abs(VOUT)>=1000?0:1);
- if (!BIAS && readDiff>ADC_OVERLOAD || BIAS && abs(readDiff)>ADC_OVERLOAD/2)
- {
- u8g2.setFont(u8g2_font_9x15B_tf);
- u8g2.drawStr(0,28, "OVERLOAD!");
- }
- u8g2.sendBuffer();
- }
- #endif
- #ifdef NEXTION_SUPPORT
- if ( millis() - nextionIntervalwrite > NEXTION_REFRESH_INTERVAL) //refresh rate (ms)
- {
- nextionIntervalwrite =millis() ;
- handleVbatRead();
- if (!AUTORANGE) readVOUT();
- if (!VOUTCalculated) VOUT = readDiff*ldoOptimized*(BIAS?1:OUTPUT_CALIB_FACTOR);
- if (nex_page==2) myNex.writeStr("bat.txt",(String)vbat);
- if (nex_page==0){
- if (vbat>4.3)
- myNex.writeNum("p0.pic",6); //charging!
- else if(vbat>4.1)
- myNex.writeNum("p0.pic",5); ///100%
- else if(vbat>3.95)
- myNex.writeNum("p0.pic",4); //80%
- else if(vbat>3.85)
- myNex.writeNum("p0.pic",3); //60%
- else if(vbat>3.75)
- myNex.writeNum("p0.pic",2); //40%
- else if(vbat>3.65)
- myNex.writeNum("p0.pic",1); //20%
- else
- myNex.writeNum("p0.pic",0); //u8g2.drawStr(88,12,"LoBat!");
- }
- char buff[7];
- float currentout=(((BIAS&&abs(VOUT)>=0.4)||(!BIAS&&VOUT>=0.4))?VOUT:0);
- snprintf (buff, sizeof(buff), "%f", ((BIAS&&abs(VOUT)>=0.4)||(!BIAS&&VOUT>=0.4))?VOUT:0, (abs(VOUT)>=1000?0:1));
- if ((!BIAS && readDiff>ADC_OVERLOAD) || (BIAS && abs(readDiff)>ADC_OVERLOAD/2))
- {
- if (nex_page == 0 || nex_page==1 || nex_page==6)
- myNex.writeStr("current.txt","OVERLOAD!");
- }else{
- if (nex_page == 0 || nex_page==1 || nex_page==6)
- myNex.writeStr("current.txt",String(buff)+rangeUnit+'A');
- if (nex_page==1){
- int Value = (uint8_t) map(currentout,0,3300,0,255); //Read the pot value ann map it to 0.255 (max value of waveform=255)
- String Tosend = "add "; //We send the string "add "
- Tosend += 1; //send the id of the block you want to add the value to
- Tosend += ",";
- Tosend += 0; //Channel of taht id, in this case channel 0 of the waveform
- Tosend += ",";
- Tosend += Value ; //Send the value and 3 full bytes
- myNex.writeStr(Tosend,"cmd");
- }
- }
- if (nex_page == 5 ){
- chronometer();
- }
- float current_test=currentout;
- if (rangeUnit=='m'){
- current_test=current_test*1000000;
- }
- if (rangeUnit=='u'){
- current_test=current_test*1000;
- }
- if (nex_timer_run )
- {
-
- Serial.println(currentout);
- Serial.println(current_test);
- if (nex_timer_set!=0){
- if (current_test>nex_timer_set){
- nex_timer_run =false;
- nex_timer_stop = millis();
- nex_timer_trigger=true;
- nex_timer_current = String(buff)+rangeUnit+'A';
- if (nex_page==5){
- myNex.writeNum("stoptimer.bco",NEX_BLUE);
- myNex.writeNum("starttimer.bco",NEX_LIGHT_GREY);
- myNex.writeStr("timercurrent.txt",nex_timer_current);
- }
- if (nex_page==0){
- myNex.writeNum("timer.pic",21);
- }
- }
- }
-
- }
- if (nex_timerstats_run)
- {
- if (nex_stats_min > current_test)
- {
- nex_stats_min = current_test;
- nex_stats_min_s = String(buff)+rangeUnit+'A';
- myNex.writeStr("avgmin.txt",nex_stats_min_s);
- }
- if (nex_stats_max < current_test)
- {
- nex_stats_max = current_test;
- nex_stats_max_s = String(buff)+rangeUnit+'A';
- myNex.writeStr("avgmax.txt",nex_stats_max_s);
- }
-
- }
- }
- #endif
- WDTclear();
- handleTouchPads(); //~112uS
- handleAutoOff();
- //Serial.println(micros()-timestamp);
- } //loop()
- void handleVbatRead() {
- //limit how often we read the battery since it's not expected to change a lot
- if (millis() - vbatInterval < VBAT_REFRESH_INTERVAL) return;
- else vbatInterval = millis();
- uint8_t half = analog_ref_half;
- if (half) analogReferenceHalf(false);
- vbat=adcRead(SENSE_VIN);
- if (half) analogReferenceHalf(true);
- vbat=((vbat/ADCFULLRANGE) * ldoValue) * 1.5; //1.5 given by vbat->A5 resistor ratio (1 / (2M * 1/(1M+2M)))
- /*
- syncADC();
- ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[SENSE_VIN].ulADCChannelNumber;
- ADC->INPUTCTRL.bit.MUXNEG = 0x19;//ioGND
- adcRead(); //discard first reading
- vbat = adcRead();
- syncADC();
- ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[SENSE_OUTPUT].ulADCChannelNumber;
- ADC->INPUTCTRL.bit.MUXNEG = g_APinDescription[SENSE_GNDISO].ulADCChannelNumber;
- syncADC();
- */
- }
- uint16_t valM=0, valU=0, valN=0;
- void handleTouchPads() {
- if (millis() - touchSampleInterval < TOUCH_SAMPLE_INTERVAL) return;
- if (TOUCH_DEBUG_ENABLED) {
- Serial.print(qt[2].measure());Serial.print('\t');
- Serial.print(qt[1].measure());Serial.print('\t');
- Serial.println(qt[0].measure());
- }
- bool MA_PRESSED = qt[2].measure()>TOUCH_HIGH_THRESHOLD;
- bool UA_PRESSED = qt[1].measure()>TOUCH_HIGH_THRESHOLD;
- bool NA_PRESSED = qt[0].measure()>TOUCH_HIGH_THRESHOLD;
- touchSampleInterval = millis();
- if (MA_PRESSED || UA_PRESSED || NA_PRESSED) lastKeepAlive=millis();
- //range switching
- if (!AUTORANGE) {
- if (MA_PRESSED && !UA_PRESSED && !NA_PRESSED && rangeUnit!='m') { rangeMA(); rangeBeep(20); }
- if (UA_PRESSED && !MA_PRESSED && !NA_PRESSED && rangeUnit!='u') { rangeUA(); rangeBeep(20); }
- if (NA_PRESSED && !UA_PRESSED && !MA_PRESSED && rangeUnit!='n') { rangeNA(); rangeBeep(20); }
- }
- //LPF activation --- [NA+UA]
- if (UA_PRESSED && NA_PRESSED && !MA_PRESSED && millis()-lpfInterval>1000) { toggleLPF(); Beep(3, false); }
- //offset toggling (GNDISO to half supply) --- [MA+UA]
- if (MA_PRESSED && UA_PRESSED && !NA_PRESSED && millis()-offsetInterval>1000) { toggleOffset(); Beep(3, false); }
- //AUTORANGE toggling
- if (MA_PRESSED && NA_PRESSED && !UA_PRESSED && millis()-autorangeInterval>1000) { toggleAutoranging(); Beep(20, false); delay(50); Beep(20, false); }
- }
- void rangeMA() {
- rangeUnit='m';
- PIN_ON(MA_PIN);
- PIN_OFF(UA_PIN);
- PIN_OFF(NA_PIN);
- if (GPIO_HEADER_RANGING) {
- PIN_ON(MA_GPIO_PIN);
- PIN_OFF(UA_GPIO_PIN);
- PIN_OFF(NA_GPIO_PIN);
- }
- analogReferenceHalf(true);
- #ifdef BT_OUTPUT_ADC
- if (BT_found) SerialBT.println("RANGE: MA");
- #endif
- #ifdef NEXTION_SUPPORT
- myNex.writeNum("b0.bco",NEX_LIGHT_GREY);
- myNex.writeNum("b1.bco",NEX_LIGHT_GREY);
- myNex.writeNum("b2.bco",NEX_BLUE);
- #endif
- }
- void rangeUA() {
- rangeUnit='u';
- PIN_OFF(MA_PIN);
- PIN_ON(UA_PIN);
- PIN_OFF(NA_PIN);
- if (GPIO_HEADER_RANGING) {
- PIN_OFF(MA_GPIO_PIN);
- PIN_ON(UA_GPIO_PIN);
- PIN_OFF(NA_GPIO_PIN);
- }
- analogReferenceHalf(true);
- #ifdef BT_OUTPUT_ADC
- if (BT_found) SerialBT.println("RANGE: UA");
- #endif
- #ifdef NEXTION_SUPPORT
- myNex.writeNum("b0.bco",NEX_LIGHT_GREY);
- myNex.writeNum("b1.bco",NEX_BLUE);
- myNex.writeNum("b2.bco",NEX_LIGHT_GREY);
- #endif
- }
- void rangeNA() {
- rangeUnit='n';
- PIN_OFF(MA_PIN);
- PIN_OFF(UA_PIN);
- PIN_ON(NA_PIN);
- if (GPIO_HEADER_RANGING) {
- PIN_OFF(MA_GPIO_PIN);
- PIN_OFF(UA_GPIO_PIN);
- PIN_ON(NA_GPIO_PIN);
- }
- analogReferenceHalf(true);
- #ifdef BT_OUTPUT_ADC
- if (BT_found) SerialBT.println("RANGE: NA");
- #endif
- #ifdef NEXTION_SUPPORT
- myNex.writeNum("b0.bco",NEX_BLUE);
- myNex.writeNum("b1.bco",NEX_LIGHT_GREY);
- myNex.writeNum("b2.bco",NEX_LIGHT_GREY);
- #endif
- }
- void handleAutoOff() {
- uint32_t autooff_deadline = uint32_t((autooff_interval == AUTOOFF_SMART && !(USB_LOGGING_ENABLED || BT_LOGGING_ENABLED))?AUTOOFF_DEFAULT:autooff_interval)*1000;
-
- if (millis() - lastKeepAlive > autooff_deadline - 5*1000) {
- autoffWarning = true;
- if (millis()-autoOffBuzzInterval> AUTOOFF_BUZZ_DELAY)
- {
- autoOffBuzzInterval = millis();
- autoffBuzz=!autoffBuzz;
- if (autoffBuzz)
- tone(BUZZER, NOTE_B5);
- else
- noTone(BUZZER);
- }
- if (millis() - lastKeepAlive > autooff_deadline) {
- pinMode(AUTOFF, OUTPUT);
- digitalWrite(AUTOFF, LOW);
- }
- }
- else if (autoffWarning) { autoffWarning=autoffBuzz=false; digitalWrite(AUTOFF, HIGH); noTone(BUZZER); }
- }
- void toggleLPF() {
- LPF=!LPF;
- lpfInterval = millis();
- digitalWrite(LPFPIN, LPF);
- digitalWrite(LPFLED, LPF);
- if (AUTORANGE && !LPF) toggleAutoranging(); //turn off AUTORANGE
- #ifdef NEXTION_SUPPORT
- if (LPF) myNex.writeNum("lpf.pic",11);
- else myNex.writeNum("lpf.pic",15);
- #endif
- }
- void toggleOffset() {
- BIAS=!BIAS;
- offsetInterval = millis();
- analogWrite(A0, (BIAS ? DAC_HALF_SUPPLY_OFFSET : DAC_GND_ISO_OFFSET));
- digitalWrite(BIAS_LED, BIAS);
- if (AUTORANGE && BIAS) toggleAutoranging(); //turn off AUTORANGE
- #ifdef NEXTION_SUPPORT
- if (BIAS) myNex.writeNum("bias.pic",12);
- else myNex.writeNum("bias.pic",14);
- #endif
- }
- void toggleAutoranging() {
- autorangeInterval = millis();
- AUTORANGE=!AUTORANGE;
- if (AUTORANGE && BIAS) toggleOffset(); //turn off BIAS
- if (AUTORANGE && !LPF) toggleLPF(); //turn on BIAS
- #ifdef NEXTION_SUPPORT
- if (AUTORANGE) myNex.writeNum("b3.bco",NEX_BLUE);
- else myNex.writeNum("b3.bco",NEX_LIGHT_GREY);
- #endif
- }
- void Beep(byte theDelay, boolean twoSounds) {
- tone(BUZZER, TONE_BEEP, theDelay);
- if (twoSounds)
- {
- delay(10);
- tone(BUZZER, 4500, theDelay);
- }
- }
- static __inline__ void syncADC() __attribute__((always_inline, unused));
- static void syncADC() {
- while(ADC->STATUS.bit.SYNCBUSY == 1);
- }
- void setupADC() {
- ADC->CTRLA.bit.ENABLE = 0; // disable ADC
- syncADC();
- ADC->REFCTRL.bit.REFCOMP = 1;
- ADC->CTRLB.reg = ADC_PRESCALER | ADC_CTRLB_RESSEL_12BIT;
- ADC->AVGCTRL.reg = ADC_AVGCTRL;
- ADC->SAMPCTRL.reg = ADC_SAMPCTRL;
- ADC->CTRLA.bit.ENABLE = 1; // enable ADC
- syncADC();
- // // ADC Linearity/Bias Calibration from NVM (should already be done done in core)
- // uint32_t bias = (*((uint32_t *) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos;
- // uint32_t linearity = (*((uint32_t *) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos;
- // linearity |= ((*((uint32_t *) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5;
- // ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity);
- }
- int adcRead(byte ADCpin) {
- ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ADCpin].ulADCChannelNumber;
- syncADC();
- ADC->SWTRIG.bit.START = 1;
- while (ADC->INTFLAG.bit.RESRDY == 0);
- ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
- syncADC();
- return ADC->RESULT.reg;
- }
- void readVOUT() {
- readDiff = adcRead(SENSE_OUTPUT) - adcRead(SENSE_GNDISO) + offsetCorrectionValue;
- if (!analog_ref_half && readDiff > RANGE_SWITCH_THRESHOLD_LOW && readDiff < RANGE_SWITCH_THRESHOLD_HIGH/3)
- {
- analogReferenceHalf(true);
- readVOUT();
- }
- else if (analog_ref_half && readDiff >= RANGE_SWITCH_THRESHOLD_HIGH)
- {
- analogReferenceHalf(false);
- readVOUT();
- }
- }
- void analogReadCorrectionForced(int offset, uint16_t gain) {
- offsetCorrectionValue=offset;
- gainCorrectionValue=gain;
- analogReadCorrection(offset,gain);
- }
- void WDTset() {
- // Generic clock generator 2, divisor = 32 (2^(DIV+1))
- GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4);
- // Enable clock generator 2 using low-power 32KHz oscillator. With /32 divisor above, this yields 1024Hz(ish) clock.
- GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_DIVSEL;
- while(GCLK->STATUS.bit.SYNCBUSY);
- // WDT clock = clock gen 2
- GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_WDT | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2;
- WDT->CTRL.reg = 0; //disable WDT
- while(WDT->STATUS.bit.SYNCBUSY);
- WDT->INTENCLR.bit.EW = 1; //disable early warning
- WDT->CONFIG.bit.PER = 0xA; //period ~8s
- WDT->CTRL.bit.WEN = 0; //disable window mode
- while(WDT->STATUS.bit.SYNCBUSY);
- WDTclear();
- WDT->CTRL.bit.ENABLE = 1; //enable WDT
- while(WDT->STATUS.bit.SYNCBUSY);
- }
- uint32_t WDTInterval=0;
- void WDTclear() {
- if (millis() - WDTInterval > 6999) //pet the dog every 7s
- {
- WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
- //while(WDT->STATUS.bit.SYNCBUSY);
- WDTInterval=millis();
- }
- }
- void ldoOptimizeRefresh() {
- if (analog_ref_half)
- ldoOptimized = (ldoValue*500)/ADCFULLRANGE;
- else
- ldoOptimized = (ldoValue*1000)/ADCFULLRANGE;
- }
- void saveLDO(float newLdoValue) {
- ldoValue = newLdoValue;
- eeprom_LDO.write(newLdoValue);
- ldoOptimizeRefresh();
- }
- void refreshADCSamplingSpeed() {
- if (ADC_SAMPLING_SPEED==ADC_SAMPLING_SPEED_AVG)
- ADC_AVGCTRL = ADC_AVGCTRL_SAMPLENUM_64 | ADC_AVGCTRL_ADJRES(0x4ul);
- else if (ADC_SAMPLING_SPEED==ADC_SAMPLING_SPEED_FAST)
- ADC_AVGCTRL = ADC_AVGCTRL_SAMPLENUM_16 | ADC_AVGCTRL_ADJRES(0x4ul); //take 16 samples adjust by 4
- else if (ADC_SAMPLING_SPEED==ADC_SAMPLING_SPEED_SLOW)
- ADC_AVGCTRL = ADC_AVGCTRL_SAMPLENUM_256 | ADC_AVGCTRL_ADJRES(0x4ul); //take 512 samples adjust by 4
- setupADC();
- //other combinations:
- //ADC_AVGCTRL_SAMPLENUM_128 | ADC_AVGCTRL_ADJRES(0x4ul)
- //ADC_AVGCTRL_SAMPLENUM_1 | ADC_AVGCTRL_ADJRES(0x00ul); // take 1 sample, adjusting result by 0
- //ADC_AVGCTRL_SAMPLENUM_16 | ADC_AVGCTRL_ADJRES(0x4ul); //take 16 samples adjust by 4
- //ADC_AVGCTRL_SAMPLENUM_256 | ADC_AVGCTRL_ADJRES(0x4ul); //take 256 samples adjust by 4
- //ADC_AVGCTRL_SAMPLENUM_512 | ADC_AVGCTRL_ADJRES(0x4ul); //take 512 samples adjust by 4
- //ADC_AVGCTRL_SAMPLENUM_1024 | ADC_AVGCTRL_ADJRES(0x4ul); //take 1024 samples adjust by 4
- }
- void printCalibInfo() {
- Serial.println("\r\nADC calibration values:");
- Serial.print("Offset="); Serial.println(offsetCorrectionValue);
- Serial.print("Gain="); Serial.println(gainCorrectionValue);
- Serial.print("LDO="); Serial.println(ldoValue,3);
-
- Serial.println("\r\nEEPROM Settings:");
- Serial.print("LoggingFormat="); Serial.println(LOGGING_FORMAT);
- Serial.print("ADCSamplingSpeed="); Serial.println(ADC_SAMPLING_SPEED);
- Serial.print("AutoOff=");
- if (autooff_interval == AUTOOFF_DISABLED) {
- Serial.println("DISABLED");
- } else if (autooff_interval == AUTOOFF_SMART) {
- Serial.println("SMART");
- } else {
- Serial.println(autooff_interval);
- }
- Serial.println("");
- }
- void printSerialMenu() {
- // Print device name, firmware version and state for interop on PC side
- Serial.println("\r\nCurrentRanger R3");
- Serial.print("Firmware version: "); Serial.println(FW_VERSION);
- Serial.print("BT Logging: "); Serial.println(BT_LOGGING_ENABLED);
- Serial.print("USB Logging: "); Serial.println(USB_LOGGING_ENABLED);
- printCalibInfo();
- Serial.println("a = cycle Auto-Off function");
- Serial.print ("b = toggle BT/serial logging (");Serial.print(SERIAL_UART_BAUD);Serial.println("baud)");
- Serial.println("f = cycle serial logging formats (exponent,nA,uA,mA/raw-ADC)");
- Serial.println("g = toggle GPIO range indication (SCK=mA,MISO=uA,MOSI=nA)");
- Serial.println("r = reboot into bootloader");
- Serial.println("s = cycle ADC sampling speeds (0=average,faster,slower)");
- Serial.println("t = toggle touchpad serial output debug info");
- Serial.println("u = toggle USB/serial logging");
- Serial.println("< = Calibrate LDO value (-1mV)");
- Serial.println("> = Calibrate LDO value (+1mV)");
- Serial.println("* = Calibrate GAIN value (+1)");
- Serial.println("/ = Calibrate GAIN value (-1)");
- Serial.println("+ = Calibrate OFFSET value (+1)");
- Serial.println("- = Calibrate OFFSET value (-1)");
- Serial.println("? = Print this menu and calib info");
- Serial.println();
- }
- void analogReferenceHalf(uint8_t half) {
- analog_ref_half = half;
- analogReference(half ? AR_INTERNAL1V65 : AR_DEFAULT);
- ldoOptimizeRefresh();
- }
- void analogReadCorrection(int offset, uint16_t gain) {
- ADC->OFFSETCORR.reg = ADC_OFFSETCORR_OFFSETCORR(offset);
- ADC->GAINCORR.reg = ADC_GAINCORR_GAINCORR(gain);
- ADC->CTRLB.bit.CORREN = 1;
- while(ADC->STATUS.bit.SYNCBUSY);
- }
- void rangeBeep(uint16_t switch_delay) {
- uint16_t freq = NOTE_C5;
- if (RANGE_UA) freq = NOTE_D5;
- if (RANGE_MA) freq = NOTE_E5;
- tone(BUZZER, freq, switch_delay?switch_delay:20);
- }
- #define REBOOT_TOKEN 0xf01669ef //special token in RAM, picked up by the bootloader
- void rebootIntoBootloader() {
- *((volatile uint32_t *)(HMCRAMC0_ADDR + HMCRAMC0_SIZE - 4)) = REBOOT_TOKEN; //Entering bootloader from application: https://github.com/microsoft/uf2-samdx1/issues/41
- NVIC_SystemReset();
- }
- void trigger1(){
- lastKeepAlive=millis();
- if (!AUTORANGE){
- rangeNA(); rangeBeep(0);
- }
- }
- void trigger2(){
- lastKeepAlive=millis();
- if (!AUTORANGE){
- rangeUA(); rangeBeep(0);
- }
- }
- void trigger3(){
- lastKeepAlive=millis();
- if (!AUTORANGE){
- rangeMA(); rangeBeep(0);
- }
- }
- void trigger4(){
- lastKeepAlive=millis();
- toggleAutoranging(); Beep(20, false); delay(50); Beep(20, false);
- }
- void trigger16(){
- lastKeepAlive=millis();
- Beep(20, false);
- myNex.writeStr("page page0","cmd");
- if (LPF) myNex.writeNum("lpf.pic",11);
- else
- {
- myNex.writeNum("lpf.pic",15);
- }
- if (BIAS) myNex.writeNum("bias.pic",12);
- else
- {
- myNex.writeNum("bias.pic",14);
- }
- if (AUTORANGE){
- myNex.writeNum("b3.bco",NEX_BLUE);
- }else{
- myNex.writeNum("b3.bco",NEX_LIGHT_GREY);
- }
- if( rangeUnit=='n') myNex.writeNum("b0.bco",NEX_BLUE);
- if( rangeUnit=='u') myNex.writeNum("b1.bco",NEX_BLUE);
- if( rangeUnit=='m') myNex.writeNum("b2.bco",NEX_BLUE);
- if (nex_timer_run){
- myNex.writeNum("timer.pic",20);
- }
- nex_page=0;
- }
- void trigger17(){
- lastKeepAlive=millis();
- Beep(20, false);
- myNex.writeStr("page page5","cmd");
- if( nex_timer_range==0)
- myNex.writeNum("tma.bco",NEX_BLUE) ;
- else
- myNex.writeNum("tma.bco",NEX_LIGHT_GREY) ;
- if( nex_timer_range==1)
- myNex.writeNum("tua.bco",NEX_BLUE) ;
- else
- myNex.writeNum("tua.bco",NEX_LIGHT_GREY) ;
- if( nex_timer_range==2)
- myNex.writeNum("tna.bco",NEX_BLUE) ;
- else
- myNex.writeNum("tna.bco",NEX_LIGHT_GREY) ;
- myNex.writeNum("dec0.val",nex_timer_d0 );
- myNex.writeNum("dec1.val",nex_timer_d1 );
- myNex.writeNum("dec2.val",nex_timer_d2 );
- myNex.writeNum("dec3.val",nex_timer_d3 );
- if (nex_timer_run){
- myNex.writeNum("starttimer.bco",NEX_BLUE);
- myNex.writeNum("stoptimer.bco",NEX_LIGHT_GREY);
- }else{
- myNex.writeNum("stoptimer.bco",NEX_BLUE);
- myNex.writeNum("starttimer.bco",NEX_LIGHT_GREY);
- }
- myNex.writeStr("timercurrent.txt",nex_timer_current);
- nex_page=5;
- }
- void trigger18(){
- Beep(20, false);
- myNex.writeStr("page page6","cmd");
- if (nex_timerstats_run){
- myNex.writeNum("startstats.bco",NEX_BLUE);
- myNex.writeNum("stopstats.bco",NEX_LIGHT_GREY);
- myNex.writeStr("avgmin.txt",nex_stats_min_s);
- myNex.writeStr("avgavg.txt",nex_stats_avg_s);
- myNex.writeStr("avgmax.txt",nex_stats_max_s);
- }else{
- myNex.writeNum("stopstats.bco",NEX_BLUE);
- myNex.writeNum("startstats.bco",NEX_LIGHT_GREY);
- }
- nex_page=6;
- }
- void trigger19(){
- lastKeepAlive=millis();
- Beep(20, false);
- myNex.writeStr("page page1","cmd");
- nex_page=1;
- }
- void trigger20(){
- lastKeepAlive=millis();
- Beep(20, false);
- myNex.writeStr("page page2","cmd");
- if (analog_ref_half)
- {
- analogReferenceHalf(false);
- vbat=adcRead(SENSE_VIN);
- analogReferenceHalf(true);
- }
- else vbat=adcRead(SENSE_VIN);
- vbat=((vbat/ADCFULLRANGE) * ldoValue) * 1.5; //1.5 given by vbat->A5 resistor ratio (1 / (2M * 1/(1M+2M)))
- nex_page=2;
- myNex.writeStr("page page2","cmd");
- myNex.writeStr("offset.txt",(String)offsetCorrectionValue);
- myNex.writeStr("gain.txt",(String)gainCorrectionValue);
- myNex.writeStr("ldo.txt",String(ldoValue,3));
- myNex.writeStr("fw.txt",(String)FW_VERSION);
- myNex.writeStr("bat.txt",(String)vbat);
- }
- void trigger21(){
- lastKeepAlive=millis();
- Beep(20, false);
- myNex.writeStr("page page3","cmd");
- nex_page=3;
- }
- void trigger32(){
- lastKeepAlive=millis();
- Beep(20, false);
- toggleLPF();
- }
- void trigger33(){
- lastKeepAlive=millis();
- Beep(20, false);
- toggleOffset();
- }
- void trigger34(){
- lastKeepAlive=millis();
- Beep(20, false);
- USB_LOGGING_ENABLED=!USB_LOGGING_ENABLED;
- if (USB_LOGGING_ENABLED) myNex.writeNum("usb.pic",10);
- else
- {
- myNex.writeNum("usb.pic",16);
- }
- }
- void trigger35()
- { //bluetooth
- lastKeepAlive=millis();
- Beep(20, false);
- if (BT_found){
- BT_found=false;
- myNex.writeNum("bluetooth.pic",13);
- }
- else
- {
- uint32_t timer=millis();
- while(millis()-timer<1000) //about 1s to respond
- {
- if (SerialBT.available()==2 && SerialBT.read()=='O' && SerialBT.read()=='K')
- {
- BT_found=true;
- break;
- }
- }
- if (BT_found){
- myNex.writeNum("bluetooth.pic",9);
- }else{
- myNex.writeNum("bluetooth.pic",13);
- }
- }
- }
- void update_current_limit()
- {
- nex_timer_set= nex_timer_d0*1000+nex_timer_d1*100+nex_timer_d2*10+nex_timer_d3;
- Beep(20, false);
- }
- void chronometer(void){ //This function print: "New: Actual time"
- unsigned long currentMillis = millis();
- uint32_t diff_time=0;
- if (nex_timer_run){
- diff_time=currentMillis-nex_timer_start;
- }else{
- diff_time=nex_timer_stop-nex_timer_start;
- }
- long days = 0;
- long hours = 0;
- long mins = 0;
- long secs = 0;
- String secs_o = ":";
- String mins_o = ":";
- String hours_o = ":";
- secs = diff_time / 1000; // set the seconds remaining
- mins = secs / 60; //convert seconds to minutes
- hours = mins / 60; //convert minutes to hours
- days = hours / 24; //convert hours to days
- secs = secs - (mins * 60); //subtract the coverted seconds to minutes in order to display 59 secs max
- mins = mins - (hours * 60); //subtract the coverted minutes to hours in order to display 59 minutes max
- hours = hours - (days * 24); //subtract the coverted hours to days in order to display 23 hours max
- if (secs < 10) {
- secs_o = ":0";
- }
- if (mins < 10) {
- mins_o = ":0";
- }
- if (hours < 10) {
- hours_o = ":0";
- }
- myNex.writeStr("timertext.txt",String(hours)+mins_o+String(mins)+secs_o+String(secs));
- }
- void trigger82()
- {
- nex_timer_range=0;
- myNex.writeNum("tma.bco",NEX_BLUE);
- myNex.writeNum("tua.bco",NEX_LIGHT_GREY);
- myNex.writeNum("tna.bco",NEX_LIGHT_GREY);
- Beep(20, false);
- }
- void trigger83()
- {
- nex_timer_range=1;
- myNex.writeNum("tma.bco",NEX_LIGHT_GREY);
- myNex.writeNum("tua.bco",NEX_BLUE);
- myNex.writeNum("tna.bco",NEX_LIGHT_GREY);
- Beep(20, false);
- }
- void trigger84()
- {
- nex_timer_range=2;
- myNex.writeNum("tma.bco",NEX_LIGHT_GREY);
- myNex.writeNum("tua.bco",NEX_LIGHT_GREY);
- myNex.writeNum("tna.bco",NEX_BLUE);
- Beep(20, false);
- }
- void trigger85()
- {
- myNex.writeNum("starttimer.bco",NEX_BLUE);
- myNex.writeNum("stoptimer.bco",NEX_LIGHT_GREY);
- nex_timer_current="";
- myNex.writeStr("timercurrent.txt",nex_timer_current);
- if (!nex_timer_run){
- nex_timer_start=millis();
- nex_timer_run=true;
- }
- Beep(20, false);
- }
- void trigger86()
- {
- myNex.writeNum("stoptimer.bco",NEX_BLUE);
- myNex.writeNum("starttimer.bco",NEX_LIGHT_GREY);
- if (nex_timer_run){
- nex_timer_stop=millis();
- nex_timer_run=false;
- }
- nex_timer_current="";
- myNex.writeStr("timercurrent.txt",nex_timer_current);
- Beep(20, false);
- }
- void trigger87()
- {
- myNex.writeNum("startstats.bco",NEX_BLUE);
- myNex.writeNum("stopstats.bco",NEX_LIGHT_GREY);
- nex_timer_current="";
- if (!nex_timerstats_run){
- nex_timerstats_run=true;
- }
- nex_stats_min = 0;
- nex_stats_count=0;
- nex_stats_max=0;
- nex_stats_avg=0;
- nex_stats_avg_s="0nA";
- nex_stats_min_s="0nA";
- nex_stats_max_s="0nA";
- myNex.writeStr("avgmin.txt",nex_stats_min_s);
- myNex.writeStr("avgavg.txt",nex_stats_avg_s);
- myNex.writeStr("avgmax.txt",nex_stats_max_s);
- Beep(20, false);
- }
- void trigger88()
- {
- myNex.writeNum("stopstats.bco",NEX_BLUE);
- myNex.writeNum("startstats.bco",NEX_LIGHT_GREY);
- if (nex_timerstats_run){
- nex_timerstats_run=false;
- }
- nex_timer_current="";
- nex_stats_min = 0;
- nex_stats_count=0;
- nex_stats_max=0;
- nex_stats_avg=0;
- Beep(20, false);
- }
|