void setup_the_fundulating_conbobulator()
   pinMode(D3, OUTPUT);
   digitalWrite(D3, HIGH);

// The STARTUP call is placed outside of any other function
// What goes inside is any valid code that can be executed. Here, we use a function call.
// Using a single function is preferable to having several `STARTUP()` calls.
STARTUP( setup_the_fundulating_conbobulator() );

Typically an application will have its initialization code in the setup() function. Using SYSTEM_THREAD(ENABLED) reduces the amount of time before setup is called to milliseconds and is the recommended method of calling code early.

The STARTUP() function instructs the system to execute the code even earlier, however there are limitations:

  • STARTUP should only be used for things like setting GPIO state very early.
  • Avoid using most system calls except as listed below. For example, you cannot use System.sleep(), any Particle calls like Particle.publish(), etc.
  • Avoid using I2C (Wire) and SPI from STARTUP.
  • The order of globally constructed objects is unpredictable and you should not rely on global variables being fully initialized.

The code referenced by STARTUP() is executed very early in the startup sequence, so it's best suited to initializing digital I/O and peripherals. Networking setup code should still be placed in setup().

There is one notable exception - WiFi.selectAntenna() should be called from STARTUP() to select the default antenna before the Wi-Fi connection is made on the Photon and P1.

Note that when startup code performs digital I/O, there will still be a period of at least few hundred milliseconds where the I/O pins are in their default power-on state, namely INPUT. Circuits should be designed with this in mind, using pullup/pulldown resistors as appropriate. For Gen 2 devices, see note below about JTAG/SWD as well.

Other acceptable calls to make from STARTUP include:

Gen 2 Devices (STM32) (E-Series, Electron, Photon, and P2; does not include E404X):

Some acceptable calls to make from STARTUP() on Gen 2 devices (Photon, P1, Electron, E-Series) include:

  • cellular_credentials_set()
  • WiFi.selectAntenna()
  • Mouse.begin()
  • Keyboard.begin()

On Gen 2 devices, beware when using pins D3, D5, D6, and D7 as OUTPUT controlling external devices on Gen 2 devices. After reset, these pins will be briefly taken over for JTAG/SWD, before being restored to the default high-impedance INPUT state during boot.

  • D3, D5, and D7 are pulled high with a pull-up
  • D6 is pulled low with a pull-down
  • D4 is left floating

The brief change in state (especially when connected to a MOSFET that can be triggered by the pull-up or pull-down) may cause issues when using these pins in certain circuits. Using STARTUP will not prevent this!