Prvni ulozeni z chegewara githubu
This commit is contained in:
92
docs/source/tutorials/basic.rst
Normal file
92
docs/source/tutorials/basic.rst
Normal file
@ -0,0 +1,92 @@
|
||||
##############
|
||||
Basic Tutorial
|
||||
##############
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This is the basic tutorial and should be used as template for other tutorials.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* Arduino IDE
|
||||
* ESP32 Board
|
||||
* Good USB Cable
|
||||
|
||||
Steps
|
||||
-----
|
||||
|
||||
Here are the steps for this tutorial.
|
||||
|
||||
1. Open the Arduino IDE
|
||||
|
||||
.. figure:: ../_static/tutorials/basic/tutorial_basic_ide.png
|
||||
:align: center
|
||||
:width: 600
|
||||
:alt: Arduino IDE (click to enlarge)
|
||||
:figclass: align-center
|
||||
|
||||
2. Build and Flash the `blink` project.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
.. code-block:: arduino
|
||||
:caption: Blink.ino
|
||||
|
||||
/*
|
||||
Blink
|
||||
|
||||
Turns an LED on for one second, then off for one second, repeatedly.
|
||||
|
||||
Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
|
||||
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
|
||||
the correct LED pin independent of which board is used.
|
||||
If you want to know what pin the on-board LED is connected to on your Arduino
|
||||
model, check the Technical Specs of your board at:
|
||||
https://www.arduino.cc/en/Main/Products
|
||||
|
||||
modified 8 May 2014
|
||||
by Scott Fitzgerald
|
||||
modified 2 Sep 2016
|
||||
by Arturo Guadalupi
|
||||
modified 8 Sep 2016
|
||||
by Colby Newman
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/Blink
|
||||
*/
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup() {
|
||||
// initialize digital pin LED_BUILTIN as an output.
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
// the loop function runs over and over again forever
|
||||
void loop() {
|
||||
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
|
||||
delay(1000); // wait for a second
|
||||
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
|
||||
delay(1000); // wait for a second
|
||||
}
|
||||
|
||||
Log Output
|
||||
----------
|
||||
|
||||
If the log output from the serial monitor is relevant, please add here:
|
||||
|
||||
.. code-block::
|
||||
|
||||
I (0) cpu_start: App cpu up.
|
||||
I (418) cpu_start: Pro cpu start user code
|
||||
I (418) cpu_start: cpu freq: 160000000
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* `ESP32 Datasheet`_ (Datasheet)
|
||||
|
||||
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
|
113
docs/source/tutorials/blink.rst
Normal file
113
docs/source/tutorials/blink.rst
Normal file
@ -0,0 +1,113 @@
|
||||
##########################
|
||||
Blink Interactive Tutorial
|
||||
##########################
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This is the interactive blink tutorial using `Wokwi`_. For this tutorial, you don't need the ESP32 board or the Arduino toolchain.
|
||||
|
||||
.. note:: If you don't want to use this tutorial with the simulation, you can copy and paste the :ref:`blink_example_code` from `Wokwi`_ editor and use it on the `Arduino IDE`_ or `PlatformIO`_.
|
||||
|
||||
About this Tutorial
|
||||
-------------------
|
||||
|
||||
This tutorial is the most basic for any get started. In this tutorial, we will show how to set a GPIO pin as an output to drive a LED to blink each 1 second.
|
||||
|
||||
Step by step
|
||||
------------
|
||||
|
||||
In order to make this simple blink tutorial, you'll need to do the following steps.
|
||||
|
||||
1. **Define the GPIO for the LED.**
|
||||
|
||||
.. code-block::
|
||||
|
||||
#define LED 2
|
||||
|
||||
This ``#define LED 2`` will be used to set the GPIO2 as the ``LED`` output pin.
|
||||
|
||||
2. **Setup.**
|
||||
|
||||
Inside the ``setup()`` function, we need to add all things we want to run once during the startup.
|
||||
Here we'll add the ``pinMode`` function to set the pin as output.
|
||||
|
||||
.. code-block::
|
||||
|
||||
void setup() {
|
||||
pinMode(LED, OUTPUT);
|
||||
}
|
||||
|
||||
The first argument is the GPIO number, already defined and the second is the mode, here defined as an output.
|
||||
|
||||
3. **Main Loop.**
|
||||
|
||||
After the ``setup``, the code runs the ``loop`` function infinitely. Here we will handle the GPIO in order to get the LED blinking.
|
||||
|
||||
.. code-block::
|
||||
|
||||
void loop() {
|
||||
digitalWrite(LED, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(LED, LOW);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
The first function is the ``digitalWrite()`` with two arguments:
|
||||
|
||||
* GPIO: Set the GPIO pin. Here defined by our ``LED`` connected to the GPIO2.
|
||||
* State: Set the GPIO state as HIGH (ON) or LOW (OFF).
|
||||
|
||||
This first ``digitalWrite`` we will set the LED ON.
|
||||
|
||||
After the ``digitalWrite``, we will set a ``delay`` function in order to wait for some time, defined in milliseconds.
|
||||
|
||||
Now we can set the GPIO to ``LOW`` to turn the LED off and ``delay`` for more few milliseconds to get the LED blinking.
|
||||
|
||||
4. **Run the code.**
|
||||
|
||||
To run this code, you'll need a development board and the Arduino toolchain installed on your computer. If you don't have both, you can use the simulator to test and edit the code.
|
||||
|
||||
Simulation
|
||||
----------
|
||||
|
||||
This simulator is provided by `Wokwi`_ and you can test the blink code and play with some modifications to learn more about this example.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<iframe src="https://wokwi.com/arduino/projects/305566932847821378?embed=1" width="100%" height="400" border="0"></iframe>
|
||||
|
||||
Change the parameters, like the delay period, to test the code right on your browser. You can add more LEDs, change the GPIO, and more.
|
||||
|
||||
.. _blink_example_code:
|
||||
|
||||
Example Code
|
||||
------------
|
||||
|
||||
Here is the full blink code.
|
||||
|
||||
.. code-block::
|
||||
|
||||
#define LED 2
|
||||
|
||||
void setup() {
|
||||
pinMode(LED, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
digitalWrite(LED, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(LED, LOW);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* `ESP32 Datasheet`_ (Datasheet)
|
||||
* `Wokwi`_ (Wokwi Website)
|
||||
|
||||
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
|
||||
.. _Wokwi: https://wokwi.com/
|
||||
.. _PlatformIO: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#platformio
|
||||
.. _Arduino IDE: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#installing-using-boards-manager
|
120
docs/source/tutorials/cdc_dfu_flash.rst
Normal file
120
docs/source/tutorials/cdc_dfu_flash.rst
Normal file
@ -0,0 +1,120 @@
|
||||
########################
|
||||
USB CDC and DFU Flashing
|
||||
########################
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Since the ESP32-S2 introduction, Espressif has been working on USB peripheral support for some of the SoC families, including the ESP32-C3 and the ESP32-S3.
|
||||
|
||||
This new peripheral allows a lot of new possibilities, including flashing the firmware directly to the SoC without any external USB-to-Serial converter.
|
||||
|
||||
In this tutorial, you will be guided on how to use the embedded USB to flash the firmware.
|
||||
|
||||
**The current list of supported SoCs:**
|
||||
|
||||
========= =======================
|
||||
SoC USB Peripheral Support
|
||||
========= =======================
|
||||
ESP32-S2 CDC and DFU
|
||||
ESP32-C3 CDC only
|
||||
ESP32-S3 CDC and DFU
|
||||
========= =======================
|
||||
|
||||
It's important that your board includes the USB connector attached to the embedded USB from the SoC. If your board doesn't have the USB connector, you can attach an external one to the USB pins.
|
||||
|
||||
These instructions it will only work on the supported devices with the embedded USB peripheral. This tutorial will not work if you are using an external USB-to-serial converter like FTDI, CP2102, CH340, etc.
|
||||
|
||||
For a complete reference to the Arduino IDE tools menu, please see the `Tools Menus <../guides/tools_menu.html>`_ reference guide.
|
||||
|
||||
USB DFU
|
||||
-------
|
||||
|
||||
The USB DFU (Device Firmware Upgrade) is a class specification from the USB standard that adds the ability to upgrade the device firmware by the USB interface.
|
||||
|
||||
Flashing Using DFU
|
||||
******************
|
||||
|
||||
.. note::
|
||||
DFU is only supported by the ESP32-S2 and ESP32-S3. See the table of supported SoCs.
|
||||
|
||||
To use the USB DFU to flash the device, you will need to configure some settings in the Arduino IDE according to the following steps:
|
||||
|
||||
1. Enter into Download Mode manually
|
||||
|
||||
This step is done only for the first time you flash the firmware in this mode. To enter into the download mode, you need to press and hold BOOT button and press and release the RESET button.
|
||||
|
||||
To check if this procedure was done correctly, now you will see the new USB device listed in the available ports. Select this new device in the **Port** option.
|
||||
|
||||
2. Configure the USB DFU
|
||||
|
||||
In the next step you can set the USB DFU as default on BOOT and for flashing.
|
||||
|
||||
Go to the Tools menu in the Arduino IDE and set the following options:
|
||||
|
||||
**For ESP32-S2**
|
||||
|
||||
* USB DFU On Boot -> Enable
|
||||
|
||||
* Upload Mode -> Internal USB
|
||||
|
||||
**For ESP32-S3**
|
||||
|
||||
* USB Mode -> USB-OTG (TinyUSB)
|
||||
|
||||
* USB DFU On Boot -> Enabled
|
||||
|
||||
Setp 3 - Flash
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Now you can upload your sketch to the device. After flashing, you need to manually reset the device.
|
||||
|
||||
.. note::
|
||||
On the USB DFU, you can't use the USB for the serial output for the logging, just for flashing. To enable the serial output, use the CDC option instead.
|
||||
If you want to use the USB DFU for just upgrading the firmware using the manual download mode, this will work just fine, however, for developing please consider using USB CDC.
|
||||
|
||||
|
||||
USB CDC
|
||||
-------
|
||||
|
||||
The USB CDC (Communications Device Class) allows you to communicate to the device like in a serial interface. This mode can be used on the supported targets to flash and monitor the device in a similar way on devices that uses the external serial interfaces.
|
||||
|
||||
To use the USB CDC, you need to configure your device in the Tools menu:
|
||||
|
||||
|
||||
1. Enter into Download Mode manually
|
||||
|
||||
Similar to the DFU mode, you will need to enter into download mode manually. To enter into the download mode, you need to press and hold BOOT button and press and release the RESET button.
|
||||
|
||||
To check if this procedure was done correctly, now you will see the new USB device listed in the available ports. Select this new device in the **Port** option.
|
||||
|
||||
2. Configure the USB CDC
|
||||
|
||||
**For ESP32-S2**
|
||||
|
||||
* USB CDC On Boot -> Enabled
|
||||
|
||||
* Upload Mode -> Internal USB
|
||||
|
||||
**For ESP32-C3**
|
||||
|
||||
* USB CDC On Boot -> Enabled
|
||||
|
||||
**For ESP32-S3**
|
||||
|
||||
* USB CDC On Boot -> Enabled
|
||||
|
||||
* Upload Mode -> UART0 / Hardware CDC
|
||||
|
||||
3. Flash and Monitor
|
||||
|
||||
You can now upload your sketch to the device. After flashing for the first time, you need to manually reset the device.
|
||||
|
||||
This procedure enables the flashing and monitoring thought the internal USB and does not requires you to manually enter into the download mode or to do the manual reset after flashing.
|
||||
|
||||
To monitor the device, you need to select the USB port and open the Monitor tool selecting the correct baud rate (usually 115200) according to the ``Serial.begin()`` defined in your code.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
|
||||
If you are developing a custom hardware using the compatible SoC, and want to remove the external USB-to-Serial chip, this feature will complete substitute the needs of the external chip. See the SoC datasheet for more details about this peripheral.
|
119
docs/source/tutorials/io_mux.rst
Normal file
119
docs/source/tutorials/io_mux.rst
Normal file
@ -0,0 +1,119 @@
|
||||
#######################
|
||||
GPIO Matrix and Pin Mux
|
||||
#######################
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This is a basic introduction to how the peripherals work in the ESP32. This tutorial can be used to understand
|
||||
how to define the peripheral usage and its corresponding pins.
|
||||
|
||||
In some microcontrollers' architecture, the peripherals are attached to specific pins and cannot be redefined to another one.
|
||||
|
||||
For example:
|
||||
|
||||
The *XYZ* MCU defines that the I2C peripheral SDA signal is the IO5 on the physical pin 10 and the SCL is on the IO6 and physical pin 11.
|
||||
|
||||
This means that, in your hardware project, you **NEED** to use these pins as the I2C and this cannot be changed due to the internal architecture.
|
||||
In this case, you must be very careful during the hardware design to not make any mistake by switching the SDA and SCL connections. Firmware will not help you if you do so.
|
||||
|
||||
GPIO Matrix and Pin Mux
|
||||
-----------------------
|
||||
|
||||
The ESP32 architecture includes the capability of configuring some peripherals to any of the GPIOs pins, managed by the `IO MUX GPIO`_.
|
||||
Essentially, this capability means that we can route the internal peripheral into a different physical pin using the IO MUX and the GPIO Matrix.
|
||||
|
||||
.. figure:: ../_static/tutorials/peripherals/tutorial_peripheral_diagram.png
|
||||
:align: center
|
||||
:width: 600
|
||||
:figclass: align-center
|
||||
|
||||
It means that in the scenario of the *XYZ* MCU, in the ESP32 we can use any of the GPIOs to route the SDA (input/output) and the SCL (output).
|
||||
|
||||
To use this functionality, we must be aware of some precautions:
|
||||
|
||||
* Some of the GPIOs are **INPUT** only.
|
||||
* Some peripherals have output signals and must be used on GPIO's capable to be configured as **OUTPUT**.
|
||||
* Some peripherals, mostly the high speed ones, ADC, DAC, Touch, and JTAG use dedicated GPIOs pins.
|
||||
|
||||
.. warning::
|
||||
Before assigning the peripheral pins in your design, double check if the pins you're using are appropriate.
|
||||
The input-only pins cannot be used for peripherals that require output or input/output signals.
|
||||
|
||||
The greatest advantage of this functionality is the fact that we don't need to be fully dependent on the physical pin, since we can change according to our needs.
|
||||
This can facilitate the hardware design routing or in some cases, fix some pin swap mistake during the hardware design phase.
|
||||
|
||||
Peripherals
|
||||
-----------
|
||||
|
||||
Here is the basic peripherals list present on the `ESP32`_. The peripheral list may vary from each ESP32 SoC family.
|
||||
To see all peripherals available on the `ESP32-S2`_ and `ESP32-C3`_, check each of the datasheets.
|
||||
|
||||
Peripheral Table
|
||||
****************
|
||||
|
||||
============================== ===================================
|
||||
Type Function
|
||||
============================== ===================================
|
||||
ADC Dedicated GPIOs
|
||||
DAC Dedicated GPIOs
|
||||
Touch Sensor Dedicated GPIOs
|
||||
JTAG Dedicated GPIOs
|
||||
SD/SDIO/MMC HostController Dedicated GPIOs
|
||||
Motor PWM Any GPIO
|
||||
SDIO/SPI SlaveController Dedicated GPIOs
|
||||
UART Any GPIO[1]
|
||||
I2C Any GPIO
|
||||
I2S Any GPIO
|
||||
LED PWM Any GPIO
|
||||
RMT Any GPIO
|
||||
GPIO Any GPIO
|
||||
Parallel QSPI Dedicated GPIOs
|
||||
EMAC Dedicated GPIOs
|
||||
Pulse Counter Any GPIO
|
||||
TWAI Any GPIO
|
||||
USB Dedicated GPIOs
|
||||
============================== ===================================
|
||||
|
||||
[1] except for the download/programming mode decided by the bootloader.
|
||||
|
||||
This table is present on each datasheet provided by Espressif.
|
||||
|
||||
Usage Examples
|
||||
--------------
|
||||
|
||||
In the Arduino Uno, we have the I2C pins defined by hardware, A4 is the SDA and A5 the SCL. In this case, we do not need to set
|
||||
these pins in the ``Wire.begin();`` function, because they are already into the Wire library.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
void setup()
|
||||
{
|
||||
Wire.begin(); // join i2c bus (address optional for master)
|
||||
}
|
||||
|
||||
Now, for the ESP32, the default pins for the I2C are SDA (GPIO21) and SCL (GPIO22). We can use a different pin as alternative for the
|
||||
default ones if you need to change the pins.
|
||||
To change the pins, we must call the ``Wire.setPins(int sda, int scl);`` function before calling ``Wire.begin();``.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
int sda_pin = 16; // GPIO16 as I2C SDA
|
||||
int scl_pin = 17; // GPIO17 as I2C SCL
|
||||
|
||||
void setup()
|
||||
{
|
||||
Wire.setPins(sda_pin, scl_pin); // Set the I2C pins before begin
|
||||
Wire.begin(); // join i2c bus (address optional for master)
|
||||
}
|
||||
|
||||
A similar approach also applies for the other peripherals.
|
||||
|
||||
.. include:: ../common/datasheet.inc
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
.. _Espressif Systems: https://www.espressif.com
|
||||
.. _Espressif Product Selector: https://products.espressif.com/
|
||||
.. _IO MUX GPIO: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#iomuxgpio
|
188
docs/source/tutorials/partition_table.rst
Normal file
188
docs/source/tutorials/partition_table.rst
Normal file
@ -0,0 +1,188 @@
|
||||
###############
|
||||
Partition Table
|
||||
###############
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Partition table is used to define the flash memory organization and the different kind of data will be stored on each partition.
|
||||
|
||||
You can use one of the available partition table scheme or create your own. You can see all the different schemes on the `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder or by the Arduino IDE tools menu `Tools -> Partition Scheme`.
|
||||
|
||||
The partition table is created by a .CSV (Comma-separeted Values) file with the following structure:
|
||||
|
||||
.. code-block::
|
||||
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
|
||||
Where:
|
||||
|
||||
1. **Name**
|
||||
|
||||
Is the partition name and must be a unique name. This name is not relevant for the system and the size must be at maximum of 16-chars (no special chars).
|
||||
|
||||
2. **Type**
|
||||
|
||||
This is the type of the partition. This value can be ``data`` or ``app``.
|
||||
|
||||
* ``app`` type is used to define the partition that will store the application.
|
||||
|
||||
* ``data`` type can be used to define the partition that stores general data, not the application.
|
||||
|
||||
3. **SubType**
|
||||
|
||||
The SubType defines the usage of the ``app`` and ``data`` partitions.
|
||||
|
||||
**data**
|
||||
|
||||
``ota``
|
||||
|
||||
The ota subtype is used to store the OTA information. This partition is used only when the OTA is used to select the initialization partition, otherwise no need to add it to your custom partition table.
|
||||
The size of this partition should be a fixed size of 8kB (0x2000 bytes).
|
||||
|
||||
``nvs``
|
||||
|
||||
The nvs partition subtype is used to define the partition to store general data, like the WiFi data, device PHY calibration data and any other data to be stored on the non-volatile memory.
|
||||
This kind of partition is suitable for small custom configuration data, cloud certificates, etc. Another usage for the NVS is to store sensitive data, since the NVS supports encryption.
|
||||
It is highly recommended to add at least one nvs partition, labeled with the name nvs, in your custom partition tables with size of at least 12kB (0x3000 bytes). If needed, you can increase the size of the nvs partition.
|
||||
The recommended size for this partition is from 12kb to 64kb. Although larger NVS partitions can be defined, we recommend using FAT or SPIFFS filesystem for storage of larger amounts of data.
|
||||
|
||||
``coredump``
|
||||
|
||||
The coredump partition subtype is used to store the core dump on the flash. The core dump is used to analyze critical errors like crash and panic.
|
||||
This function must be enabled in the project configuration menu and set the data destination to flash.
|
||||
The recommended size for this partition is 64kB (0x10000).
|
||||
|
||||
``nvs_keys``
|
||||
|
||||
The nvs_keys partition subtype is used to store the keys when the NVS encryption is used.
|
||||
The size for this partition is 4kB (0x1000).
|
||||
|
||||
``fat``
|
||||
|
||||
The fat partition subtype defines the FAT filesystem usage, and it is suitable for larger data and if this data is often updated and changed. The FAT FS can be used with wear leveling feature to increase the erase/modification cycles per memory sector and encryption for sensitive data storage, like cloud certificates or any other data that may be protected.
|
||||
To use FAT FS with wear leveling see the example.
|
||||
|
||||
``spiffs``
|
||||
|
||||
The spiffs partition subtype defines the SPI flash filesystem usage, and it is also suitable for larger files and it also performs the wear leveling and file system consistency check.
|
||||
The SPIFFS do not support flash encryption.
|
||||
|
||||
**app**
|
||||
|
||||
``factory``
|
||||
|
||||
The factory partition subtype is the default application. The bootloader will set this partition as the default application initialization if no OTA partition is found, or the OTA partitions are empty.
|
||||
If the OTA partition is used, the ota_0 can be used as the default application and the factory can be removed from the partition table to save memory space.
|
||||
|
||||
``ota_0`` to ``ota_15``
|
||||
|
||||
The ota_x partition subtype is used for the Over-the air update. The OTA feature requires at least two ota_x partition (usually ota_0 and ota_1) and it also requires the ota partition to keep the OTA information data.
|
||||
Up to 16 OTA partitions can be defined but only two are needed for basic OTA feature.
|
||||
|
||||
``test``
|
||||
|
||||
The test partition subtype is used for factory test procedures.
|
||||
|
||||
4. **Offset**
|
||||
|
||||
The offset defines the partition start address. The offset is defined by the sum of the offset and the size of the earlier partition.
|
||||
|
||||
.. note::
|
||||
Offset must be multiple of 4kB (0x1000) and for app partitions it must be aligned by 64kB (0x10000).
|
||||
If left blank, the offset will be automatically calculated based on the end of the previous partition, including any necessary alignment, however, the offset for the first partition must be always set as **0x9000** and for the first application partition **0x10000**.
|
||||
|
||||
5. **Size**
|
||||
|
||||
Size defines the amount of memory to be allocated on the partition. The size can be formatted as decimal, hex numbers (0x prefix), or using unit prefix K (kilo) or M (mega) i.e: 4096 = 4K = 0x1000.
|
||||
|
||||
6. **Flags**
|
||||
|
||||
The last column in the CSV file is the flags and it is currently used to define if the partition will be encrypted by the flash encryption feature.
|
||||
|
||||
|
||||
For example, **the most common partition** is the ``default_8MB.csv`` (see `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder for some examples):
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x330000,
|
||||
app1, app, ota_1, 0x340000,0x330000,
|
||||
spiffs, data, spiffs, 0x670000,0x190000,
|
||||
|
||||
Using a Custom Partition Scheme
|
||||
-------------------------------
|
||||
|
||||
To create your own partition table, you can create the ``partitions.csv`` file **in the same folder you created your sketch**. The build system will automatically pick the partition table file and use it instead of the predefined ones.
|
||||
|
||||
Here is an example you can use for a custom partition table:
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 2M,
|
||||
app1, app, ota_1, , 2M,
|
||||
spiffs, data, spiffs, , 8M,
|
||||
|
||||
This partition will use about 12MB of the 16MB flash. The offset will be automatically calculated after the first application partition and the units are in K and M.
|
||||
|
||||
A alternative is to create the new partition table as a new file in the `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder and edit the `boards.txt <https://github.com/espressif/arduino-esp32/tree/master/boards.txt>`_ file to add your custom partition table.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
**2MB no OTA**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
factory, app, factory, 64K, 1900K,
|
||||
|
||||
**4MB no OTA**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
factory, app, factory, 64K, 4000K,
|
||||
|
||||
**4MB with OTA**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 1900K,
|
||||
app1, app, ota_1, , 1900K,
|
||||
|
||||
**8MB no OTA with Storage**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
factory, app, factory, 64K, 2M,
|
||||
spiffs, data, spiffs, , 5M,
|
||||
|
||||
**8MB with OTA and Storage**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 2M,
|
||||
app1, app, ota_1, , 2M,
|
||||
spiffs, data, spiffs, , 3M,
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
This documentation was based on the `How to use custom partition tables on ESP32 <https://medium.com/p/69c0f3fa89c8>`_ article.
|
697
docs/source/tutorials/preferences.rst
Normal file
697
docs/source/tutorials/preferences.rst
Normal file
@ -0,0 +1,697 @@
|
||||
###########
|
||||
Preferences
|
||||
###########
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The Preferences library is unique to arduino-esp32. It should be considered as the replacement for the Arduino EEPROM library.
|
||||
|
||||
It uses a portion of the on-board non-volatile memory (NVS) of the ESP32 to store data. This data is retained across restarts and loss of power events to the system.
|
||||
|
||||
Preferences works best for storing many small values, rather than a few large values. If you need to store large amounts of data, consider using a file system library such as LitteFS.
|
||||
|
||||
The Preferences library is usable by all ESP32 variants.
|
||||
|
||||
|
||||
Preferences Attributes
|
||||
----------------------
|
||||
|
||||
Preferences data is stored in NVS in sections called a "``namespace``". Within each namespace are a set of ``key-value`` pairs. The "``key``" is the name of the data item and the "``value``" is, well, the value of that piece of data. Kind of like variables. The key is the name of the variable and the value is its value. Like variables, a ``key-value`` pair has a data type.
|
||||
|
||||
Multiple namespaces are permitted within NVS. The name of each namespace must be unique. The keys within that namespace are unique to that namespace. Meaning the same key name can be used in multiple namespaces without conflict.
|
||||
|
||||
Namespace and key names are case sensitive.
|
||||
|
||||
Each key name must be unique within a namespace.
|
||||
|
||||
Namespace and key names are character strings and are limited to a maximum of 15 characters.
|
||||
|
||||
Only one namespace can be open (in use) at a time.
|
||||
|
||||
|
||||
Library Overview
|
||||
----------------
|
||||
|
||||
Library methods are provided to:
|
||||
- create a namespace;
|
||||
- open and close a namespace;
|
||||
- store and retrieve data within a namespace for supported data types;
|
||||
- determine if a key value has been initialized;
|
||||
- delete a ``key-value`` pair;
|
||||
- delete all ``key-value`` pairs in a namespace;
|
||||
- determine data types stored against a key;
|
||||
- determine the number of key entries available in the namespace.
|
||||
|
||||
Preferences directly suports the following data types:
|
||||
|
||||
.. table:: **Table 1 — Preferences Types**
|
||||
:align: center
|
||||
|
||||
+-------------------+-------------------+---------------+
|
||||
| Preferences Type | Data Type | Size (bytes) |
|
||||
+===================+===================+===============+
|
||||
| Bool | bool | 1 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Char | int8_t | 1 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| UChar | uint8_t | 1 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Short | int16_t | 2 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| UShort | uint16_t | 2 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Int | int32_t | 4 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| UInt | uint32_t | 4 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Long | int32_t | 4 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| ULong | uint32_t | 4 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Long64 | int64_t | 8 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| ULong64 | uint64_t | 8 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Float | float_t | 8 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Double | double_t | 8 |
|
||||
+-------------------+-------------------+---------------+
|
||||
| | const char* | |
|
||||
| String +-------------------+ variable |
|
||||
| | String | |
|
||||
+-------------------+-------------------+---------------+
|
||||
| Bytes | uint8_t | variable |
|
||||
+-------------------+-------------------+---------------+
|
||||
|
||||
String values can be stored and retrieved either as an Arduino String or as a null terminated ``char`` array (C-string).
|
||||
|
||||
Bytes type is used for storing and retrieving an arbitrary number of bytes in a namespace.
|
||||
|
||||
|
||||
Workflow
|
||||
--------
|
||||
|
||||
Preferences workflow, once everything is initialized, is pretty simple.
|
||||
|
||||
To store a value:
|
||||
- Open the namespace in read-write mode.
|
||||
- Put the value into the key.
|
||||
- Close the namespace.
|
||||
|
||||
To retrieve a value:
|
||||
- Open the namespace in read-only mode.
|
||||
- Use the key to get the value.
|
||||
- Close the namespace.
|
||||
|
||||
*(Technically, you can retrieve a value if the namespace is open in either read-only or read-write mode but it's good practice to open the namespace in read-only mode if you are only retrieving values.)*
|
||||
|
||||
When storing information, a "``put[PreferencesType]``" method referenced to its key is used.
|
||||
|
||||
When retrieving information a "``get[PreferencesType]``" method referenced to its key is used.
|
||||
|
||||
Ensuring that the data types of your “``get``'s” and “``put``'s” all match, you’re good to go.
|
||||
|
||||
The nuance is in initializing everything at the start.
|
||||
|
||||
Before you can store or retrieve anything using Preferences, both the namespace and the key within that namespace need to exist. So the workflow is:
|
||||
|
||||
#. Create or open the namespace.
|
||||
#. Test for the existence of a key that should exist if the namespace has been initialized.
|
||||
#. If that key does not exist, create the key(s).
|
||||
#. Carry on with the rest of your sketch where data can now be stored and retrieved from the namespace.
|
||||
|
||||
Each step is discussed below.
|
||||
|
||||
.. note::
|
||||
|
||||
From here on when referring in general to a method used to store or retrieve data we'll use the shorthand "``putX``" and "``getX``" where the "``X``" is understood to be a Preferences Type; Bool, UInt, Char, and so on from the Preferences Types table above.
|
||||
|
||||
..
|
||||
|
||||
|
||||
Create or Open the Namespace
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In your sketch, first insert a declaration of a ``Preferences`` object by including a line like;
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
Preferences mySketchPrefs; // "mySketchPrefs" is the name of the Preferences object.
|
||||
// Can be whatever you want.
|
||||
|
||||
This object is used with the Preferences methods to access the namespace and the key-value pairs it contains.
|
||||
|
||||
A namespace is made available for use with the ``.begin`` method:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
mySketchPrefs.begin("myPrefs", false)
|
||||
|
||||
If the namespace does not yet exist, this will create and then open the namespace ``myPrefs``.
|
||||
|
||||
If the namespace already exists, this will open the namespace ``myPrefs``.
|
||||
|
||||
If the second argument is ``false`` the namespace is opened in read-write (RW) mode — values can be stored in to and retrieved from the namespace. If it is ``true`` the namespace is opened in read-only (RO) mode — values can be retrieved from the namespace but nothing can be stored.
|
||||
|
||||
|
||||
Test for Initial Existence of Your Key(s)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When the ESP32 boots, there is no inherent way to know if this is the very first time it has ever powered on or if it is a subsequent launch and it has run its sketch before. We can use Preferences to store information that is retained across reboots that we can read, and based on that, decide if this is a first-time run and take the required actions if so.
|
||||
|
||||
We do this by testing for the existence of a certain key within a namespace. If that key exists, it is safe to assume the key was created during the first-time run of the sketch and so the namespace has already been initialized.
|
||||
|
||||
To determine if a key exists, use:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
isKey("myTestKey")
|
||||
|
||||
This returns ``true`` if ``"myTestKey"`` exists in the namespace, and ``false`` if it does not.
|
||||
|
||||
By example, consider this code segment:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
Preferences mySketchPrefs;
|
||||
String doesExist;
|
||||
|
||||
mySketchPrefs.begin("myPrefs", false); // open (or create and then open if it does not
|
||||
// yet exist) the namespace "myPrefs" in RW mode.
|
||||
|
||||
bool doesExist = mySketchPrefs.isKey("myTestKey");
|
||||
|
||||
if (doesExist == false) {
|
||||
/*
|
||||
If doesExist is false, we will need to create our
|
||||
namespace key(s) and store a value into them.
|
||||
*/
|
||||
|
||||
// Insert your "first time run" code to create your keys & assign their values below here.
|
||||
}
|
||||
else {
|
||||
/*
|
||||
If doesExist is true, the key(s) we need have been created before
|
||||
and so we can access their values as needed during startup.
|
||||
*/
|
||||
|
||||
// Insert your "we've been here before" startup code below here.
|
||||
}
|
||||
|
||||
|
||||
|
||||
Creating Namespace Keys and Storing Values
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To create a key, we use one of the ``.putX`` methods, matching ``"X"`` to the Preferences Type of the data we wish to store:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
myPreferences.putX("myKeyName", value)
|
||||
|
||||
If ``"myKeyName"`` does not exist in the namespace, it is first created and then ``value`` is stored against that keyname. The namespace must be open in RW mode to do this. Note that ``value`` is not optional and must be provided with every "``.putX``" statement. Thus every key within a namespace will always hold a valid value.
|
||||
|
||||
An example is:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
myPreferences.putFloat("pi", 3.14159265359); // stores an float_t data type
|
||||
// against the key "pi".
|
||||
|
||||
Reading Values From a Namespace
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once a key exists in a namespace and the namespace is open, its value is retrieved using one of the ``getX`` methods, matching ``"X"`` to the type of data stored against that key.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
myPreferences.getX("myKeyName")
|
||||
|
||||
Like so:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
String myString = myPreferences.getString("myStringKey");
|
||||
|
||||
This will retrieve the String value from the namespace key ``"myStringKey"`` and assign it to the String type variable ``myString``.
|
||||
|
||||
|
||||
Summary
|
||||
~~~~~~~
|
||||
|
||||
So the basics of using Preferences are:
|
||||
|
||||
#. You cannot store into or retrieve from a ``key-value`` pair until a namespace is created and opened and the key exists in that namespace.
|
||||
|
||||
#. If the key already exists, it was created the first time the sketch was run.
|
||||
|
||||
#. A key value can be retrieved regardless of the mode in which the namespace was opened, but a value can only be stored if the namespace is open in read-write mode.
|
||||
|
||||
#. Data types of the “``get``'s” and “``put``'s” must match.
|
||||
|
||||
#. Remember the 15 character limit for namespace and key names.
|
||||
|
||||
|
||||
Real World Example
|
||||
------------------
|
||||
|
||||
Here is part of a ``setup()`` function that uses Preferences.
|
||||
|
||||
Its purpose is to set either a factory default configuration if the system has never run before, or use the last configuration if it has.
|
||||
|
||||
When started, the system has no way of knowing which of the above conditions is true. So the first thing it does after opening the namespace is check for the existence of a key that we have predetermined can only exist if we have previously run the sketch. Based on its existence we decide if a factory default set of operating parameters should be used (and in so doing create the namespace keys and populate the values with defaults) or if we should use operating parameters from the last time the system was running.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
#include <Preferences.h>
|
||||
|
||||
#define RW_MODE false
|
||||
#define RO_MODE true
|
||||
|
||||
Preferences stcPrefs;
|
||||
|
||||
void setup() {
|
||||
|
||||
// not the complete setup(), but in setup(), include this...
|
||||
|
||||
stcPrefs.begin("STCPrefs", RO_MODE); // Open our namespace (or create it
|
||||
// if it doesn't exist) in in RO mode.
|
||||
|
||||
bool tpInit = stcPrefs.isKey("nvsInit"); // Test for the existence of the "already initialized" key.
|
||||
|
||||
if (tpInit == false) {
|
||||
// If tpInit is 'false', the key "nvsInit" does not yet exist therefore this
|
||||
// must be our first-time run. We need to set up our Preferences namespace keys. So...
|
||||
stcPrefs.end(); // close the namespace in RO mode and...
|
||||
stcPrefs.begin("STCPrefs", RW_MODE); // reopen it in RW mode.
|
||||
|
||||
|
||||
// The .begin() method created the "STCPrefs" namespace and since this is our
|
||||
// first-time run we will create our keys and store the initial "factory default" values.
|
||||
stcPrefs.putUChar("curBright", 10);
|
||||
stcPrefs.putString("talChan", "one");
|
||||
stcPrefs.putLong("talMax", -220226);
|
||||
stcPrefs.putBool("ctMde", true);
|
||||
|
||||
stcPrefs.putBool("nvsInit", true); // Create the "already initialized" key and store a value.
|
||||
|
||||
// The "factory defaults" are created and stored so...
|
||||
stcPrefs.end(); // Close the namespace in RW mode and...
|
||||
stcPrefs.begin("STCPrefs", RO_MODE); // reopen it in RO mode so the setup code
|
||||
// outside this first-time run 'if' block
|
||||
// can retrieve the run-time values
|
||||
// from the "STCPrefs" namespace.
|
||||
}
|
||||
|
||||
// Retrieve the operational parameters from the namespace
|
||||
// and save them into their run-time variables.
|
||||
currentBrightness = stcPrefs.getUChar("curBright"); //
|
||||
tChannel = stcPrefs.getString("talChan"); // The LHS variables were defined
|
||||
tChanMax = stcPrefs.getLong("talMax"); // earlier in the sketch.
|
||||
ctMode = stcPrefs.getBool("ctMde"); //
|
||||
|
||||
// All done. Last run state (or the factory default) is now restored.
|
||||
stcPrefs.end(); // Close our preferences namespace.
|
||||
|
||||
// Carry on with the rest of your setup code...
|
||||
|
||||
// When the sketch is running, it updates any changes to an operational parameter
|
||||
// to the appropriate key-value pair in the namespace.
|
||||
|
||||
}
|
||||
|
||||
|
||||
Utility Functions
|
||||
-----------------
|
||||
|
||||
There are a few other functions useful when working with namespaces.
|
||||
|
||||
Deleting key-value Pairs
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
preferences.clear();
|
||||
|
||||
..
|
||||
|
||||
- Deletes *all* the key-value pairs in the currently opened namespace.
|
||||
|
||||
- The namespace still exists.
|
||||
|
||||
- The namespace must be open in read-write mode for this to work.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
preferences.remove("keyname");
|
||||
|
||||
..
|
||||
|
||||
- Deletes the "keyname" and value associated with it from the currently opened namespace.
|
||||
|
||||
- The namespace must be open in read-write mode for this to work.
|
||||
- Tip: use this to remove the "test key" to force a "factory reset" during the next reboot (see the *Real World Example* above).
|
||||
|
||||
If either of the above are used, the ``key-value`` pair will need to be recreated before using it again.
|
||||
|
||||
|
||||
Determining the Number of Available Keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For each namespace, Preferences keeps track of the keys in a key table. There must be an open entry in the table before a key can be created. This method will return the number of entires available in the table.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
freeEntries()
|
||||
|
||||
..
|
||||
|
||||
To send to the serial monitor the number of available entries the following could be used.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
Preferences mySketchPrefs;
|
||||
|
||||
mySketchPrefs.begin("myPrefs", true);
|
||||
size_t whatsLeft = freeEntries(); // this method works regardless of the mode in which the namespace is opened.
|
||||
Serial.printf("There are: %u entries available in the namespace table.\n, whatsLeft);
|
||||
mySketchPrefs.end();
|
||||
|
||||
..
|
||||
|
||||
The number of available entries in the key table changes depending on the number of keys in the namespace and also the dynamic size of certain types of data stored in the namespace. Details are in the `Preferences API Reference`_.
|
||||
|
||||
Do note that the number of entries in the key table does not guarantee that there is room in the opened NVS namespace for all the data to be stored in that namespace. Refer to the espressif `Non-volatile storage library`_ documentation for full details.
|
||||
|
||||
|
||||
Determining the Type of a key-value Pair
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Keeping track of the data types stored against a key-value pair is one of the bookkeeping tasks left to you. Should you want to discover the Preferences data type stored against a given key, use this method:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
getType("myKey")
|
||||
|
||||
..
|
||||
|
||||
As in:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
PreferenceType whatType = getType("myKey");
|
||||
|
||||
..
|
||||
|
||||
The value returned is a ``PreferenceType`` value that maps to a Preferences Type. Refer to the description in the `Preferences API Reference`_ for details.
|
||||
|
||||
|
||||
|
||||
Working with Large Data
|
||||
-----------------------
|
||||
|
||||
Recall that the Preferences library works best for storing many small values, rather than a few large values. Regardless, it may be desirable to store larger amounts of arbitrary data than what is provided by the basic types in the Preferences Types table above.
|
||||
|
||||
The library provides the following methods to facilitate this.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
putBytes("myBytesKey", value, valueLen)
|
||||
getBytes("myBytesKey", buffer, valueLen)
|
||||
getBytesLength("myBytesKey")
|
||||
|
||||
..
|
||||
|
||||
The ``put`` and ``get`` ``Bytes`` methods store and retrieve the data. The ``getBytesLength`` method is used to find the size of the data stored against the key (which is needed to retrieve ``Bytes`` data).
|
||||
|
||||
As the names of the methods imply, they operate on variable length bytes of data (often referred to as a "blob") and not on individual elements of a certain data type.
|
||||
|
||||
Meaning if you store for example an array of type ``int16_t`` against a ``Bytes`` type key, the value of that key becomes a series of bytes with no associated data type. Or if you like, all data stored as a blob gets converted to a series of ``uint8_t`` type bytes.
|
||||
|
||||
As a result, when using the ``getBytes`` method to retrieve the value of the key, what is returned to the buffer is a series of ``uint8_t`` bytes. It is up to you to manage the data types and size of the arrays and buffers when retrieving ``Bytes`` data.
|
||||
|
||||
Fortunately this is not as difficult as it may sound as the ``getBytesLength`` method and the ``sizeof`` operator help with keeping track of it all.
|
||||
|
||||
This is best explained with an example. Here the ``Bytes`` methods are used to store and retrieve an array, while ensuring the data type is preserved.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
/*
|
||||
* An example sketch using the Preferences "Bytes" methods
|
||||
* to store and retrieve an arbitrary number of bytes in
|
||||
* a namespace.
|
||||
*/
|
||||
|
||||
#include <Preferences.h>
|
||||
|
||||
#define RO_MODE true
|
||||
#define RW_MODE false
|
||||
|
||||
void setup() {
|
||||
|
||||
Preferences mySketchPrefs;
|
||||
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
|
||||
mySketchPrefs.begin("myPrefs", RW_MODE); // open (or create) the namespace "myPrefs" in RW mode
|
||||
mySketchPrefs.clear(); // delete any previous keys in this namespace
|
||||
|
||||
// Create an array of test values. We're using hex numbers throughout to better show how the bytes move around.
|
||||
int16_t myArray[] = { 0x1112, 0x2122, 0x3132, 0x4142, 0x5152, 0x6162, 0x7172 };
|
||||
|
||||
Serial.println("Printing myArray...");
|
||||
for (int i = 0; i < sizeof(myArray) / sizeof(int16_t); i++) {
|
||||
Serial.print(myArray[i], HEX); Serial.print(", ");
|
||||
}
|
||||
Serial.println("\r\n");
|
||||
|
||||
// In the next statement, the second sizeof() needs to match the data type of the elements of myArray
|
||||
Serial.print("The number of elements in myArray is: "); Serial.println( sizeof(myArray) / sizeof(int16_t) );
|
||||
Serial.print("But the size of myArray in bytes is: "); Serial.println( sizeof(myArray) );
|
||||
Serial.println("");
|
||||
|
||||
Serial.println("Storing myArray into the Preferences namespace \"myPrefs\" against the key \"myPrefsBytes\".");
|
||||
// Note: in the next statement, to store the entire array, we must use the
|
||||
// size of the arrray in bytes, not the number of elements in the array.
|
||||
mySketchPrefs.putBytes( "myPrefsBytes", myArray, sizeof(myArray) );
|
||||
Serial.print("The size of \"myPrefsBytes\" is (in bytes): "); Serial.println( mySketchPrefs.getBytesLength("myPrefsBytes") );
|
||||
Serial.println("");
|
||||
|
||||
int16_t myIntBuffer[20] = {}; // No magic about 20. Just making a buffer (array) big enough.
|
||||
Serial.println("Retrieving the value of myPrefsBytes into myIntBuffer.");
|
||||
Serial.println(" - Note the data type of myIntBuffer matches that of myArray");
|
||||
mySketchPrefs.getBytes( "myPrefsBytes", myIntBuffer, mySketchPrefs.getBytesLength("myPrefsBytes") );
|
||||
|
||||
Serial.println("Printing myIntBuffer...");
|
||||
// In the next statement, sizeof() needs to match the data type of the elements of myArray
|
||||
for (int i = 0; i < mySketchPrefs.getBytesLength("myPrefsBytes") / sizeof(int16_t); i++) {
|
||||
Serial.print(myIntBuffer[i], HEX); Serial.print(", ");
|
||||
}
|
||||
Serial.println("\r\n");
|
||||
|
||||
Serial.println("We can see how the data from myArray is actually stored in the namespace as follows.");
|
||||
uint8_t myByteBuffer[40] = {}; // No magic about 40. Just making a buffer (array) big enough.
|
||||
mySketchPrefs.getBytes( "myPrefsBytes", myByteBuffer, mySketchPrefs.getBytesLength("myPrefsBytes") );
|
||||
|
||||
Serial.println("Printing myByteBuffer...");
|
||||
for (int i = 0; i < mySketchPrefs.getBytesLength("myPrefsBytes"); i++) {
|
||||
Serial.print(myByteBuffer[i], HEX); Serial.print(", ");
|
||||
}
|
||||
Serial.println("");
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
;
|
||||
}
|
||||
|
||||
..
|
||||
|
||||
The resulting output is:
|
||||
::
|
||||
|
||||
Printing myArray...
|
||||
1112, 2122, 3132, 4142, 5152, 6162, 7172,
|
||||
|
||||
The number of elements in myArray is: 7
|
||||
But the size of myArray in bytes is: 14
|
||||
|
||||
Storing myArray into the Preferences namespace "myPrefs" against the key "myPrefsBytes".
|
||||
The size of "myPrefsBytes" is (in bytes): 14
|
||||
|
||||
Retrieving the value of myPrefsBytes into myIntBuffer.
|
||||
- Note the data type of myIntBuffer matches that of myArray
|
||||
Printing myIntBuffer...
|
||||
1112, 2122, 3132, 4142, 5152, 6162, 7172,
|
||||
|
||||
We can see how the data from myArray is actually stored in the namespace as follows.
|
||||
Printing myByteBuffer...
|
||||
12, 11, 22, 21, 32, 31, 42, 41, 52, 51, 62, 61, 72, 71,
|
||||
|
||||
You can copy the sketch and change the data type and values in ``myArray`` and follow along with the code and output to see how the ``Bytes`` methods work. The data type of ``myIntBuffer`` should be changed to match that of ``myArray`` (and check the "``sizeof()``'s" where indicated in the comments).
|
||||
|
||||
The main takeaway is to remember you're working with bytes and so attention needs to be paid to store all the data based on the size of its type and to manage the buffer size and data type for the value retrieved.
|
||||
|
||||
|
||||
Multiple Namespaces
|
||||
-------------------
|
||||
|
||||
As stated earlier, multiple namespaces can exist in the Preferences NVS partition. However, only one namespace at a time can be open (in use).
|
||||
|
||||
If you need to access a different namespace, close the one before opening the other. For example:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
Preferences currentNamespace;
|
||||
|
||||
currentNamespace.begin("myNamespace", false);
|
||||
// do stuff...
|
||||
|
||||
currentNamespace.end(); // closes 'myNamespace'
|
||||
|
||||
currentNamespace.begin("myOtherNamespace", false); // opens a different Preferences namesspace.
|
||||
// do other stuff...
|
||||
|
||||
currentNamespace.end(); // closes 'myOtherNamespace'
|
||||
|
||||
Here the "``currentNamespace``" object is reused, but different Preferences objects can be declared and used. Just remember to keep it all straight as all "``putX``'s" and "``getX``'s", etc. will only operate on the single currently opened namespace.
|
||||
|
||||
|
||||
A Closer Look at ``getX``
|
||||
--------------------------
|
||||
|
||||
Methods in the Preferences library return a status code that can be used to determine if the method completed successfully. This is described in the `Preferences API Reference`_.
|
||||
|
||||
Assume we have a key named "``favourites``" that contains a value of a ``String`` data type.
|
||||
|
||||
After executing the statement:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
dessert = mySketchPrefs.getString("favourites");
|
||||
|
||||
..
|
||||
|
||||
the variable ``dessert`` will contain the value of the string stored against the key ``"favourites"``.
|
||||
|
||||
But what if something went wrong and the ``getString`` call failed to retrieve the key value? How would we be able to detect the error?
|
||||
|
||||
With Preferences, the ``getX`` methods listed in Table 2 below will return a default value if an error is encountered.
|
||||
|
||||
.. table:: **Table 2 — getX Methods Defaults**
|
||||
:align: center
|
||||
|
||||
+------------------+-----------------+
|
||||
| Preferences | Default Return |
|
||||
| Type | Value |
|
||||
+==================+=================+
|
||||
| Char, UChar, | 0 |
|
||||
| | |
|
||||
| Short, UShort, | |
|
||||
| | |
|
||||
| Int, UInt, | |
|
||||
| | |
|
||||
| Long, ULong, | |
|
||||
| | |
|
||||
| Long64, ULong64 | |
|
||||
+------------------+-----------------+
|
||||
| Bool | false |
|
||||
+------------------+-----------------+
|
||||
| Float | NAN |
|
||||
| | |
|
||||
| Double | |
|
||||
+------------------+-----------------+
|
||||
| String (String) | "" |
|
||||
+------------------+-----------------+
|
||||
| String (* buf) | \\0 |
|
||||
+------------------+-----------------+
|
||||
|
||||
Thus to detect an error we could compare the value returned against its default return value and if they are equal assume an error occurred and take the appropriate action.
|
||||
|
||||
But what if a method default return value is also a potential legitimate value? How can we then know if an error occurred?
|
||||
|
||||
As it turns out, the complete form of the ``getX`` methods for each of the Preferences Types in Table 2 is:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
preferences.getX("myKey", myDefault)
|
||||
|
||||
..
|
||||
|
||||
In this form the method will return either the value associated with "``myKey``" or, if an error occurred, return the value ``myDefault``, where ``myDefault`` must be the same data type as the ``getX``.
|
||||
|
||||
Returning to the example above:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
dessert = mySketchPrefs.getString("favourites", "gravel");
|
||||
|
||||
..
|
||||
|
||||
will assign to the variable ``dessert`` the String ``gravel`` if an error occurred, or the value stored against the key ``favourites`` if not.
|
||||
|
||||
If we predetermine a default value that is outside all legitimate values, we now have a way to test if an error actually occurred.
|
||||
|
||||
In summary, if you need to confirm that a value was retrieved without error from a namespace, use the complete form of the ``getX`` method with a predetermined default "this can only happen if an error" value and compare that against the value returned by the call. Otherwise, you can omit the default value as the call will return the default for that particular ``getX`` method.
|
||||
|
||||
Additional detail is given in the `Preferences API Reference`_.
|
||||
|
||||
|
||||
Advanced Item
|
||||
-------------
|
||||
|
||||
In the arduino-esp32 implementation of Preferences there is no method to completely remove a namespace. As a result, over the course of a number of projects, it is possible that the ESP32 NVS Preferences partition becomes cluttered or full.
|
||||
|
||||
To completely erase and reformat the NVS memory used by Preferences, create and run a sketch that contains:
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
#include <nvs_flash.h>
|
||||
|
||||
void setup() {
|
||||
|
||||
nvs_flash_erase(); // erase the NVS partition and...
|
||||
nvs_flash_init(); // initialize the NVS partition.
|
||||
while (true);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
;
|
||||
}
|
||||
|
||||
..
|
||||
|
||||
.. warning::
|
||||
**You should download a new sketch to your board immediately after running the above or else it will reformat the NVS partition every time it is powered up or restarted!**
|
||||
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* `Preferences API Reference <../api/preferences.html>`_
|
||||
* `Non-volatile storage library`_ (espressif-IDF API Reference)
|
||||
* `Official ESP-IDF documentation`_ (espressif-IDF Reference)
|
||||
|
||||
|
||||
.. _Non-volatile storage library: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html
|
||||
.. _Official ESP-IDF documentation: https://docs.espressif.com/projects/esp-idf/en/stable
|
||||
|
||||
|
||||
Contribute
|
||||
----------
|
||||
|
||||
.. ==*Do not change! Keep as is.*==
|
||||
|
||||
To contribute to this project, see `How to contribute`_.
|
||||
|
||||
If you have any **feedback** or **issue** to report on this tutorial, please open an issue or fix it by creating a new PR. Contributions are more than welcome!
|
||||
|
||||
Before creating a new issue, be sure to try the Troubleshooting and to check if the same issue was already created by someone else.
|
||||
|
||||
.. _How to Contribute: https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst
|
||||
|
||||
.. ---- EOF ----
|
10
docs/source/tutorials/tutorials.rst
Normal file
10
docs/source/tutorials/tutorials.rst
Normal file
@ -0,0 +1,10 @@
|
||||
#########
|
||||
Tutorials
|
||||
#########
|
||||
|
||||
.. toctree::
|
||||
:caption: Tutorials:
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
*
|
Reference in New Issue
Block a user