1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-27 01:56:14 +01:00

make the Adc class functions the normal code path

This commit is contained in:
Harald Barth 2022-10-04 21:55:13 +02:00
parent 367d2dfe20
commit ee568fcd11
9 changed files with 100 additions and 85 deletions

View File

@ -425,7 +425,7 @@ void DCCACK::checkAck(byte sentResetsSincePacket) {
return; return;
} }
int current=progDriver->getCurrentRawInInterrupt(); int current=progDriver->getCurrentRaw(true); // true means "from interrupt"
numAckSamples++; numAckSamples++;
if (current > ackMaxCurrent) ackMaxCurrent=current; if (current > ackMaxCurrent) ackMaxCurrent=current;
// An ACK is a pulse lasting between minAckPulseDuration and maxAckPulseDuration uSecs (refer @haba) // An ACK is a pulse lasting between minAckPulseDuration and maxAckPulseDuration uSecs (refer @haba)

View File

@ -95,8 +95,12 @@ private:
class Adc { class Adc {
public: public:
static void reg(uint8_t pin); // On architectures that use the analog read during DCC waveform
static int read(uint8_t pin); // with specially configured ADC, for example AVR, init must be
// called PRIOR to the start of the waveform. It returns the
// current value so that an offset can be initialized.
static int init(uint8_t pin);
static int read(uint8_t pin, bool fromISR);
private: private:
static void scan(); static void scan();
static void begin(); static void begin();

View File

@ -129,19 +129,26 @@ int * Adc::analogvals = NULL;
/* /*
* Register a new pin to be scanned * Register a new pin to be scanned
* Returns current reading of pin and
* stores that as well
*/ */
void Adc::reg(uint8_t pin) { int Adc::init(uint8_t pin) {
uint8_t id = pin - A0; uint8_t id = pin - A0;
if (id > NUM_ADC_INPUTS) if (id > NUM_ADC_INPUTS)
return; return -1023;
pinMode(pin, INPUT);
int value = analogRead(pin);
if (analogvals == NULL) if (analogvals == NULL)
analogvals = (int *)calloc(NUM_ADC_INPUTS+1, sizeof(int)); analogvals = (int *)calloc(NUM_ADC_INPUTS+1, sizeof(int));
analogvals[id] = value;
usedpins |= (1<<id); usedpins |= (1<<id);
return value;
} }
/* /*
* Read function Adc::read(pin) to get value instead of analogRead(pin) * Read function Adc::read(pin) to get value instead of analogRead(pin)
*/ */
int Adc::read(uint8_t pin) { int Adc::read(uint8_t pin, bool fromISR) {
(void)fromISR; // AVR does ignore this arg
uint8_t id = pin - A0; uint8_t id = pin - A0;
if ((usedpins & (1<<id) ) == 0) if ((usedpins & (1<<id) ) == 0)
return -1023; return -1023;

View File

@ -78,6 +78,23 @@ int DCCTimer::freeMemory() {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#include <driver/adc.h>
#include <soc/sens_reg.h>
#include <soc/sens_struct.h>
#undef ADC_INPUT_MAX_VALUE
#define ADC_INPUT_MAX_VALUE 4095 // 12 bit ADC
#define pinToADC1Channel(X) (adc1_channel_t)(((X) > 35) ? (X)-36 : (X)-28)
int IRAM_ATTR local_adc1_get_raw(int channel) {
uint16_t adc_value;
SENS.sar_meas_start1.sar1_en_pad = (1 << channel); // only one channel is selected
while (SENS.sar_slave_addr1.meas_status != 0);
SENS.sar_meas_start1.meas1_start_sar = 0;
SENS.sar_meas_start1.meas1_start_sar = 1;
while (SENS.sar_meas_start1.meas1_done_sar == 0);
adc_value = SENS.sar_meas_start1.meas1_data_sar;
return adc_value;
}
#include "DCCTimer.h" #include "DCCTimer.h"
INTERRUPT_CALLBACK interruptHandler=0; INTERRUPT_CALLBACK interruptHandler=0;
@ -133,5 +150,26 @@ int DCCTimer::freeMemory() {
void DCCTimer::reset() { void DCCTimer::reset() {
ESP.restart(); ESP.restart();
} }
#endif int Adc::init(uint8_t pin) {
pinMode(pin, ANALOG);
adc1_config_channel_atten(pinToADC1Channel(pin),ADC_ATTEN_DB_11);
return local_adc1_get_raw(pinToADC1Channel(pin));
}
/*
* Read function Adc::read(pin) to get value instead of analogRead(pin)
*/
int Adc::read(uint8_t pin, bool fromISR) {
return local_adc1_get_raw(pinToADC1Channel(pin));
}
/*
* Scan function that is called from interrupt
*/
void Adc::scan() {
}
void Adc::begin() {
adc1_config_width(ADC_WIDTH_BIT_12);
}
#endif //ESP32

View File

@ -37,24 +37,6 @@ INTERRUPT_CALLBACK interruptHandler=0;
void DCCTimer::begin(INTERRUPT_CALLBACK callback) { void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
interruptHandler=callback; interruptHandler=callback;
noInterrupts(); noInterrupts();
// Set up ADC to do faster reads... default for Arduino Zero platform configs is 436uS,
// and we need sub-100uS. This code sets it to a read speed of around 21uS, and for now
// enables 10-bit mode, although 12-bit is possible
ADC->CTRLA.bit.ENABLE = 0; // disable ADC
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // wait for synchronization
ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits
ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64 | // divide Clock by 64
ADC_CTRLB_RESSEL_10BIT; // Result on 10 bits default, 12 bits possible
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample at a time
ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0
ADC->SAMPCTRL.reg = 0x00; // sampling Time Length = 0
ADC->CTRLA.bit.ENABLE = 1; // enable ADC
while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization
// Timer setup - setup clock sources first // Timer setup - setup clock sources first
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1
GCLK_GENDIV_ID(4); // Apply to GCLK4 GCLK_GENDIV_ID(4); // Apply to GCLK4
@ -173,4 +155,43 @@ void DCCTimer::reset() {
while(true) {}; while(true) {};
} }
int Adc::init(uint8_t pin) {
return analogRead(pin);
}
/*
* Read function Adc::read(pin) to get value instead of analogRead(pin)
*/
int Adc::read(uint8_t pin, bool fromISR) {
int current;
if (!fromISR) noInterrupts();
current = analogRead(pin);
if (!fromISR) interrupts();
return current;
}
/*
* Scan function that is called from interrupt
*/
void Adc::scan() {
}
void Adc::begin() {
noInterrupts();
// Set up ADC to do faster reads... default for Arduino Zero platform configs is 436uS,
// and we need sub-100uS. This code sets it to a read speed of around 21uS, and for now
// enables 10-bit mode, although 12-bit is possible
ADC->CTRLA.bit.ENABLE = 0; // disable ADC
while( ADC->STATUS.bit.SYNCBUSY == 1 ); // wait for synchronization
ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits
ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64 | // divide Clock by 64
ADC_CTRLB_RESSEL_10BIT; // Result on 10 bits default, 12 bits possible
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample at a time
ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0
ADC->SAMPCTRL.reg = 0x00; // sampling Time Length = 0
ADC->CTRLA.bit.ENABLE = 1; // enable ADC
while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization
interrupts();
}
#endif #endif

View File

@ -82,10 +82,8 @@ void DCCWaveform::interruptHandler() {
TrackManager::setDCCSignal(sigMain); TrackManager::setDCCSignal(sigMain);
TrackManager::setPROGSignal(sigProg); TrackManager::setPROGSignal(sigProg);
#ifdef ANALOG_READ_INTERRUPT // Refresh the values in the Adc object buffering the values of the ADC HW
//TrackManager::sampleCurrent();
Adc::scan(); Adc::scan();
#endif
// Move on in the state engine // Move on in the state engine
mainTrack.state=stateTransform[mainTrack.state]; mainTrack.state=stateTransform[mainTrack.state];

View File

@ -30,24 +30,6 @@
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
#include "ESP32-fixes.h" #include "ESP32-fixes.h"
#include <driver/adc.h>
#include <soc/sens_reg.h>
#include <soc/sens_struct.h>
#undef ADC_INPUT_MAX_VALUE
#define ADC_INPUT_MAX_VALUE 4095 // 12 bit ADC
#define pinToADC1Channel(X) (adc1_channel_t)(((X) > 35) ? (X)-36 : (X)-28)
int IRAM_ATTR local_adc1_get_raw(int channel) {
uint16_t adc_value;
SENS.sar_meas_start1.sar1_en_pad = (1 << channel); // only one channel is selected
while (SENS.sar_slave_addr1.meas_status != 0);
SENS.sar_meas_start1.meas1_start_sar = 0;
SENS.sar_meas_start1.meas1_start_sar = 1;
while (SENS.sar_meas_start1.meas1_done_sar == 0);
adc_value = SENS.sar_meas_start1.meas1_data_sar;
return adc_value;
}
#endif #endif
bool MotorDriver::commonFaultPin=false; bool MotorDriver::commonFaultPin=false;
@ -110,18 +92,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i
currentPin=current_pin; currentPin=current_pin;
if (currentPin!=UNUSED_PIN) { if (currentPin!=UNUSED_PIN) {
#ifdef ARDUINO_ARCH_ESP32 senseOffset = Adc::init(currentPin);
pinMode(currentPin, ANALOG);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(pinToADC1Channel(currentPin),ADC_ATTEN_DB_11);
senseOffset = adc1_get_raw(pinToADC1Channel(currentPin));
#else
pinMode(currentPin, INPUT);
Adc::reg(currentPin);
// run analogRead as Adc::read() does not have any values before
// the waveform has been started.
senseOffset=analogRead(currentPin); // value of sensor at zero current
#endif
} }
faultPin=fault_pin; faultPin=fault_pin;
@ -223,20 +194,7 @@ int MotorDriver::getCurrentRaw(bool fromISR) {
(void)fromISR; (void)fromISR;
if (currentPin==UNUSED_PIN) return 0; if (currentPin==UNUSED_PIN) return 0;
int current; int current;
#ifdef ARDUINO_ARCH_ESP32 current = Adc::read(currentPin, fromISR)-senseOffset;
current = local_adc1_get_raw(pinToADC1Channel(currentPin))-senseOffset;
#else
#ifdef ANALOG_READ_INTERRUPT
current = Adc::read(currentPin)-senseOffset;
//current = sampleCurrent-senseOffset;
//if ((millis() - sampleCurrentTimestamp) > 3)
// DIAG(F("Current sample old %d"), millis() - sampleCurrentTimestamp);
#else
if (!fromISR) noInterrupts();
current = analogRead(currentPin)-senseOffset;
if (!fromISR) interrupts();
#endif //ANALOG_READ_INTERRUPT
#endif //ARDUINO_ARCH_ESP32
if (current<0) current=0-current; if (current<0) current=0-current;
if ((faultPin != UNUSED_PIN) && isLOW(fastFaultPin) && powerMode==POWERMODE::ON) if ((faultPin != UNUSED_PIN) && isLOW(fastFaultPin) && powerMode==POWERMODE::ON)
return (current == 0 ? -1 : -current); return (current == 0 ? -1 : -current);

View File

@ -153,12 +153,7 @@ class MotorDriver {
setDCSignal(128); setDCSignal(128);
#endif #endif
}; };
int getCurrentRaw() { int getCurrentRaw(bool fromISR=false);
return getCurrentRaw(false);
}
int getCurrentRawInInterrupt() {
return getCurrentRaw(true);
};
unsigned int raw2mA( int raw); unsigned int raw2mA( int raw);
unsigned int mA2raw( unsigned int mA); unsigned int mA2raw( unsigned int mA);
inline bool brakeCanPWM() { inline bool brakeCanPWM() {
@ -192,7 +187,6 @@ class MotorDriver {
void startCurrentFromHW(); void startCurrentFromHW();
#endif #endif
private: private:
int getCurrentRaw(bool fromISR);
bool isProgTrack = false; // tells us if this is a prog track bool isProgTrack = false; // tells us if this is a prog track
void getFastPin(const FSH* type,int pin, bool input, FASTPIN & result); void getFastPin(const FSH* type,int pin, bool input, FASTPIN & result);
void getFastPin(const FSH* type,int pin, FASTPIN & result) { void getFastPin(const FSH* type,int pin, FASTPIN & result) {

View File

@ -43,11 +43,6 @@
#undef USB_SERIAL // Teensy has this defined by default... #undef USB_SERIAL // Teensy has this defined by default...
#define USB_SERIAL Serial #define USB_SERIAL Serial
// All AVRs must read analog values from the DCC timer interrupt
#ifdef ARDUINO_ARCH_AVR
#define ANALOG_READ_INTERRUPT
#endif
#if defined(ARDUINO_AVR_UNO) #if defined(ARDUINO_AVR_UNO)
#define ARDUINO_TYPE "UNO" #define ARDUINO_TYPE "UNO"
#undef HAS_ENOUGH_MEMORY #undef HAS_ENOUGH_MEMORY