Notes, Misc - mhightower83/Arduino-ESP8266-misc GitHub Wiki

ESP8266 Board Summary

here TODO: Need to verify internal pull-up and pull-down options against Expressive documentation.

CPU Speed Changes

From bbs.espressif.com post by Don Kinzer

I agree that the defines in the include file are misleading. I've done some additional testing and this is what I've found:

  • It appears not to be necessary to use REG_SET_BIT() or REG_CLR_BIT() to change the speed. Simply calling system_update_cpu_freq() with a parameter of 80 or 160 effects the desired speed. Alternatively, one can set/clear the register bit instead of calling system_update_cpu_freq(). In other words, using either alone appears to have the same effect and using both together does not appear to have any additional effect.
  • Specifying a CPU speed of 160 does, in fact, change the execution speed to 160MHz. I confirmed this using an app that toggled an output several times and observed with a logic analyzer that the period was about one-half of that measured when operating at 80MHz.
  • The UART baud rate is not affected by the CPU speed setting. A given divisor produces the same baud rate with both speed settings.
  • The timers of the RTC are not affected by the CPU speed setting. A given timer divisor produces the same rate of change of the RTC timer's COUNT register with both speed settings.

Don Kinzer Beaverton, OR, USA

Flash Access Issue

You cannot reliably access data in flash from an ISR. The problem is not that interrupts are needed to handle cache-miss; it is that the SPI bus may be busy. You could have interrupted a foreground SPI bus operation that is not finished. And, that can happen with an ISR, not in IRAM or an ISR making a call to a non-IRAM function that is not cached. Cache-miss creates demand for a busy SPI bus, thus crash.

No additional interrupts needed for processing a cache-miss, just SPI bus access. Thus we are okay when we start an INTLEVEL 15 from the foreground, there is no SPI bus activity and none can start outside of our execution path. From this context, we can safely access flash.

Atomic Operators on ESP8266

I tried to use an std::atomic_exchange(&lock, 1) function. The sketch compiles; however, it cannot link because of an "undefined reference to __atomic_exchange_4". Apparently, there are no test-and-set instructions on the ESP8266. So far it looks like, for memory exchanges that need to be atomic, you will need to disable and restore interrupts around the sensitive area.

  • For multi-architecture Arduino platforms, this repo looks good. He creates an ATOMIC() macro similar to the ATOMIC_BLOCK() that is available for Arduino AVRs.
  • In the Arduino ESP8266 core the interrupts.h file has two class-based options for doing this:
    • InterruptsLock - Disables all interrupts through level 15.
      {
           esp8266::InterruptLock lock;
           // Do sensitive stuff with interrupts locked out.
      }
      // Back to normal interrupt operations in background.
      
    • A macro AutoInterruptLock(level) that defines a class inline, then uses it to start the process.
      {
           esp8266::AutoInterruptLock(3);  // Allows interrupt levels above 3
           // Do sensitive stuff with interrupts up to 3 locked out.
      }
      // Back to normal interrupt operations in background.
      
    • Something like this also seems to compile down nicely:
      int interlocked_exchange_int(volatile int *target, int value) {
          uint32_t ps = xt_rsil(15);
          int oldValue = *target;
          *target = value;
          xt_wsr_ps(ps);
          return oldValue;
      }
      

String Class - Use Considerations

"In Libraries String use is not recommended by inexperienced programmers."

Based on Develo's comments:: The String class manages its own dynamic allocs internally, and the user must be aware of how it behaves in a tiny system like the ESP. Usage such as pass-by-value (Creates a copy, use pass by reference.) or long sequences of concats (Many small allocs causes heap fragmentation, use .reserve.) are bad. Using when receiving chars and not knowing when the sequence ends is preferable to C-style manual handling of the dynamic allocs, so it's good. As a user, it can ease a whole lot of use cases, but you must be a responsible adult and use them correctly.

  • Use .reserve when many small concat operations may occur.
  • Pass by reference, not by value and use const when possible.
  • Starting with Core 2.5.0, Small String Optimization, SSO, was added. A String object can hold up to an 11 character string (+ '/0', 12 chars total) before an alloc is done.

WiFi Init Notes

Start by extracting some interesting details from Arduino ESP8266 Core Issue #1054 There are a lot more interesting points in this issue discussion.

WiFi.mode(WIFI_AP_STA);
WiFi.softAP(ap_ssid, SecuritySettings.WifiAPKey);
  • Only call these when there is a change in WiFi settings.
WiFi.mode(WIFI_STA);
WiFi.begin(id, pass);

Each time these are done, the Espressif SDK writes these settings to flash memory. If these are done at every boot, depending on your frequency, this might result in some wear to these sectors of flash memory. ref(https://github.com/esp8266/Arduino/issues/1054#issuecomment-158404894)

Scheduled Functions

There are two classes of Scheduled Functions: (Extraced from d-a-v's comment)

  1. One time
    • Scheduled functions are not called from yield(), because they are allowed to call yield().
    • They are only called at next loop().
  2. Reoccurring
    • Reoccurring scheduled functions, must not call yield(), because they are called from yield().

WiFi Debug Logging - Connect Semantics Issue

I think there is a semantics issue created by looking at the SDK debug logging. It looks to me that the SDK concept of "connected" is based on 802.11 of being connected to an AP. The Core.'s concept of "connected" is based on being able to use the Network, eg. connected to AP, and having an IP address.

  • SDK wifi evt: 0 (EVENT_STAMODE_CONNECTED) - which I take to mean finished 802.11 negotiations with the AP were successful.
  • SDK wifi evt: 3 (EVENT_STAMODE_GOT_IP) indicates got an IP address, either DHCP has succeeded or used a static IP address.
  • The Arduino ESP8266 core returns connected, WiFi.status() == WL_CONNECTED, when the SDK API wifi_station_get_connect_status() returns STATION_GOT_IP. Note, SDK status and events have a different set of enums.

So the SDK can be connected to an AP w/o an IP Address, and the Arduino ESP8266 Core will continue to report != WL_CONNECTED because the connection is not complete from a user's perspective.