Skip to content

millis() depends on actual cpu freq #1289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
HDPWR opened this issue Apr 4, 2018 · 6 comments
Closed

millis() depends on actual cpu freq #1289

HDPWR opened this issue Apr 4, 2018 · 6 comments

Comments

@HDPWR
Copy link

HDPWR commented Apr 4, 2018

Hardware:

Board: ?Adafruit ESP32 Feather Clone?
Core Installation/update date: ?15/march/2018?
IDE name: ?Arduino IDE?
Flash Frequency: ?80Mhz?
Upload Speed: ?921600?

Description:

If I change the CPU freq then the output of millis() becomes invalid, it changes inversely proportionally with the freq. Perhaps it is a known error but I haven't see any documentation about it.

#include "soc/rtc.h"

void setup() {
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M);
int startTime, interval;
}

void loop() {
startTime = millis();
delay(1000);
interval = millis() - startTime; // it will be 1000, but that is 3000 in real
}

@lbernstone
Copy link
Contributor

Time is based on ticks. The code has been compiled with each tick being 240MHz (4.2ns). If you change the length of a tick (the CPU frequency), you are responsible for redefining the conversion to real time. If you use a library compiled at 80MHz ticks, you will get the right time.

@HDPWR
Copy link
Author

HDPWR commented Apr 5, 2018

Yep, I thought that less ticks are the route of the problem.
I tried the library, but I still have problems. Mainly I used 80MHz because my HX711 chip cannot handle too fast communication, but now with the new library the situation is the same in spite of the operation became slower. However, if I paste rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); then the communication is flawless but time is three-times slower again. What would you recommend for me?

@copercini
Copy link
Contributor

you can try esp_timer_get_time(); that is the time since the device boot (in microseconds)

@stickbreaker
Copy link
Contributor

@HosszuDaniel here is a test sketch I wrote that uses interrupts and timers to read A HX711, it is clock independent, see if it works for you.

hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

volatile int nextSampleClock=25; // Default channel A 128 Gain
volatile int currentSampleClock=0; // >0 if sample in progress
volatile int sample=0;
volatile int sampleWidth = 0;

#define PD_SCK 17 // pin for sck
#define DOUT 18 // data pin

void IRAM_ATTR onSampleReady(){
  portENTER_CRITICAL_ISR(&timerMux);
  currentSampleClock = nextSampleClock * 2; // highs and lows
  timerAlarmEnable(timer);
  sample = 0;
  sampleWidth = 24;
  detachInterrupt(digitalPinToInterrupt(DOUT)); // shutoff trigger interrupt

  portEXIT_CRITICAL_ISR(&timerMux);

}
 
void IRAM_ATTR onTimer() {

  portENTER_CRITICAL_ISR(&timerMux);

  if(currentSampleClock > 0){ // Sampling in progress
    if((currentSampleClock & 1)==0){ // Set clock High
      digitalWrite(PD_SCK,HIGH);
      }
    else { // else take reading, set clock low
      if(sampleWidth>0){ // ignore the next sample selection clock cycles
        sample = sample << 1;
        sample = sample | digitalRead(DOUT);
        sampleWidth--;
        } 
      digitalWrite(PD_SCK,LOW);
      }
    currentSampleClock--;
    }
  else { //sample done
    timerAlarmDisable(timer);
    }

  portEXIT_CRITICAL_ISR(&timerMux);
 
}

void initHX711(){
  pinMode(DOUT, INPUT_PULLUP);
  digitalWrite(PD_SCK, LOW);
  pinMode(PD_SCK, OUTPUT);

  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true); // every 1 us
  timerAlarmDisable(timer);

}
 
void startConversionHX711(int sampleConfig){
  bool ready=false;
  while(!ready){ // allow last conversion to complete
    yield(); // don't want to starve the watchdog 
    portENTER_CRITICAL(&timerMux);
    ready = currentSampleClock ==0;
    portEXIT_CRITICAL(&timerMux);
    }

  if((sampleConfig <25)||(sampleConfig>27)) nextSampleClock = 25;
  else nextSampleClock = sampleConfig;

  if(digitalRead(DOUT)){// pin is high, attach int, wait for ready
    currentSampleClock = 1; // mark as sample in progress
    attachInterrupt(digitalPinToInterrupt(DOUT), onSampleReady, FALLING);
    }
  else { // already ready, no need for interrupt, just start sampling
    onSampleReady();
    }    
}

bool sampleReadyHX711(){
  bool ready;
  
  portENTER_CRITICAL(&timerMux);
  
  ready = currentSampleClock ==0;
 
  portEXIT_CRITICAL(&timerMux);
  
  return ready;
}
  
int sampleHX711(int sampleConfig){
  startConversionHX711(sampleConfig);
    
  while(!sampleReadyHX711()){ // wait for sample to complete
    yield();
    }
  
  return sample;
    
}

bool readSampleHX711(int &outSample){
if(sampleReadyHX711()) {
  outSample = sample;
  return true;
  }
else {
  outSample = -1;
  return false;
  }
}

void setup() {
 
  Serial.begin(115200);
 
  initHX711();
  
  startConversionHX711(25); // channel a, 128 gain
  
}
 
static uint32_t tick=0;
static uint32_t loopCount =0;

void loop() {
  loopCount++;
  int reading;
  if (readSampleHX711(reading)) {
    uint32_t time=millis();
    Serial.printf("Current HX711 Reading %d, took %ums, looped=%d times\n",reading,time-tick,loopCount);
    startConversionHX711(25);
    tick=millis();
    loopCount=0;
    }
 
}

You should not build code that relies on jiggering processor speed, or looping delays.

Chuck.

@squix78
Copy link
Contributor

squix78 commented Apr 23, 2018

@stickbreaker Thanks for your code, it looks very interesting! Sadly it doesn't work for me. Only change I did to the code was to use pin 21 for data and pin 18 for clock. I would have to re-solder the pins to match your code. From what I can tell readSampleHX711 never returns true, so no sample is retrieved. Can this be related to the pins I used?

Also, if someone is interested, I added the output of my logic analyzer for the bodge/HX711 library here: bogde/HX711#75
Except for the glitch everything looks fine to me. Why would the higher frequency of the CPU be a problem with the HX711?

@copercini
Copy link
Contributor

The main issue was solved here: #1424

@HosszuDaniel @squix78 Please let's discuss the HX711 issue here: #936 to keep things organized =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants