Skip to content
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

Add support for ESP32 #5

Merged
merged 3 commits into from
Sep 26, 2021
Merged

Conversation

alexthomazo
Copy link
Contributor

@alexthomazo alexthomazo commented Sep 25, 2021

Hello,

After some debugging this afternoon, I managed to have a working version of the library working on an ESP32.

It was not working because the ESP32 is way too faster that the Arduino UNO for setting a pin value so the clock was not within the specs of the TM1637. The datasheet specify a minimum clock pulse of 400ns but the ESP32 done that in ~50ns.

I add a delay after each write in order to comply with the TM1637 specs. The delay is only added for the ESP32 in order to not slow down the write on the Arduino.

related to #3

@RobTillaart
Copy link
Owner

Thanks for this addition I will do a code check

@RobTillaart
Copy link
Owner

It looks good, overal just one remark on code level to make other timing adjustments possible

However thinking about it, you need a delay of 400 ns and you use 1000 ns.

Is there a way to write the delayNanoseconds() - (drawback) it is CPU clock dependent...

something like

void delayNanoseconds(uint32_t  ns)
{
  ns >>= 5;   // every loop takes about 32 nanoseconds @ 240 MHz
  while (ns--)
  {
    __asm__ __volatile__ ("nop");  // 1 nop = 1000 /240 ~~ 4ns;
  }
}

One might need initially get the ESP32 board frequency - Freq = getCpuFrequencyMhz();

TM1637.cpp Outdated Show resolved Hide resolved
@RobTillaart
Copy link
Owner

small test

uint32_t start, duration;

void setup()
{
  Serial.begin(115200);

  for (uint16_t n = 100; n < 3100; n += 100)
  {
    start = micros();
    nanoDelay240(n);
    duration = micros() - start;
    Serial.print(n);
    Serial.print("\t");
    Serial.println(duration);
    delay(10);
  }
}

void loop()
{
}

void nanoDelay240(uint16_t n)    // 240 ==> at 240 MHz
{
  volatile uint16_t i;
  for (i = 0; i < n; ++i);
}

one iteration seems to be about 91 nanoseconds so to get a 400ns delay ==> n = 4 or 5 ?

Can you test?

@alexthomazo
Copy link
Contributor Author

Hello Rob,

Thanks for all your suggestions, yes I will test it to see if it's possible to reduce the delay furthermore.

@alexthomazo
Copy link
Contributor Author

After some tests, it's working with nanoDelay with only 2 loops. It's almost working with 1 loop but I see some weird issues on the display with it.

Here the timing diagram for ESP32 with 2 loops.
esp32_full
esp32_details

Same timings with the Arduino UNO:
arduino_full
arduino_details

Also, it's working as well when removing the delayMicroseconds when getting acknowledge (the diagrams are without), I don't really know if it's really needed as the ACK is not used afterward. So I don't remove it on my pull request but it's definitively working on Arduino and ESP32 without it.

@RobTillaart
Copy link
Owner

Wow, looks pretty clean signal to me.
How much time did you gain?
How much faster is the ESP compared to the UNO now?

@RobTillaart
Copy link
Owner

did a test here and found a version that is 40% faster so in theory more accurate nanoDelay
the -- instruction in combination with the automatic compare to zero is less machine instructions
as the ++ and the comparison with n.

Think you should be able to squeeze some nanoseconds of, - which add up to microseconds

void nanoDelay(uint16_t n)
{
  volatile uint16_t i = n;
  while (i--);
}

@RobTillaart
Copy link
Owner

Think the PR looks good, will merge after you confirmed (or not) if the new nanoDelay() works better.

Using new nanoDelay, total time from 133us to 113us
@alexthomazo
Copy link
Contributor Author

I tried with the new nanoDelay, succeed to gain a little more (113us instead of 133us), it's not working if I go lower.

@RobTillaart
Copy link
Owner

I tried with the new nanoDelay, succeed to gain a little more (113us instead of 133us), it's not working if I go lower.

had a thought,
when the CLOCK is set LOW, it is followed by a nanoDelay() to be sure the period is long enough.
However that LOW is followed by writing the DATA, with its own nanoDelay().
As the data is actually read after the CLOCK goes HIGH, the nanoDelay() should not be needed with the CLOCK LOW command.

(think that would keep al signals just limits but could save another 25-30% ?

That's my final squeeze :)

@alexthomazo
Copy link
Contributor Author

Yes, I've got the same idea, already tried it but unfortunately it's not working and the datasheet is not very explicit for theses timings.

@Niv1900
Copy link

Niv1900 commented Sep 26, 2021

Thanks @alexthomazo and @RobTillaart!

When I tried to use level shifter to solve #3 it didn't work and I blame the fault on the level shifter not working properly.

@RobTillaart RobTillaart merged commit 68c3ed5 into RobTillaart:master Sep 26, 2021
@RobTillaart
Copy link
Owner

Merged into master branch,
I will update version numbers etc tonight and make a new release

Thanks @alexthomazo for code, investigating and testing!

@RobTillaart
Copy link
Owner

0.2.0 version released

@alexthomazo
Copy link
Contributor Author

Thanks 🙂

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

Successfully merging this pull request may close these issues.

3 participants