Merge pull request #9426 from gschorcht/esp32

ESP32 port
This commit is contained in:
Kevin "Bear Puncher" Weiss 2018-10-16 15:24:25 +02:00 committed by GitHub
commit 7187bbf8cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
310 changed files with 69311 additions and 2 deletions

View File

@ -0,0 +1,3 @@
MODULE = boards_common_esp32
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,5 @@
include $(RIOTCPU)/esp32/Makefile.dep
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
endif

View File

@ -0,0 +1,12 @@
# most board features results directly from ESP32 CPU features
include $(RIOTCPU)/esp32/Makefile.features
# additional features provided by all boards are GPIOs and at least one UART
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_gpio_irq
FEATURES_PROVIDED += periph_uart
# other features provided by all boards
FEATURES_PROVIDED += esp_spiffs
FEATURES_PROVIDED += esp_wifi
FEATURES_PROVIDED += esp_now

View File

@ -0,0 +1,11 @@
# the cpu to build for
export CPU ?= esp32
export CPU_MODEL ?= esp32
# configure the serial interface
PORT_LINUX ?= /dev/ttyUSB0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*)))
include $(RIOTMAKE)/tools/serial.inc.mk
# reset tool configuration
export RESET = esptool.py --before default_reset run

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_common_esp32 ESP32 Board Commons
* @ingroup boards_common
* @brief Common definitions for all ESP32 boards
* @{
*
* @file
* @brief Common declarations and functions for all ESP32 boards.
*
* This file contains default declarations and functions that are valid
* for all ESP32 boards.
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#include "board.h"
#include "esp_common.h"
#include "log.h"
#include "periph/gpio.h"
#include "periph/spi.h"
#include "rom/ets_sys.h"
#ifdef __cplusplus
extern "C" {
#endif
void board_init(void)
{
#ifdef LED0_PIN
gpio_init (LED0_PIN, GPIO_OUT);
LED0_OFF;
#endif
#ifdef LED1_PIN
gpio_init (LED1_PIN, GPIO_OUT);
LED1_OFF;
#endif
#ifdef LED2_PIN
gpio_init (LED2_PIN, GPIO_OUT);
LED2_OFF;
#endif
}
extern void adc_print_config(void);
extern void pwm_print_config(void);
extern void i2c_print_config(void);
extern void spi_print_config(void);
extern void uart_print_config(void);
extern void can_print_config(void);
void print_board_config (void)
{
ets_printf("\nBoard configuration:\n");
adc_print_config();
pwm_print_config();
i2c_print_config();
spi_print_config();
uart_print_config();
#ifdef MODULE_ESP_CAN
can_print_config();
#endif
ets_printf("\tLED\t\tpins=[ ");
#ifdef LED0_PIN
ets_printf("%d ", LED0_PIN);
#endif
#ifdef LED1_PIN
ets_printf("%d ", LED1_PIN);
#endif
#ifdef LED2_PIN
ets_printf("%d ", LED2_PIN);
#endif
ets_printf("]\n");
ets_printf("\tBUTTONS\t\tpins=[ ");
#ifdef BUTTON0_PIN
ets_printf("%d ", BUTTON0_PIN);
#endif
#ifdef BUTTON2_PIN
ets_printf("%d ", BUTTON1_PIN);
#endif
#ifdef BUTTON3_PIN
ets_printf("%d ", BUTTON2_PIN);
#endif
ets_printf("]\n");
ets_printf("\n");
}
#ifdef __cplusplus
} /* end extern "C" */
#endif
/** @} */

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_common_esp32 ESP32 Common
* @ingroup boards_common
* @ingroup boards_esp32
* @brief Definitions and configurations that are common for
* all ESP32 boards.
*
* For detailed information about the ESP32, configuring and compiling RIOT
* for ESP32 boards, please refer \ref esp32_riot.
*/
/**
* @defgroup boards_esp32 ESP32 Boards
* @ingroup boards
* @brief This group of boards contains the documentation
* defined ESP32 boards.
*
* @note For detailed information about the ESP32 SoC, the tool chain
* as well as configuring and compiling RIOT for ESP32 boards,
* see \ref esp32_riot.
*/

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_common_esp32
* @{
*
* @file
* @brief Common board for the Arduino API
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_BOARD_COMMON_H
#define ARDUINO_BOARD_COMMON_H
#include "arduino_pinmap.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Look-up table for the Arduino's digital pins
*/
static const gpio_t arduino_pinmap[] = {
ARDUINO_PIN_0,
ARDUINO_PIN_1,
ARDUINO_PIN_2,
ARDUINO_PIN_3,
ARDUINO_PIN_4,
ARDUINO_PIN_5,
ARDUINO_PIN_6,
ARDUINO_PIN_7,
ARDUINO_PIN_8,
ARDUINO_PIN_9,
ARDUINO_PIN_10,
ARDUINO_PIN_11,
ARDUINO_PIN_12,
ARDUINO_PIN_13,
ARDUINO_PIN_A0,
ARDUINO_PIN_A1,
ARDUINO_PIN_A2,
ARDUINO_PIN_A3,
ARDUINO_PIN_A4,
ARDUINO_PIN_A5
};
/**
* @brief Look-up table for the Arduino's analog pins
*/
static const adc_t arduino_analog_map[] = {
ARDUINO_PIN_A0,
ARDUINO_PIN_A1,
ARDUINO_PIN_A2,
ARDUINO_PIN_A3,
ARDUINO_PIN_A4,
ARDUINO_PIN_A5
};
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_BOARD_COMMON_H */
/** @} */

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_common_esp32
* @brief Board definitions that are common for all ESP32 boards.
*
* This file contains board configurations that are valid for all ESP32.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#ifndef BOARD_COMMON_H
#define BOARD_COMMON_H
#include <stdint.h>
#include "cpu.h"
#include "periph_conf.h"
#include "arduino_pinmap.h"
#include "periph/gpio.h"
#include "sdk_conf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name LED configuration (three predefined LEDs at maximum)
*
* @note LEDx_ACTIVE value must be declared in board configuration.
* @{
*/
#if defined(LED0_PIN) || DOXYGEN
#define LED0_MASK (BIT(LED0_PIN))
#define LED0_ON (gpio_write(LED0_PIN, LED0_ACTIVE))
#define LED0_OFF (gpio_write(LED0_PIN, !LED0_ACTIVE))
#define LED0_TOGGLE (gpio_toggle(LED0_PIN))
#endif
#if defined(LED1_PIN) || DOXYGEN
#define LED1_MASK (BIT(LED1_PIN))
#define LED1_ON (gpio_write(LED1_PIN, LED1_ACTIVE))
#define LED1_OFF (gpio_write(LED1_PIN, !LED1_ACTIVE))
#define LED1_TOGGLE (gpio_toggle(LED1_PIN))
#endif
#if defined(LED2_PIN) || DOXYGEN
#define LED2_MASK (BIT(LED2_PIN))
#define LED2_ON (gpio_write(LED2_PIN, LED2_ACTIVE))
#define LED2_OFF (gpio_write(LED2_PIN, !LED2_ACTIVE))
#define LED2_TOGGLE (gpio_toggle(LED2_PIN))
#endif
/** @} */
/**
* @name STDIO configuration
* @{
*/
/**< Default baudrate of UART for stdio */
#ifndef STDIO_UART_BAUDRATE
#define STDIO_UART_BAUDRATE (115200)
#endif
/** @} */
#if MODULE_MTD || DOXYGEN
/**
* @name MTD system drive configuration
*
* Built-in SPI flash memory is used as MTD system drive.
* @{
*/
#include "mtd.h"
/**
* @brief MTD drive start address in SPI flash memory
*
* Defines the start adress of the MTD system device in the SPI
* flash memory. It can be overridden by \ref esp32_app_spec_conf
* "application-specific board configuration"
*
* If the MTD start address is not defined or is 0, the first possible
* multiple of 0x100000 (1 MByte) is used in free SPI flash memory,
* which was determined from the partition table.
*/
#ifndef SPI_FLASH_DRIVE_START
#define SPI_FLASH_DRIVE_START 0
#endif
/** Default MTD drive definition */
#define MTD_0 mtd0
/** Pointer to the default MTD drive structure */
extern mtd_dev_t *mtd0;
/** @} */
#endif /* MODULE_MTD || DOXYGEN */
#if MODULE_SPIFFS || DOXYGEN
/**
* @name SPIFFS configuration for the system MTD device
*
* Configuration of the SPIFFS that can be used on the system MTD device.
* @{
*/
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
#define SPIFFS_READ_ONLY 0
#define SPIFFS_SINGLETON 0
#define SPIFFS_HAL_CALLBACK_EXTRA 1
#define SPIFFS_CACHE 1
/** @} */
#endif /* MODULE_SPIFFS || DOXYGEN */
/**
* @brief Initialize board specific hardware
*
* Since all features of ESP32 boards are provided by the SOC, almost all
* initializations are done during the CPU initialization that is called from
* boot loader.
*/
void board_init (void);
/**
* @brief Print the board configuration in a human readable format
*/
void print_board_config (void);
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* BOARD_COMMON_H */
/** @} */

View File

@ -0,0 +1,164 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_common_esp32
* @brief Common declarations of ESP32 periphery for all ESP32 boards
*
* This file contains peripheral configurations that are valid for all ESP32.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#ifndef PERIPH_CONF_COMMON_H
#define PERIPH_CONF_COMMON_H
/* include periph_cpu.h to make it visible in any case */
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ADC configuration
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as ADC channels
*
* ADC_GPIOS is defined in board-specific peripheral configuration. Since
* ADC_GPIOS must be defined even if there are no ADC channels, an empty
* list definition is done here as fallback configuration.
*/
#ifndef ADC_GPIOS
#define ADC_GPIOS { }
#endif
/**
* @brief Number of GPIOs declared as ADC channels
*
* The number of GPIOs that are declared as ADC channels is determined from
* the ADC_GPIOS definition.
*
* @note ADC_NUMOF definition must not be changed.
*/
#define ADC_NUMOF (adc_chn_num)
/** @} */
/**
* @name DAC configuration
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as DAC channels
*
* DAC_GPIOS is defined in board-specific peripheral configuration. Since
* DAC_GPIOS must be defined even if there are no DAC channels, an empty
* list definition is done here as fallback configuration.
*/
#ifndef DAC_GPIOS
#define DAC_GPIOS { }
#endif
/**
* @brief Number of GPIOs declared as DAC channels
*
* The number of GPIOs that are declared as DAC channels is determined from
* the DAC_GPIOS definition.
*
* @note DAC_NUMOF definition must not be changed.
*/
#define DAC_NUMOF (dac_chn_num)
/** @} */
/**
* @name I2C configuration
* @{
*/
/**
* @brief Number of I2C interfaces
*
* The number of I2C interfaces is determined from board-specific peripheral
* definitions of I2Cn_SPEED, I2Cn_SCK, and I2Cn_SDA.
*
* @note I2C_NUMOF definition must not be changed.
*/
#define I2C_NUMOF (i2c_bus_num)
/** @} */
/**
* @name PWM configuration
* @{
*/
/**
* @brief Number of PWM devices
*
* The number of PWM devices is determined from the PWM0_GPIOS and PWM1_GPIOS
* definitions.
*
* @note PWM_NUMOF definition must not be changed.
*/
#define PWM_NUMOF (pwm_dev_num)
/** @} */
/**
* @name SPI configuration
*/
/**
* @brief Number of SPI interfaces
*
* The number of SPI interfaces is determined from board-specific peripheral
* definitions of SPIn_*.
*
* @note SPI_NUMOF definition must not be changed.
*/
#define SPI_NUMOF (spi_bus_num)
/** @} */
/**
* @name UART configuration
*/
/**
* @brief Number of UART interfaces
*
* The number of UART interfaces is determined from board-specific peripheral
* definitions of UARTn_*.
*
* @note UART_NUMOF definition must not be changed.
*/
#if defined(UART1_TXD) && defined(UART1_RXD) && defined(UART2_TXD) && defined(UART2_RXD)
#define UART_NUMOF 3
#elif (defined(UART1_TXD) && defined(UART1_RXD)) || (defined(UART2_TXD) && defined(UART2_RXD))
#define UART_NUMOF 2
#else
#define UART_NUMOF 1
#endif
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* PERIPH_CONF_COMMON_H */
/** @} */

View File

@ -0,0 +1,5 @@
MODULE = board
DIRS = $(RIOTBOARD)/common/esp32
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
include $(RIOTBOARD)/common/esp32/Makefile.dep

View File

@ -0,0 +1,11 @@
# common board and CPU features
include $(RIOTBOARD)/common/esp32/Makefile.features
# additional features provided by the board
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_dac
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += arduino

View File

@ -0,0 +1,3 @@
USEMODULE += boards_common_esp32
include $(RIOTBOARD)/common/esp32/Makefile.include

View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_esp32_mh-et-live-minikit MH-ET LIVE MiniKit
* @ingroup boards_esp32
* @brief Support for MH-ET LIVE MiniKit for ESP32
* @author Gunar Schorcht <gunar@schorcht.net>
## <a name="toc"> Table of Contents </a>
1. [Overview](#overview)
2. [Hardware](#hardware)
1. [MCU](#mcu)
2. [Board Configuration](#board_configuration)
3. [Board Pinout](#pinout)
4. [Optional Hardware Configurations](#optional_hardware)
3. [Flashing the Device](#flashing)
## <a name="overview"> Overview </a> &nbsp;&nbsp; [[TOC](#toc)]
The MH-ET LIVE MiniKit for ESP32 uses the ESP32-WROOM-32 module. It is a very interesting development kit as it uses in the stackable Wemos D1 Mini format. Thus, all [shields for Wemos D1 mini](https://wiki.wemos.cc/products:d1_mini_shields) for ESP8266 can also be used with ESP32. Examples for such shields are:
- Micro SD-Card Shield
- MRF24J40 IEEE 802.15.4 radio Shield
- Button Shield
- RGB LED Shield
- ...
This makes it possible to create different hardware configurations without the need for a soldering iron or a breadboard.
MH-ET LIVE MiniKit for ESP32 belongs to the class of general purpose boards where most ESP32 pins are broken out for easier access.
\htmlonly<style>div.image img[src="https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/MH-ET_LIVE_D1_mini_ESP32_2.png?inline=false"]{width:250px;}</style>\endhtmlonly
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/MH-ET_LIVE_D1_mini_ESP32_2.png?inline=false" "MH-ET LIVE MiniKit for ESP32"
This stackable plattform was tested in an RIOT application with:
- [Micro SD-Card Shield](https://wiki.wemos.cc/products:d1_mini_shields:micro_sd_card_shield)
- MRF24J40 IEEE 802.15.4 radio Shield (contact gunar@schorcht.net for more information)
- BMP180 Pressure Sensor Shield
This application is a good example how easy it is with this board to create different hardware applications.
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/MH-ET_LIVE_D1_mini_ESP32_5.png?inline=false" "RIOT application with SD-Card, MRF24J40 Radio, and BMP180 Pressure Sensor"
## <a name="hardware"> Hardware </a> &nbsp;&nbsp; [[TOC](#toc)]
This section describes
- the [MCU](#mcu),
- the default [board configuration](#board_configuration),
- [optional hardware configurations](#optional_hardware),
- the [board pinout](#pinout).
### <a name="mcu"> MCU </a> &nbsp;&nbsp; [[TOC](#toc)]
Most features of the board are provided by the ESP32 SoC. The following table summarizes these features and gives an overview of which of these features are supported by RIOT. For detailed information about the ESP32, see section \ref esp32_mcu "MCU ESP32".
<center>
MCU | ESP32 | Supported by RIOT
------------|-----------|------------------
Vendor | Espressif | |
Cores | 1 or 2 x Tensilica Xtensa LX6 | 1 core
FPU | yes (ULP - Ultra low power co-processor) | no
RAM | 520 kByte SRAM <br> 16 kByte RTC SRAM | yes
ROM | 520 kByte | yes
Flash | 512 kByte ... 16 MByte | yes
Frequency | 240 MHz, 160 MHz, 80 MHz | yes
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz <br> 31 mA @ 80 MHz <br> 5 uA in deep sleep mode | yes <br> yes <br> yes <br> no
Timers | 4 x 64 bit | yes
ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes
DACs | 2 x DAC with 8 bit | yes
GPIOs | 34 (6 of them are only inputs) | yes
I2Cs | 2 | yes
SPIs | 4 | yes
UARTs | 3 | yes
WiFi | IEEE 802.11 b/g/n built in | yes
Bluetooth | v4.2 BR/EDR and BLE | no
Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes
CAN | version 2.0 | no
IR | up to 8 channels TX/RX | no
Motor PWM | 2 devices x 6 channels | yes
LED PWM | 16 channels | no
Crypto | Hardware acceleration of AES, SHA-2, RSA, ECC, RNG | no
Vcc | 2.5 - 3.6 V | |
Documents | [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) <br> [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) | |
</center>
### <a name="board_configuration"> Board Configuration </a> &nbsp;&nbsp; [[TOC](#toc)]
The following table shows the default board configuration, which is sorted according to the defined functionality of GPIOs. This configuration can be overridden by an \ref esp32_app_spec_conf "application-specific configuration".
<center>
\anchor esp32_mh-et-live-minikit_table_board_configuration
Pin | Default Configuration<b>*</b> | Optional Modules<b>*</b> | Remarks / Prerequisites | Configuration
:------|:-------------------------|:--------------------------|:--------|:------
GPIO2 | PWM_DEV(0):0 / LED blue | | | \ref esp32_pwm_channels "PWM Channels"
GPIO0 | PWM_DEV(0):1 | | | \ref esp32_pwm_channels "PWM Channels"
GPIO4 | PWM_DEV(0):2 | | | \ref esp32_pwm_channels "PWM Channels"
GPIO15 | PWM_DEV(0):3 | | | \ref esp32_pwm_channels "PWM Channels"
GPIO22 | I2C_DEV(0):SCL | | | \ref esp32_i2c_interfaces "I2C Interfaces"
GPIO21 | I2C_DEV(0):SDA | | | \ref esp32_i2c_interfaces "I2C Interfaces"
GPIO18 | SPI_DEV(0):SCK | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO19 | SPI_DEV(0):MISO | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO23 | SPI_DEV(0):MOSI | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO5 | SPI_DEV(0):CS0 | SD Card CS | when module [sdcard_spi](https://riot-os.org/api/group__drivers__sdcard__spi.html) is used | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO1 | UART_DEV(0):TxD | | Console (configuration is fixed) | \ref esp32_uart_interfaces "UART interfaces"
GPIO3 | UART_DEV(0):RxD | | Console (configuration is fixed) | \ref esp32_uart_interfaces "UART interfaces"
GPIO9 | UART_DEV(1):TxD | | | \ref esp32_uart_interfaces "UART interfaces"
GPIO10 | UART_DEV(1):RxD | | | \ref esp32_uart_interfaces "UART interfaces"
GPIO34 | ADC_LINE(0) | | | \ref esp32_adc_channels "ADC Channels"
GPIO35 | ADC_LINE(1) | | | \ref esp32_adc_channels "ADC Channels"
GPIO36 | ADC_LINE(2) | | | \ref esp32_adc_channels "ADC Channels"
GPIO39 | ADC_LINE(3) | | | \ref esp32_adc_channels "ADC Channels"
GPIO25 | DAC_LINE(0) | | | \ref esp32_dac_channels "DAC Channels"
GPIO13 | - | | | |
GPIO12 | - | | | |
GPIO14 | - | | | |
GPIO16 | - | MRF24J40 RESET | when module [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html) is used | |
GPIO17 | - | MRF24J40 INT | when module [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html) is used | |
GPIO26 | - | MRF24J40 CS | when module [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html) is used | |
GPIO27 | - | | | |
GPIO32 | - | | | |
GPIO33 | - | | | |
</center>
<b>*</b> Default configuration cannot be used or is not available at all when the the optional hardware is used.
@note
- GPIO9 and GIOP10 can only be used in **dout** and **dio** \ref esp32_flash_modes "flash modes".
- The **RESET** signal of MRF24J40 shield can be connected to the RST **pin** of the board (see \ref esp32_mh-et-live-minikit "pinout") to keep the configured GPIO free for other purposes.
For detailed information about the configuration of ESP32 boards, see section \ref esp32_comm_periph "Common Peripherals".
### <a name="optional_hardware"> Optional Hardware Configurations </a> &nbsp;&nbsp; [[TOC](#toc)]
ENC28J60-based Ethernet network interface modules have been tested with the board. You could use the following code in your \ref esp32_app_spec_conf "application-specific configuration" to use such a module:
```
#if MODULE_ENC28J80 && BOARD_ESP32_MH_ET_LIVE_MINIKIT
#define ENC28J80_PARAM_CS GPIO14 /* ENC28J80 CS signal */
#define ENC28J80_PARAM_INT GPIO33 /* ENC28J80 INT signal */
#define ENC28J80_PARAM_RESET GPIO12 /* ENC28J80 RESET signal */
#endif
```
For **ENC28J80_PARAM_SPI** the default parameter defined by the driver can be used.
@note The **RESET** signal of ENC28J60 based modules can also be connected to the **RST** pin of the board (see \ref esp32_mh-et-live-minikit "pinout") to keep the configured GPIO free for other purposes.
### <a name="pinout"> Board Pinout </a> &nbsp;&nbsp; [[TOC](#toc)]
The following picture shows the pinout of MH-ET LIVE MiniKit for ESP32 board as defined by the default board configuration. The light green GPIOs are not used by configured on-board hardware components and can be used for any purpose. However, if optional off-board hardware modules are used, these GPIOs may also be occupied, see \ref esp32_mh-et-live-minikit_table_board_configuration "optional functions" in table board configuration.
The corresponding board schematic can be found [here](https://i.imgur.com/EpE4dGj.jpg)
\anchor esp32_mh-et-live-minikit
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/MH-ET_LIVE_D1_mini_ESP32_pinout.png?inline=false" "MH-ET LIVE MiniKit for ESP32 pinout"
## <a name="flashing"> Flashing the Device </a> &nbsp;&nbsp; [[TOC](#toc)]
Flashing RIOT is quite easy. The board has a Micro-USB connector with a reset/boot/flash logic. Just connect the board to your host computer using the programming port and type:
```
make flash BOARD=esp32-mh-et-live-minikit ...
```
For detailed information about ESP32 as well as configuring and compiling RIOT for ESP32 boards, see \ref esp32_riot.
*/

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_mh-et-live-minikit
* @{
*
* @file
* @brief Board specific configuration for the Arduino API
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_BOARD_H
#define ARDUINO_BOARD_H
#include "arduino_board_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The on-board LED is connected to Arduino pin 3 on this board
*/
#define ARDUINO_LED (3)
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_BOARD_H */
/** @} */

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_mh-et-live-minikit
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
#define ARDUINO_PIN_0 GPIO3 /**< Arduino Uno pin 0 (RxD) */
#define ARDUINO_PIN_1 GPIO1 /**< Arduino Uno pin 1 (TxD) */
#define ARDUINO_PIN_2 GPIO32 /**< Arduino Uno pin 2 */
#define ARDUINO_PIN_3 GPIO2 /**< Arduino Uno pin 3 (PWM) */
#define ARDUINO_PIN_4 GPIO27 /**< Arduino Uno pin 4 */
#define ARDUINO_PIN_5 GPIO0 /**< Arduino Uno pin 5 (PWM) */
#define ARDUINO_PIN_6 GPIO4 /**< Arduino Uno pin 6 (PWM) */
#define ARDUINO_PIN_7 GPIO33 /**< Arduino Uno pin 7 */
#define ARDUINO_PIN_8 GPIO25 /**< Arduino Uno pin 8 */
#define ARDUINO_PIN_9 GPIO15 /**< Arduino Uno pin 9 (PWM) */
#define ARDUINO_PIN_10 GPIO5 /**< Arduino Uno pin 10 (CS0 / PWM) */
#define ARDUINO_PIN_11 GPIO23 /**< Arduino Uno pin 11 (MOSI / PWM) */
#define ARDUINO_PIN_12 GPIO19 /**< Arduino Uno pin 12 (MISO) */
#define ARDUINO_PIN_13 GPIO18 /**< Arduino Uno pin 13 (SCK) */
#define ARDUINO_PIN_A0 GPIO34 /**< Arduino Uno pin A0 */
#define ARDUINO_PIN_A1 GPIO35 /**< Arduino Uno pin A1 */
#define ARDUINO_PIN_A2 GPIO36 /**< Arduino Uno pin A2 */
#define ARDUINO_PIN_A3 GPIO39 /**< Arduino Uno pin A3 */
#define ARDUINO_PIN_A4 GPIO21 /**< Arduino Uno pin A4 (SDA) */
#define ARDUINO_PIN_A5 GPIO22 /**< Arduino Uno pin A5 (SCL) */
/** @ */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_PINMAP_H */
/** @} */

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_mh-et-live-minikit
* @brief Board specific definitions for MH-ET LIVE MiniKit for ESP32
* @{
*
* The MH-ET LIVE MiniKit for ESP32 uses the ESP32-WROOM-32 module. It is
* a very interesting development kit as it is available in the stackable
* Wemos D1 Mini format. Thus, all shields for Wemos D1 mini (ESP8266
* platform) can also be used with ESP32. All GPIOs are broken out so that
* it can be configured very flexibly.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name LED (on-board) configuration
*
* @{
*/
#define LED0_PIN GPIO2
#define LED0_ACTIVE 1 /**< LED is high active */
#define LED_BLUE_PIN GPIO2
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common board definitions as last step */
#include "board_common.h"
/* include definitions for optional hardware modules */
#include "board_modules.h"
#endif /* BOARD_H */
/** @} */

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef BOARD_MODULES_H
#define BOARD_MODULES_H
/**
* @ingroup boards_esp32_mh-et-live-minikit
* @brief Definitions for Wemos stackable hardware modules (shields)
*
* The board can be used with lots of optional stackable hardware modules.
* This file contains the default configurations for those hardware modules
* that have been tested. Most of these configurations can be overridden by an
* \ref esp32_app_spec_conf "application-specific configuration".
*
* The configurations of the respective hardware modules only take place if
* the corresponding driver modules are used.
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
#if MODULE_MRF24J40 || DOXYGEN
/**
* @name MRF24J40 shield configuration
*
* Configuration for the MRF24J40 shield when module ```mrf24j40``` is used.
*
* MRF24J40 module uses SPI_DEV(0) and according pins on this board to be
* compatible with the Wemos D1 mini MRF24J40 shield.
*
* @note To keep an additional GPIO free, the ENC28J60 RESET signal can
* be connected to ESP32 Reset pin.
* @{
*/
#define MRF24J40_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */
#ifndef MRF24J40_PARAM_SPI_CLK
#define MRF24J40_PARAM_SPI_CLK SPI_CLK_1MHZ /**< SPI bus speed used (can be overriden) */
#endif
#ifndef MRF24J40_PARAM_CS
#define MRF24J40_PARAM_CS GPIO26 /**< MRF24J40 CS signal (can be overriden) */
#endif
#ifndef MRF24J40_PARAM_INT
#define MRF24J40_PARAM_INT GPIO17 /**< MRF24J40 INT signal (can be overriden) */
#endif
#ifndef MRF24J40_PARAM_RESET
#define MRF24J40_PARAM_RESET GPIO16 /**< MRF24J40 RESET signal (can be overriden) */
#endif
/** @} */
#endif /* MODULE_MRF24J40 || DOXYGEN */
#if MODULE_SDCARD_SPI || DOXYGEN
/**
* @name SD-Card shield configuration
*
* Configuration of the SD-Card interface when module ```sdcard_spi``` is used.
*
* SD card interface uses SPI_DEV(0) on this board to be compatible with the
* Wemos D1 mini micro SD card shield. The D8 pin (GPIO5) is used as default
* CS signal.
*
* @note Please override the definition of CS pin by an by \ref
* esp32_app_spec_conf "application-specific configurations" according to your
* solder bride configuration.
* @{
*/
#define SDCARD_SPI_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */
#define SDCARD_SPI_PARAM_CLK SPI0_SCK /**< SPI_DEV(0) SCK is used (fixed) */
#define SDCARD_SPI_PARAM_MOSI SPI0_MOSI /**< SPI_DEV(0) MOSI is used (fixed) */
#define SDCARD_SPI_PARAM_MISO SPI0_MISO /**< SPI_DEV(0) MISO is used (fixed) */
#define SDCARD_SPI_PARAM_POWER GPIO_UNDEF /**< power control is not used (fixed) */
#ifndef SDCARD_SPI_PARAM_CS
#define SDCARD_SPI_PARAM_CS SPI0_CS0 /**< SD-Card CS signal (overridde it) */
#endif
/** @} */
#endif /* MODULE_SDCARD_SPI || DOXYGEN */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/** @} */
#endif /* BOARD_MODULES_H */

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
/**
* @ingroup boards_esp32_mh-et-live-minikit
* @brief Board specific configuration of direct mapped GPIOs
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
* @{
*/
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
{
.name = "LED",
.pin = LED0_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INIT_CLEAR
}
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,176 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_mh-et-live-minikit
* @brief Peripheral MCU configuration for MH-ET LIVE MiniKit for ESP32
* @{
*
* The MH-ET LIVE MiniKit for ESP32 uses the ESP32-WROOM-32 module. It is
* a very interesting development kit as it is available in the stackable
* Wemos D1 Mini format. Thus, all shields for Wemos D1 mini (ESP8266
* platform) can also be used with ESP32. All GPIOs are broken out so that
* it can be configured very flexibly.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ADC and DAC channel configuration
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as ADC channels
*
* @note As long as the GPIOs listed in ADC_GPIOS are not initialized as ADC
* channels with the ```adc_init``` function, they can be used for other
* purposes.
*/
#ifndef ADC_GPIOS
#define ADC_GPIOS { GPIO34, GPIO35, GPIO36, GPIO39 }
#endif
/**
* @brief Declaration of GPIOs that can be used as DAC channels
*
* @note As long as the GPIOs listed in DAC_GPIOS are not initialized as DAC
* channels with the ```dac_init``` function, they can be used for other
* purposes.
*/
#ifndef DAC_GPIOS
#define DAC_GPIOS { GPIO25 }
#endif
/** @} */
/**
* @name I2C configuration
*
* Only I2C interface I2C_DEV(0) is used.
*
* @note The GPIOs listed in the configuration are only initialized as I2C
* signals when module ```perpih_i2c``` is used. Otherwise they are not
* allocated and can be used for other purposes.
*
* @{
*/
#ifndef I2C0_SPEED
#define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */
#endif
#ifndef I2C0_SCL
#define I2C0_SCL GPIO22 /**< SCL signal of I2C_DEV(0) [UEXT1] */
#endif
#ifndef I2C0_SDA
#define I2C0_SDA GPIO21 /**< SDA signal of I2C_DEV(0) [UEXT1] */
#endif
/** @} */
/**
* @name PWM channel configuration
*
* @note As long as the according PWM device is not initialized with
* the ```pwm_init```, the GPIOs declared for this device can be used
* for other purposes.
*
* @{
*/
/** PWM channels for device PWM_DEV(0) */
#ifndef PWM0_GPIOS
#define PWM0_GPIOS { GPIO2, GPIO0, GPIO4, GPIO15 }
#endif
/** PWM_DEV(1) is not used */
#ifndef PWM1_GPIOS
#define PWM1_GPIOS { }
#endif
/** @} */
/**
* @name SPI configuration
*
* @note The GPIOs listed in the configuration are first initialized as SPI
* signals when the corresponding SPI interface is used for the first time
* by either calling the ```spi_init_cs``` function or the ```spi_acquire```
* function. That is, they are not allocated as SPI signals before and can
* be used for other purposes as long as the SPI interface is not used.
*
* @{
*/
#ifndef SPI0_DEV
#define SPI0_DEV VSPI /**< VSPI is used as SPI_DEV(0) */
#endif
#ifndef SPI0_SCK
#define SPI0_SCK GPIO18 /**< VSPI SCK */
#endif
#ifndef SPI0_MISO
#define SPI0_MISO GPIO19 /**< VSPI MISO */
#endif
#ifndef SPI0_MOSI
#define SPI0_MOSI GPIO23 /**< VSPI MOSI */
#endif
#ifndef SPI0_CS0
#define SPI0_CS0 GPIO5 /**< VSPI CS0 */
#endif
/** @} */
/**
* @name UART configuration
*
* ESP32 provides 3 UART interaces at maximum:
*
* UART_DEV(0) uses fixed standard configuration.<br>
* UART_DEV(1) is defined here.<br>
* UART_DEV(2) is not used.<br>
*
* @{
*/
#define UART0_TXD GPIO10 /**< direct I/O pin for UART_DEV(0) TxD, can't be changed */
#define UART0_RXD GPIO9 /**< direct I/O pin for UART_DEV(0) RxD, can't be changed */
#if FLASH_MODE_DOUT || FLASH_MODE_DIO || DOXYGEN
#ifndef UART1_TXD
#define UART1_TXD GPIO10 /**< direct I/O pin for UART_DEV(1) TxD */
#endif
#ifndef UART1_RXD
#define UART1_RXD GPIO9 /**< direct I/O pin for UART_DEV(1) RxD */
#endif
#else
#warning Configuration problem: Flash mode is qio or qout, \
GPIO9 and GPIO10 are not available for UART1 as configured
#endif
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common board definitions as last step */
#include "periph_conf_common.h"
#endif /* PERIPH_CONF_H */
/** @} */

View File

@ -0,0 +1,5 @@
MODULE = board
DIRS = $(RIOTBOARD)/common/esp32
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,5 @@
ifneq (,$(filter can,$(USEMODULE)))
USEMODULE += esp_can
endif
include $(RIOTBOARD)/common/esp32/Makefile.dep

View File

@ -0,0 +1,16 @@
# common board and CPU features
include $(RIOTBOARD)/common/esp32/Makefile.features
# additional features provided by the board (no ADC and no DAC)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_dac
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
# unique features of the board
FEATURES_PROVIDED += periph_eth # Ethernet MAC (EMAC)
FEATURES_PROVIDED += periph_can # CAN peripheral interface
FEATURES_PROVIDED += periph_ir # IR peripheral interface
FEATURES_PROVIDED += arduino

View File

@ -0,0 +1,15 @@
PSEUDOMODULES += olimex_esp32_gateway
USEMODULE += boards_common_esp32
# enables esp_eth as network device
ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
# avoid multiple definitions when package depenedencies are resolved recursively
ifndef MODULE_ESP_ETH_ADDED
MODULE_ESP_ETH_ADDED = 1
USEMODULE += esp_eth
$(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1))))
endif
endif
include $(RIOTBOARD)/common/esp32/Makefile.include

View File

@ -0,0 +1,184 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_esp32_olimex-esp32-evb Olimex ESP32-EVB
* @ingroup boards_esp32
* @brief Support for Olimex ESP32-EVB and ESP32-GATEWAY
* @author Gunar Schorcht <gunar@schorcht.net>
## <a name="toc"> Table of Contents </a>
1. [Overview](#overview)
2. [Hardware](#hardware)
1. [MCU](#mcu)
2. [Board Configuration](#board_configuration)
3. [Board Pinout](#pinout)
4. [Optional Hardware Configurations](#optional_hardware)
3. [Flashing the Device](#flashing)
## <a name="overview"> Overview </a> &nbsp;&nbsp; [[TOC](#toc)]
[Olimex ESP32-EVB](https://github.com/OLIMEX/ESP32-EVB) and [Olimex ESP32-GATEWAY](https://github.com/OLIMEX/ESP32-GATEWAY) are open source hardware boards which use the ESP32-WROOM module. The key features of the boards are:
- Ethernet LAN interface
- MicroSD card interface
- IR interface (Olimex ESP32-EVB only)
- CAN interface (Olimex ESP32-EVB only)
- two Relais (Olimex ESP32-EVB only)
- [UEXT](https://www.olimex.com/Products/Modules/UEXT/) connector with I2C, SPI and UART interfaces (Olimex ESP32-EVB only)
Using the UEXT connector, a lot of [off-board hardware modules](https://www.olimex.com/Products/Modules/) can be connected to Olimex ESP32-EVB to extend the hardware without the need for soldering iron or breadboards.
Because of the differences in the on-board hardware, it is necessary to add the following line to the makefile of the application to use the according configuration for Olimex ESP32-GATEWAY:
```
USEMODULE += olimex_esp32_gateway
```
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/Olimex_ESP32-EVB_GATEWAY.png?inline=false" "Olimex ESP32-EVB (left) and Olimex ESP32-GATEWAY (right)"
## <a name="hardware"> Hardware </a> &nbsp;&nbsp; [[TOC](#toc)]
This section describes
- the [MCU](#mcu),
- the default [board configuration](#board_configuration),
- [optional hardware configurations](#optional_hardware),
- the [board pinout](#pinout).
### <a name="mcu"> MCU </a> &nbsp;&nbsp; [[TOC](#toc)]
Most features of the boards are provided by the ESP32 SoC. The following table summarizes these features and gives an overview of which of these features are supported by RIOT. For detailed information about the ESP32, see section \ref esp32_mcu "MCU ESP32".
<center>
MCU | ESP32 | Supported by RIOT
------------|-----------|------------------
Vendor | Espressif | |
Cores | 1 or 2 x Tensilica Xtensa LX6 | 1 core
FPU | yes (ULP - Ultra low power co-processor) | no
RAM | 520 kByte SRAM <br> 16 kByte RTC SRAM | yes
ROM | 520 kByte | yes
Flash | 512 kByte ... 16 MByte | yes
Frequency | 240 MHz, 160 MHz, 80 MHz | yes
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz <br> 31 mA @ 80 MHz <br> 5 uA in deep sleep mode | yes <br> yes <br> yes <br> no
Timers | 4 x 64 bit | yes
ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes
DACs | 2 x DAC with 8 bit | yes
GPIOs | 34 (6 of them are only inputs) | yes
I2Cs | 2 | yes
SPIs | 4 | yes
UARTs | 3 | yes
WiFi | IEEE 802.11 b/g/n built in | yes
Bluetooth | v4.2 BR/EDR and BLE | no
Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes
CAN | version 2.0 | no
IR | up to 8 channels TX/RX | no
Motor PWM | 2 devices x 6 channels | yes
LED PWM | 16 channels | no
Crypto | Hardware acceleration of AES, SHA-2, RSA, ECC, RNG | no
Vcc | 2.5 - 3.6 V | |
Documents | [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) <br> [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) | |
</center>
### <a name="board_configuration"> Board Configuration </a> &nbsp;&nbsp; [[TOC](#toc)]
Olimex ESP32-EVB and Olimex ESP32-GATEWAY have the following on-board components:
- Ethernet LAN interface
- MicroSD card interface
- IR interface (Olimex ESP32-EVB only)
- CAN interface (Olimex ESP32-EVB only)
- two Relais (Olimex ESP32-EVB only)
- [UEXT](https://www.olimex.com/Products/Modules/UEXT/) connector with I2C, SPI and UART interfaces (Olimex ESP32-EVB only)
The following table shows the default board configuration, which is sorted according to the defined functionality of GPIOs. This configuration can be overridden by \ref esp32_app_spec_conf "application-specific configurations".
<center>
\anchor esp32_olimex-esp32-evb_table_board_configuration
Pin | Configuration<b>*</b><br>ESP32-EVB | Configuration<b>*</b><br>ESP32-GATEWAY | Remarks / Prerequisites | Configuration
:------|:------------------|:-----------------|-|-|
GPIO13 | I2C_DEV(0):SDA | SDCARD_CS | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_i2c_interfaces "I2C Interfaces"
GPIO16 | I2C_DEV(0):SCL | I2C_DEV(0):SCL | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_i2c_interfaces "I2C Interfaces"
GPIO14 | SPI_DEV(0):CLK | SDCARD_CLK | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO2 | SPI_DEV(0):MISO | SDCARD_MISO | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO15 | SPI_DEV(0):MOSI | SDCARD_MOSI | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO17 | SPI_DEV(0):CS0 | I2C_DEV(0):SDA | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO1 | UART_DEV(0):TxD | UART_DEV(0):TxD | Console (cannot be changed) | \ref esp32_uart_interfaces "UART interfaces"
GPIO3 | UART_DEV(0):RxD | UART_DEV(0):RxD | Console (cannot be changed) | \ref esp32_uart_interfaces "UART interfaces"
GPIO4 | UART_DEV(1):TxD | N/A | ESP32-EVB [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_uart_interfaces "UART interfaces"
GPIO36 | UART_DEV(1):RxD | ADC_LINE(2) | on ESP32-EVB available at [[UEXT1](https://www.olimex.com/Products/Modules/UEXT)] | \ref esp32_uart_interfaces "UART interfaces"
GPIO32 | Relais 1 | ADC_LINE(0) | | \ref esp32_adc_channels "ADC Channels"
GPIO33 | Relais 2 | LED0 | | |
GPIO34 | BUTTON0 | BUTTON0 | | |
GPIO9 | PWM_DEV(0):0 | PWM_DEV(0):0 | | \ref esp32_pwm_channels "PWM Channels"
GPIO10 | PWM_DEV(0):1 | PWM_DEV(0):1 | | \ref esp32_pwm_channels "PWM Channels"
GPIO5 | CAN_DEV(0):TX | | | \ref esp32_can_interfaces "CAN Interfaces"
GPIO35 | CAN_DEV(0):RX | ADC_LINE(1) | | \ref esp32_adc_channels "ADC Channels"
GPIO12 | IR_DEV(0):TX | N/A | IR is not yet supported | |
GPIO39 | IR_DEV(0):RX | ADC_LINE(3) | IR is not yet supported | \ref esp32_adc_channels "ADC Channels"
GPIO18 | EMAC_SMI:MDIO | EMAC_SMI:MDIO | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO23 | EMAC_SMI:MDC | EMAC_SMI:MDC | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO0 | EMAC_RMII:TX_CLK | EMAC_RMII:TX_CLK | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO21 | EMAC_RMII:TX_EN | EMAC_RMII:TX_EN | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO19 | EMAC_RMII:TXD0 | EMAC_RMII:TXD0 | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO22 | EMAC_RMII:TXD1 | EMAC_RMII:TXD1 | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO25 | EMAC_RMII:RXD0 | EMAC_RMII:RXD0 | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO26 | EMAC_RMII:RXD1 | EMAC_RMII:RXD1 | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
GPIO27 | EMAC_RMII:RX_DV | EMAC_RMII:RX_DV | LAN interface | \ref esp32_ethernet_network_interface "Ethernet MAC"
</center>
@note
- To use the board configuration for Olimex-ESP32-GATEWAY, it is necessary to add the following line to makefile of the application:<br><br>
```
USEMODULE += olimex_esp32_gateway
```
- GPIO9 and GIOP10 can only be used in **dout** and **dio** \ref esp32_flash_modes "flash modes".
- It might be necessary to remove the SD card or the peripheral hardware attached to the SPI_DEV(0) interface for flashing RIOT. Reason is that the **SPI_DEV(0)** interface uses the HSPI interface with the GPIO2 pin as the MISO signal, which has bootstrapping functionality.
For detailed information about the configuration of ESP32 boards, see section \ref esp32_comm_periph "Common Peripherals".
### <a name="optional_hardware"> Optional Hardware Configurations </a> &nbsp;&nbsp; [[TOC](#toc)]
MRF24J40-based IEEE 802.15.4 radio modules have been tested with the board. You could use the following code in your \ref esp32_app_spec_conf "application-specific configuration" to use such modules:
```
#ifdef BOARD_ESP32_OLIMEX_EVB && !MODULE_ESP32_OLIMEX_GATEWAY
#if MODULE_MRF24J40
#define MRF24J40_PARAM_CS GPIO9 /* MRF24J40 CS signal */
#define MRF24J40_PARAM_RESET GPIO10 /* MRF24J40 RESET signal */
#define MRF24J40_PARAM_INT GPIO34 /* MRF24J40 INT signal */
#endif
#endif
```
For other parameters, the default values defined by the drivers can be used.
@note
- Since the Olimex-ESP32-GATEWAY does not break out the GPIO of the HSPI interface SPI_DEV(0), it is not possible to connect such module to Olimex-ESP32-GATEWAY.
- Since the Olimex-ESP32-EVB has a lot of on-board hardware, only a few GPIOs are available for external hardware.
- The **RESET** signal of MRF24J40 based modules can also be connected to the **RST** pin of the board (see \ref esp32_olimex-esp32-evb_pinout "pinout") to keep the configured GPIO free for other purposes.
### <a name="pinout"> Board Pinout </a> &nbsp;&nbsp; [[TOC](#toc)]
The following pictures shows the pinout of Olimex ESP32-EVB and Olimex ESP32-GATEWAY boards as defined by the default board configuration. The light green GPIOs are not used by configured on-board hardware components and can be used for any purpose. However, if optional off-board hardware modules are used, these GPIOs may also be occupied, see \ref esp32_olimex-esp32-evb_table_board_configuration "optional functions" in table board configuration.
The corresponding board schematics can be found on GitHub for [Olimex ESP32-EVB board](https://github.com/OLIMEX/ESP32-EVB/raw/master/HARDWARE/REV-D/ESP32-EVB_Rev_D.pdf) and for [Olimex ESP32-GATEWAY](https://github.com/OLIMEX/ESP32-GATEWAY/raw/master/HARDWARE/Hardware%20revision%20C/ESP32-GATEWAY_Rev_C.pdf).
\anchor esp32_olimex-esp32-evb_pinout
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/Olimex_ESP32-EVB_pinout.png?inline=false" "Olimex ESP32-EVB pinout"
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/Olimex_ESP32-GATEWAY_pinout.png?inline=false" "Olimex ESP32-GATEWAY pinout"
## <a name="flashing"> Flashing the Device </a> &nbsp;&nbsp; [[TOC](#toc)]
Flashing RIOT is quite easy. The board has a Micro-USB connector with reset/boot/flash logic. Just connect the board to your host computer and type using the programming port:
```
make flash BOARD=esp32-olimex-evb ...
```
For detailed information about ESP32 as well as configuring and compiling RIOT for ESP32 boards, see \ref esp32_riot.
*/

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_olimex-esp32-evb
* @{
*
* @file
* @brief Board specific configuration for the Arduino API
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_BOARD_H
#define ARDUINO_BOARD_H
#include "arduino_board_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The on-board LED is not available
*/
#define ARDUINO_LED (0)
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_BOARD_H */
/** @} */

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_olimex-esp32-evb
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
#define ARDUINO_PIN_0 GPIO3 /**< Arduino Uno pin 0 (RxD) */
#define ARDUINO_PIN_1 GPIO1 /**< Arduino Uno pin 1 (TxD) */
#define ARDUINO_PIN_2 GPIO32 /**< Arduino Uno pin 2 */
#define ARDUINO_PIN_3 GPIO33 /**< Arduino Uno pin 3 (PWM) */
#define ARDUINO_PIN_4 GPIO4 /**< Arduino Uno pin 4 */
#define ARDUINO_PIN_5 GPIO9 /**< Arduino Uno pin 5 (PWM) */
#define ARDUINO_PIN_6 GPIO10 /**< Arduino Uno pin 6 (PWM) */
#define ARDUINO_PIN_7 GPIO7 /**< Arduino Uno pin 7 */
#define ARDUINO_PIN_8 GPIO8 /**< Arduino Uno pin 8 */
#define ARDUINO_PIN_9 GPIO_UNDEF /**< Arduino Uno pin 9 (PWM) */
#define ARDUINO_PIN_10 GPIO17 /**< Arduino Uno pin 10 (CS0 / PWM) */
#define ARDUINO_PIN_11 GPIO15 /**< Arduino Uno pin 11 (MOSI / PWM) */
#define ARDUINO_PIN_12 GPIO2 /**< Arduino Uno pin 12 (MISO) */
#define ARDUINO_PIN_13 GPIO14 /**< Arduino Uno pin 13 (SCK) */
#define ARDUINO_PIN_A0 GPIO34 /**< Arduino Uno pin A0 */
#define ARDUINO_PIN_A1 GPIO35 /**< Arduino Uno pin A1 */
#define ARDUINO_PIN_A2 GPIO36 /**< Arduino Uno pin A2 */
#define ARDUINO_PIN_A3 GPIO39 /**< Arduino Uno pin A3 */
#define ARDUINO_PIN_A4 GPIO13 /**< Arduino Uno pin A4 (SDA) */
#define ARDUINO_PIN_A5 GPIO16 /**< Arduino Uno pin A5 (SCL) */
/** @ */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_PINMAP_H */
/** @} */

View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_olimex-esp32-evb
* @brief Board specific definitions for Olimex ESP32-EVB (ESP32-GATEWAY)
*
* This configuration is for the Olimex ESP32-EVB, but can also be used
* for the Olimex ESP32-GATEWAY. To use this board definition with Olimex
* ESP32-GATEWAY, add
* ```
* USEMODULE += olimex_esp32_gateway
* ```
* to the makefile of the application to use the according default board
* configuration.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Button pin definitions
* @{
*/
#define BUTTON0_PIN GPIO34
/** @} */
/**
* @name LED (on-board) configuration
*
* Olimex ESP32-GATEWAY has an ob-board LED.
* @{
*/
#if MODULE_OLIMEX_ESP32_GATEWAY
#define LED0_PIN GPIO33
#define LED0_ACTIVE (1) /**< LED is high active */
#endif
/** @} */
/**
* @name SD-Card interface configuration
*
* SD-Card interface uses SPI_DEV(1) on this board.
*
* @note On Olimex ESP32-EVB, the CD/CS pin is not connected and
* simply pulled-up. Therefore, SPI bus mode is not available and the card
* interface can be used only in 1-bit SD bus mode. That is, SPI SD-Card
* is not working. On Olimex ESP32-GATEWAY, the CD/CS pin is connected to
* GPIO13. The SPI SD-Card driver should work on this board.
* @{
*/
#if (MODULE_SDCARD_SPI && MODULE_OLIMEX_ESP32_GATEWAY) || DOXYGEN
#define SDCARD_SPI_PARAM_SPI SPI_DEV(0)
#define SDCARD_SPI_PARAM_CS GPIO13
#define SDCARD_SPI_PARAM_CLK SPI0_SCK
#define SDCARD_SPI_PARAM_MOSI SPI0_MOSI
#define SDCARD_SPI_PARAM_MISO SPI0_MISO
#define SDCARD_SPI_PARAM_POWER GPIO_UNDEF
#endif
/** @} */
/**
* @name ESP32 Ethernet (EMAC) configuration
* @{
*/
#if MODULE_ESP_ETH || DOXYGEN
#define EMAC_PHY_LAN8720 1 /**< LAN8710 used as PHY interface */
#define EMAC_PHY_ADDRESS 0 /**< PHY0 used as base address */
#define EMAC_PHY_SMI_MDC_PIN 23 /**< SMI MDC pin */
#define EMAC_PHY_SMI_MDIO_PIN 18 /**< SMI MDC pin */
#define EMAC_PHY_CLOCK_MODE ETH_CLOCK_GPIO0_IN /**< external 50 MHz clock */
#define EMAC_PHY_POWER_PIN GPIO_UNDEF /**< power enable pin not used */
#endif
/** @} */
/* include common board definitions as last step */
#include "board_common.h"
#ifdef __cplusplus
} /* end extern "C" */
#endif
#endif /* BOARD_H */
/** @} */

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
/**
* @ingroup boards_esp32_olimex-esp32-evb
* @brief Board specific configuration of direct mapped GPIOs
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
* @{
*/
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED and button configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
#if MODULE_OLIMEX_ESP32_GATEWAY
{
.name = "LED",
.pin = LED0_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INIT_CLEAR
},
#endif
{
.name = "BUT1",
.pin = BUTTON0_PIN,
.mode = GPIO_IN,
.flags = 0
},
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,225 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_olimex-esp32-evb
* @brief Peripheral MCU configuration for Olimex ESP32-EVB (ESP32-GATEWAY)
* @{
*
* This configuration is for the Olimex ESP32-EVB, but can also be used
* for the Olimex ESP32-GATEWAY. To use this board definition with Olimex
* ESP32-GATEWAY, add
* ```
* USEMODULE += olimex_esp32_gateway
* ```
* to the makefile of the application to use the according default board
* configuration.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
*/
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ADC and DAC channel configuration
*
* @note As long as the GPIOs listed in ADC_GPIOS are not initialized as ADC
* channels with the ```adc_init``` function, they can be used for other
*
* purposes.
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as ADC channels
*
* @note As long as the GPIOs listed in ADC_GPIOS are not initialized as ADC
* channels with the ```adc_init``` function, they can be used for other
* purposes.
*/
#ifndef ADC_GPIOS
#if MODULE_OLIMEX_ESP32_GATEWAY
#define ADC_GPIOS { GPIO32, GPIO35, GPIO36, GPIO39 }
#else /* MODULE_OLIMEX_ESP32_GATEWAY */
#define ADC_GPIOS { }
#endif /* MODULE_OLIMEX_ESP32_GATEWAY */
#endif /* ADC_GPIOS */
/** Olimex ESP32-EVB has no GPIOs left that might be used as DAC channels. */
#ifndef DAC_GPIOS
#define DAC_GPIOS { }
#endif
/** @} */
/**
* @name CAN configuration
*
* Olimex ESP32-EVB has a CAN interface including a CAN tranceiver on board.
*/
#ifndef MODULE_OLIMEX_ESP32_GATEWAY
#define CAN_TX GPIO5 /**< CAN TX tranceiver signal */
#define CAN_RX GPIO35 /**< CAN RX tranceiver signal */
#endif
/**
* @name I2C configuration
*
* Olimex ESP32-EVB/GATEWAY have one I2C interface ```I2C_DEV(0)```. However,
* they use different GPIOs. Olimex ESP32-EVB, the interface is also available
* at the [UEXT] connector.
*
* @note The GPIOs listed in the configuration are only initialized as I2C
* signals when module ```perpih_i2c``` is used. Otherwise they are not
* allocated and can be used for other purposes.
*
* @{
*/
#ifndef I2C0_SPEED
#define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */
#endif
#ifdef MODULE_OLIMEX_ESP32_GATEWAY
#ifndef I2C0_SCL
#define I2C0_SCL GPIO16 /**< SCL signal of I2C_DEV(0) [UEXT] */
#endif
#ifndef I2C0_SDA
#define I2C0_SDA GPIO17 /**< SDA signal of I2C_DEV(0) [UEXT] */
#endif
#else /* MODULE_OLIMEX_ESP32_GATEWAY */
#ifndef I2C0_SCL
#define I2C0_SCL GPIO16 /**< SCL signal of I2C_DEV(0) */
#endif
#ifndef I2C0_SDA
#define I2C0_SDA GPIO13 /**< SDA signal of I2C_DEV(0) */
#endif
#endif /* MODULE_OLIMEX_ESP32_GATEWAY */
/** @} */
/**
* @name PWM channel configuration
*
* @note As long as the according PWM device is not initialized with
* the ```pwm_init```, the GPIOs declared for this device can be used
* for other purposes.
*
* @{
*/
/**
* In DOUT and DIO flash mode, GPIO9 and GIO10 are available and can be used
* as PWM channels with ```PWM_DEV(0)```.
*/
#ifndef PWM0_GPIOS
#if FLASH_MODE_DOUT || FLASH_MODE_DIO || DOXYGEN
#define PWM0_GPIOS { GPIO9, GPIO10 }
#else
#error Configuration problem: Flash mode qio or qout is used, \
GPIO9 and GPIO10 cannot be used as PWM channels as configured
#define PWM0_GPIOS { }
#endif
#endif
/** PWM_DEV(1) is not used */
#ifndef PWM1_GPIOS
#define PWM1_GPIOS { }
#endif
/** @} */
/**
* @name SPI configuration
* @{
*/
/**
* @brief HSPI is used as SPI_DEV(0)
*
* It is available at the [UEXT] connector on Olimex ESP32-EVB.
*
* Although the SD card interface of the Olimex ESP32-EVB is also available at
* the ```SPI_DEV(0)``` interface, it does not have a CS signal. Therefore,
* it cannot be used in SPI mode with the ```sdcard_spi``` module. Olimex
* ESP32-GATEWAY uses the integrated SD card interface with another GPIO for
* the CS signal.
*
* @note The GPIOs listed in the configuration are first initialized as SPI
* signals when the corresponding SPI interface is used for the first time
* by either calling the ```spi_init_cs``` function or the ```spi_acquire```
* function. That is, they are not allocated as SPI signals before and can
* be used for other purposes as long as the SPI interface is not used.
*/
#ifndef SPI0_DEV
#define SPI0_DEV HSPI
#endif
#ifndef SPI0_SCK
#define SPI0_SCK GPIO14 /**< SCK [UEXT] / SD card interface] */
#endif
#ifndef SPI0_MISO
#define SPI0_MISO GPIO2 /**< MISO [UEXT] / SD card interface] */
#endif
#ifndef SPI0_MOSI
#define SPI0_MOSI GPIO15 /**< MOSI [UEXT] / SD Card interface] */
#endif
#ifndef SPI0_CS0
#ifndef MODULE_OLIMEX_ESP32_GATEWAY
#define SPI0_CS0 GPIO17 /**< CS0 [UEXT] */
#else /* MODULE_OLIMEX_ESP32_GATEWAY */
#define SPI0_CS0 GPIO13 /**< CS0 SD Card interface */
#endif /* MODULE_OLIMEX_ESP32_GATEWAY */
#endif /* SPI0_CS0 */
/** @} */
/**
* @name UART configuration
*
* ESP32 provides 3 UART interaces at maximum:
*
* UART_DEV(0) uses fixed standard configuration.<br>
* UART_DEV(1) is defined here.<br>
* UART_DEV(2) is not used.<br>
*
* If the board definition is used for Olimex EVB-GATEWAY, the UART_DEV(1)
* interface is not available.
*
* @{
*/
#define UART0_TXD GPIO1 /**< direct I/O pin for UART_DEV(0), can't be changed */
#define UART0_RXD GPIO3 /**< direct I/O pin for UART_DEV(0), can't be changed */
#ifndef UART1_TXD
#define UART1_TXD GPIO4 /**< UART_DEV(1) TxD */
#endif
#ifndef UART1_RXD
#define UART1_RXD GPIO36 /**< UART_DEV(1) RxD */
#endif
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common peripheral definitions as last step */
#include "periph_conf_common.h"
#endif /* PERIPH_CONF_H */
/** @} */

View File

@ -0,0 +1,5 @@
MODULE = board
DIRS = $(RIOTBOARD)/common/esp32
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
include $(RIOTBOARD)/common/esp32/Makefile.dep

View File

@ -0,0 +1,14 @@
# common board and CPU features
include $(RIOTBOARD)/common/esp32/Makefile.features
# additional features provided by the board
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_dac
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
# unique features provided by the board
FEATURES_PROVIDED += esp_spi_ram
FEATURES_PROVIDED += arduino

View File

@ -0,0 +1,6 @@
PSEUDOMODULES += esp_lolin_tft
USEMODULE += boards_common_esp32
USEMODULE += esp_spi_ram
include $(RIOTBOARD)/common/esp32/Makefile.include

View File

@ -0,0 +1,174 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_esp32_wemos-lolin-d32-pro Wemos LOLIN D32 Pro
* @ingroup boards_esp32
* @brief Support for Wemos LOLIN D32 Pro
* @author Gunar Schorcht <gunar@schorcht.net>
## <a name="toc"> Table of Contents </a>
1. [Overview](#overview)
2. [Hardware](#hardware)
1. [MCU](#mcu)
2. [Board Configuration](#board_configuration)
3. [Board Pinout](#pinout)
4. [Optional Hardware Configurations](#optional_hardware)
3. [Flashing the Device](#flashing)
## <a name="overview"> Overview </a> &nbsp;&nbsp; [[TOC](#toc)]
Wemos LOLIN D32 Pro is a development board that uses the ESP32-WROVER module which has a built-in 4 MByte SPI RAM. Most important features of the board are
- Micro-SD card interface
- TFT display interface
- SPI RAM 4 MByte
Wemos LOLIN D32 Pro belongs to the class of general purpose boards where most ESP32 pins are broken out for easier access.
\htmlonly<style>div.image img[src="https://wiki.wemos.cc/_media/products:d32:d32_pro_v2.0.0_1_16x9.jpg"]{width:600px;}</style>\endhtmlonly
@image html "https://wiki.wemos.cc/_media/products:d32:d32_pro_v2.0.0_1_16x9.jpg" "Wemos LOLIN D32 PRO"
## <a name="hardware"> Hardware </a> &nbsp;&nbsp; [[TOC](#toc)]
This section describes
- the [MCU](#mcu),
- the default [board configuration](#board_configuration),
- [optional hardware configurations](#optional_hardware),
- the [board pinout](#pinout).
### <a name="mcu"> MCU </a> &nbsp;&nbsp; [[TOC](#toc)]
Most features of the board are provided by the ESP32 SoC. The following table summarizes these features and gives an overview of which of these features are supported by RIOT. For detailed information about the ESP32, see section \ref esp32_mcu "MCU ESP32".
<center>
MCU | ESP32 | Supported by RIOT
------------|-----------|------------------
Vendor | Espressif | |
Cores | 1 or 2 x Tensilica Xtensa LX6 | 1 core
FPU | yes (ULP - Ultra low power co-processor) | no
RAM | 520 kByte SRAM <br> 16 kByte RTC SRAM | yes
ROM | 520 kByte | yes
Flash | 512 kByte ... 16 MByte | yes
Frequency | 240 MHz, 160 MHz, 80 MHz | yes
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz <br> 31 mA @ 80 MHz <br> 5 uA in deep sleep mode | yes <br> yes <br> yes <br> no
Timers | 4 x 64 bit | yes
ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes
DACs | 2 x DAC with 8 bit | yes
GPIOs | 34 (6 of them are only inputs) | yes
I2Cs | 2 | yes
SPIs | 4 | yes
UARTs | 3 | yes
WiFi | IEEE 802.11 b/g/n built in | yes
Bluetooth | v4.2 BR/EDR and BLE | no
Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes
CAN | version 2.0 | no
IR | up to 8 channels TX/RX | no
Motor PWM | 2 devices x 6 channels | yes
LED PWM | 16 channels | no
Crypto | Hardware acceleration of AES, SHA-2, RSA, ECC, RNG | no
Vcc | 2.5 - 3.6 V | |
Documents | [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) <br> [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) | |
</center>
### <a name="board_configuration"> Board Configuration </a> &nbsp;&nbsp; [[TOC](#toc)]
The board for the Wemos LOLIN D32 Pro has the following on-board components:
- 1 x LED
- 1 x Micro SD card interface
- 1 x TFT display connector
The following table shows the default board configuration, which is sorted according to the defined functionality of GPIOs. This configuration can be overridden by an \ref esp32_app_spec_conf "application-specific configuration".
<center>
\anchor esp32_wemos-lolin-d32-pro_table_board_configuration
Pin | Default Configuration<b>*</b> | Optional Configuration<b>*</b> | Remarks / Prerequisites | Configuration
:------|:-----------------|:--------------------|:--------------|:-------------
GPIO22 | I2C_DEV(0):SCL | | | \ref esp32_i2c_interfaces "I2C Interfaces"
GPIO21 | I2C_DEV(0):SDA | | | \ref esp32_i2c_interfaces "I2C Interfaces"
GPIO18 | SPI_DEV(0):SCK | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO19 | SPI_DEV(0):MISO | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO23 | SPI_DEV(0):MOSI | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO5 | SPI_DEV(0):CS0 / LED0 | | | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO4 | SPI_DEV(0):CS1 | SD Card CS | when module [sdcard_spi](https://riot-os.org/api/group__drivers__sdcard__spi.html) is used | \ref esp32_spi_interfaces "SPI Interfaces"
GPIO1 | UART_DEV(0):TxD | | Console (configuration is fixed) | \ref esp32_uart_interfaces "UART interfaces"
GPIO3 | UART_DEV(0):RxD | | Console (configuration is fixed) | \ref esp32_uart_interfaces "UART interfaces"
GPIO36 | ADC_LINE(0) | | | \ref esp32_adc_channels "ADC Channels"
GPIO39 | ADC_LINE(1) | | | \ref esp32_adc_channels "ADC Channels"
GPIO34 | ADC_LINE(2) | | | \ref esp32_adc_channels "ADC Channels"
GPIO35 | ADC_LINE(3) | | VBat measurement (GPIO is not broken out) | \ref esp32_adc_channels "ADC Channels"
GPIO32 | ADC_LINE(4) | TFT_LED | when TFT is connected | \ref esp32_adc_channels "ADC Channels"
GPIO33 | ADC_LINE(5) | TFT_RESET| when TFT is connected | \ref esp32_adc_channels "ADC Channels"
GPIO25 | DAC_LINE(0) | | | \ref esp32_dac_channels "DAC Channels"
GPIO26 | DAC_LINE(1) | | | \ref esp32_dac_channels "DAC Channels"
GPIO0 | PWM_DEV(0):0| MRF24J40/ENC28J60 RESET | when module [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html)/[enc2860](https://riot-os.org/api/group__drivers__enc28j60.html) is used | \ref esp32_pwm_channels "PWM Channels"
GPIO2 | PWM_DEV(0):1| MRF24J40/ENC28J60 CS | when module [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html)/[enc2860](https://riot-os.org/api/group__drivers__enc28j60.html) is used | \ref esp32_pwm_channels "PWM Channels"
GPIO13 | - | MRF24J40/ENC28J60 INT | when module [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html)/[enc2860](https://riot-os.org/api/group__drivers__enc28j60.html) is used | |
GPIO15 | - | | | |
GPIO12 | - | TS_CS | when TFT is connected | |
GPIO14 | - | TFT_CS | when TFT is connected | |
GPIO27 | - | TFT_DC | when TFT is connected | |
</center>
<b>*</b> Default configuration cannot be used or is not available at all when optional configuration is used. For example, when the TFT is connected, GPIO32 is used as **TFT_LED** signal and ADC_LINE(4) is not available.
@note When the TFT display is connected, add the following line to the makefile of the application to enable the according default board and peripheral configuration:<br>
```
USEMODULE += esp_lolin_tft
```
For detailed information about the configuration of ESP32 boards, see section \ref esp32_comm_periph "Common Peripherals".
### <a name="optional_hardware"> Optional Hardware Configurations </a> &nbsp;&nbsp; [[TOC](#toc)]
MRF24J40-based IEEE 802.15.4 radio modules and ENC28J60-based Ethernet network interface modules have been tested with the board. You could use the following code in your \ref esp32_app_spec_conf "application-specific configuration" to use such modules:
```
#ifdef BOARD_ESP32_WEMOS_LOLIN_D32_PRO
#if MODULE_MRF24J40
#define MRF24J40_PARAM_CS GPIO15 /* MRF24J40 CS signal */
#define MRF24J40_PARAM_RESET GPIO2 /* MRF24J40 RESET signal */
#define MRF24J40_PARAM_INT GPIO13 /* MRF24J40 INT signal */
#endif
#if MODULE_ENC28J80
#define ENC28J80_PARAM_CS GPIO15 /* ENC28J80 CS signal */
#define ENC28J80_PARAM_RESET GPIO2 /* ENC28J80 RESET signal */
#define ENC28J80_PARAM_INT GPIO13 /* ENC28J80 INT signal */
endif
#endif
```
For other parameters, the default values defined by the drivers can be used.
@note
- Only a few GPIOs are available for external hardware on the Wemos LOLIN D32 PRO. Therefore, MRF24J40 and ENC28J60 based modules use the same GPIOs and only one of these modules can be used simultaneously.
- The **RESET** signal of MRF24J40 and ENC28J60 based modules can also be connected to the **RST** pin of the board (see \ref esp32_wemos-lolin-d32-pro_pinout "pinout") to keep the configured GPIO free for other purposes.
### <a name="pinout"> Board Pinout </a> &nbsp;&nbsp; [[TOC](#toc)]
The following picture shows the pinout of WEMOS LOLIN D32 PRO board as defined by the default board configuration. The light green GPIOs are not used by configured on-board hardware components and can be used for any purpose. However, if optional off-board hardware modules are used, these GPIOs may also be occupied, see \ref esp32_wemos-lolin-d32-pro_table_board_configuration "optional functions" in table board configuration.
The corresponding board schematic can be found [here](https://wiki.wemos.cc/_media/products:d32:sch_d32_pro_v2.0.0.pdf).
\anchor esp32_wemos-lolin-d32-pro_pinout
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/Wemos_LOLIN_D32_PRO_pinout.png?inline=false" "Wemos LOLIN D32 PRO pinout"
## <a name="flashing"> Flashing the Device </a> &nbsp;&nbsp; [[TOC](#toc)]
Flashing RIOT is quite easy. The board has a Micro-USB connector with reset/boot/flash logic. Just connect the board to your host computer using the programming port and type:
```
make flash BOARD=esp32-wemos-lolin-d32-pro ...
```
For detailed information about ESP32 as well as configuring and compiling RIOT for ESP32 boards, see \ref esp32_riot.
*/

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wemos-lolin-d32-pro
* @{
*
* @file
* @brief Board specific configuration for the Arduino API
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_BOARD_H
#define ARDUINO_BOARD_H
#include "arduino_board_common.h"
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The on-board LED is connected to pin 2 on this board
*/
#define ARDUINO_LED (10)
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_BOARD_H */
/** @} */

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wemos-lolin-d32-pro
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
#define ARDUINO_PIN_0 GPIO3 /**< Arduino Uno pin 0 (RxD) */
#define ARDUINO_PIN_1 GPIO1 /**< Arduino Uno pin 1 (TxD) */
#define ARDUINO_PIN_2 GPIO4 /**< Arduino Uno pin 2 */
#define ARDUINO_PIN_3 GPIO0 /**< Arduino Uno pin 3 (PWM) */
#define ARDUINO_PIN_4 GPIO13 /**< Arduino Uno pin 4 */
#define ARDUINO_PIN_5 GPIO2 /**< Arduino Uno pin 5 (PWM) */
#define ARDUINO_PIN_6 GPIO15 /**< Arduino Uno pin 6 (PWM) */
#define ARDUINO_PIN_7 GPIO25 /**< Arduino Uno pin 7 */
#define ARDUINO_PIN_8 GPIO26 /**< Arduino Uno pin 8 */
#define ARDUINO_PIN_9 GPIO32 /**< Arduino Uno pin 9 (PWM) */
#define ARDUINO_PIN_10 GPIO5 /**< Arduino Uno pin 10 (CS0 / PWM) */
#define ARDUINO_PIN_11 GPIO23 /**< Arduino Uno pin 11 (MOSI / PWM) */
#define ARDUINO_PIN_12 GPIO19 /**< Arduino Uno pin 12 (MISO) */
#define ARDUINO_PIN_13 GPIO18 /**< Arduino Uno pin 13 (SCK) */
#define ARDUINO_PIN_A0 GPIO36 /**< Arduino Uno pin A0 */
#define ARDUINO_PIN_A1 GPIO39 /**< Arduino Uno pin A1 */
#define ARDUINO_PIN_A2 GPIO34 /**< Arduino Uno pin A2 */
#define ARDUINO_PIN_A3 GPIO35 /**< Arduino Uno pin A3 */
#define ARDUINO_PIN_A4 GPIO21 /**< Arduino Uno pin A4 (SDA) */
#define ARDUINO_PIN_A5 GPIO22 /**< Arduino Uno pin A5 (SCL) */
/** @ */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_PINMAP_H */
/** @} */

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wemos-lolin-d32-pro
* @brief Board specific definitions for Wemos LOLIN D32 Pro
* @{
*
* Wemos LOLIN D32 Pro is a development board that uses the ESP32-WROVER
* module which has a built-in 4 MByte SPI RAM. Most important
* features of the board are
*
* - Micro-SD card interface
* - LCD interface
* - SPI RAM 4 MByte
*
* Furthermore, most GPIOs are broken out for extension.
*
* When the TFT display is connected, add
* ```
* USEMODULE += esp_lolin_tft
* ```
* to the makefile of the application to use the according default board
* configuration.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name LED (on-board) configuration
* @{
*/
#define LED0_PIN GPIO5
#define LED0_ACTIVE (0) /* LED is low active */
/** @} */
/**
* @name SD card interface configuration
*
* SD card interface uses SPI_DEV(0) on this board. This configuration cannot
* be overriden.
* @{
*/
#if MODULE_SDCARD_SPI
#define SDCARD_SPI_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */
#define SDCARD_SPI_PARAM_CLK SPI0_SCK /**< HSPI SCK is used (fixed) */
#define SDCARD_SPI_PARAM_MOSI SPI0_MOSI /**< HSPI MOSI is used (fixed) */
#define SDCARD_SPI_PARAM_MISO SPI0_MISO /**< HSPI MISO is used (fixed) */
#define SDCARD_SPI_PARAM_CS SPI0_CS1 /**< HSPI CS1 is used (fixed) */
#define SDCARD_SPI_PARAM_POWER GPIO_UNDEF /**< power control is not used (fixed) */
#endif
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common board definitions as last step */
#include "board_common.h"
#endif /* BOARD_H */
/** @} */

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
/**
* @ingroup boards_esp32_wemos-lolin-d32-pro
* @brief Board specific configuration of direct mapped GPIOs
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
* @{
*/
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
{
.name = "LED",
.pin = LED0_PIN,
.mode = GPIO_OUT,
.flags = (SAUL_GPIO_INVERTED | SAUL_GPIO_INIT_CLEAR)
}
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,194 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wemos-lolin-d32-pro
* @brief Peripheral MCU configuration for Wemos LOLIN D32 Pro
* @{
*
*
* Wemos LOLIN D32 Pro is a development board that uses the ESP32-WROVER
* module which has a built-in 4 MByte SPI RAM. Most important
* features of the board are
*
* - Micro-SD card interface
* - LCD interface
* - SPI RAM 4 MByte
*
* Furthermore, most GPIOs are broken out for extension.
*
* When the TFT display is connected, add
* ```
* USEMODULE += esp_lolin_tft
* ```
* to the makefile of the application to use the according default board
* configuration.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
*/
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ADC and DAC channel configuration
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as ADC channels
*
* GPIO35 is used to measure V_BAT and is therefore not broken out.
*
* @note As long as the GPIOs listed in ADC_GPIOS are not initialized as ADC
* channels with the ```adc_init``` function, they can be used for other
* purposes.
*/
#ifndef ADC_GPIOS
#ifndef MODULE_ESP_LOLIN_TFT
#define ADC_GPIOS { GPIO36, GPIO39, GPIO34, GPIO35, GPIO32, GPIO33 }
#else
#define ADC_GPIOS { GPIO36, GPIO39, GPIO34, GPIO35 }
#endif
#endif
/**
* @brief Declaration of GPIOs that can be used as DAC channels
*
* @note As long as the GPIOs listed in DAC_GPIOS are not initialized as DAC
* channels with the ```dac_init``` function, they can be used for other
* purposes.
*/
#ifndef DAC_GPIOS
#define DAC_GPIOS { GPIO25, GPIO26 }
#endif
/** @} */
/**
* @name I2C configuration
*
* Only I2C interface I2C_DEV(0) is used.
*
* @note The GPIOs listed in the configuration are only initialized as I2C
* signals when module ```perpih_i2c``` is used. Otherwise they are not
* allocated and can be used for other purposes.
*
* @{
*/
#ifndef I2C0_SPEED
#define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */
#endif
#ifndef I2C0_SCL
#define I2C0_SCL GPIO22 /**< SCL signal of I2C_DEV(0) [UEXT1] */
#endif
#ifndef I2C0_SDA
#define I2C0_SDA GPIO21 /**< SDA signal of I2C_DEV(0) [UEXT1] */
#endif
/** @} */
/**
* @name PWM channel configuration
*
* @note As long as the according PWM device is not initialized with
* the ```pwm_init```, the GPIOs declared for this device can be used
* for other purposes.
*
* @{
*/
/** PWM channels for device PWM_DEV(0) */
#ifndef PWM0_GPIOS
#define PWM0_GPIOS { GPIO0, GPIO2 }
#endif
/** PWM_DEV(1) is not used */
#ifndef PWM1_GPIOS
#define PWM1_GPIOS { }
#endif
/** @} */
/**
* @name SPI configuration
*
* @note The GPIOs listed in the configuration are first initialized as SPI
* signals when the corresponding SPI interface is used for the first time
* by either calling the ```spi_init_cs``` function or the ```spi_acquire```
* function. That is, they are not allocated as SPI signals before and can
* be used for other purposes as long as the SPI interface is not used.
*
* @{
*/
#ifndef SPI0_DEV
#define SPI0_DEV VSPI /**< VSPI is used as SPI_DEV(0) */
#endif
#ifndef SPI0_SCK
#define SPI0_SCK GPIO18 /**< VSPI SCK */
#endif
#ifndef SPI0_MISO
#define SPI0_MISO GPIO19 /**< VSPI MISO */
#endif
#ifndef SPI0_MOSI
#define SPI0_MOSI GPIO23 /**< VSPI MOSI */
#endif
#ifndef SPI0_CS0
#define SPI0_CS0 GPIO5 /**< VSPI CS0 */
#endif
#ifdef MODULE_SDCARD_SPI
#define SPI0_CS1 GPIO4 /**< VSPI CS1 / SD card [TF_CS] */
#endif
#ifdef MODULE_ESP_LOLIN_TFT
#define SPI0_CS2 GPI14 /**< VSPI CS2 / TFT [TFT_CS] */
#define SPI0_CS3 GPI12 /**< VSPI CS3 / TFT [TS_CS] */
#endif
/** @} */
/**
* @name UART configuration
*
* ESP32 provides 3 UART interaces at maximum:
*
* UART_DEV(0) uses fixed standard configuration.<br>
* UART_DEV(1) is not used.<br>
* UART_DEV(2) is not used.<br>
*
* @{
*/
#define UART0_TXD GPIO1 /**< direct I/O pin for UART_DEV(0) TxD, can't be changed */
#define UART0_RXD GPIO3 /**< direct I/O pin for UART_DEV(0) RxD, can't be changed */
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common board definitions as last step */
#include "periph_conf_common.h"
#endif /* PERIPH_CONF_H */
/** @} */

View File

@ -0,0 +1,5 @@
MODULE = board
DIRS = $(RIOTBOARD)/common/esp32
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,49 @@
include $(RIOTBOARD)/common/esp32/Makefile.dep
# default parameter definitions when module enc28j60 is used
ifneq (, $(filter enc28j60, $(USEMODULE)))
# avoid multiple definitions when package depenedencies are resolved recursively
ifndef ENC28J60_PARAM_DEFINED
export ENC28J60_PARAM_DEFINED = 1
# default definitions
ENC28J60_PARAM_SPI ?= SPI_DEV\(0\)
ENC28J60_PARAM_CS ?= GPIO32
ENC28J60_PARAM_INT ?= GPIO35
ENC28J60_PARAM_RESET ?= GPIO33
CFLAGS += -DENC28J60_PARAM_SPI=$(ENC28J60_PARAM_SPI)
CFLAGS += -DENC28J60_PARAM_CS=$(ENC28J60_PARAM_CS)
CFLAGS += -DENC28J60_PARAM_INT=$(ENC28J60_PARAM_INT)
CFLAGS += -DENC28J60_PARAM_RESET=$(ENC28J60_PARAM_RESET)
# to satisfy variable defintions in tests/driver_enc28j60/Makefile
ENC_SPI = $(ENC28J60_PARAM_SPI)
ENC_CS = $(ENC28J60_PARAM_CS)
ENC_INT = $(ENC28J60_PARAM_INT)
ENC_RST = $(ENC28J60_PARAM_RESET)
endif
endif
# default parameter definitions when module mfr24j40 is used
ifneq (, $(filter mrf24j40, $(USEMODULE)))
# avoid multiple definitions when package depenedencies are resolved recursively
ifndef MRF24J40_PARAM_DEFINED
export MRF24J40_PARAM_DEFINED = 1
# default definitions
MRF24J40_PARAM_SPI = SPI_DEV\(0\)
MRF24J40_PARAM_SPI_CLK = SPI_CLK_1MHZ
MRF24J40_PARAM_CS ?= GPIO16
MRF24J40_PARAM_INT ?= GPIO34
MRF24J40_PARAM_RESET ?= GPIO17
CFLAGS += -DMRF24J40_PARAM_SPI=$(MRF24J40_PARAM_SPI)
CFLAGS += -DMRF24J40_PARAM_SPI_CLK=$(MRF24J40_PARAM_SPI_CLK)
CFLAGS += -DMRF24J40_PARAM_CS=$(MRF24J40_PARAM_CS)
CFLAGS += -DMRF24J40_PARAM_INT=$(MRF24J40_PARAM_INT)
CFLAGS += -DMRF24J40_PARAM_RESET=$(MRF24J40_PARAM_RESET)
endif
endif

View File

@ -0,0 +1,11 @@
# common board and CPU features
include $(RIOTBOARD)/common/esp32/Makefile.features
# additional features provided by the board
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_dac
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += arduino

View File

@ -0,0 +1,3 @@
USEMODULE += boards_common_esp32
include $(RIOTBOARD)/common/esp32/Makefile.include

View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_esp32_wroom-32 Generic ESP32-WROOM-32 boards
* @ingroup boards_esp32
* @brief Support for generic ESP32-WROOM-32 boards
* @author Gunar Schorcht <gunar@schorcht.net>
## <a name="toc"> Table of Contents </a>
1. [Overview](#overview)
2. [Hardware](#hardware)
1. [MCU](#mcu)
2. [Board Configuration](#board_configuration)
3. [Board Pinout](#pinout)
4. [Optional Hardware Configurations](#optional_hardware)
3. [Flashing the Device](#flashing)
## <a name="overview"> Overview </a> &nbsp;&nbsp; [[TOC](#toc)]
This board definition covers not just a single board, but rather a large set of generic boards that use an ESP32-WROOM-32 module and simply break out all GPIOs to external pads without having any special hardware or interfaces on-board. Examples are Espressif's ESP32-DevKitC or NodeMCU-ESP32S and a large number of clones.
\htmlonly<style>div.image img[src="https://docs.espressif.com/projects/esp-idf/en/latest/_images/esp32-devkitc-functional-overview1.jpg"]{width:600px;}</style>\endhtmlonly
\image html "https://docs.espressif.com/projects/esp-idf/en/latest/_images/esp32-devkitc-functional-overview1.jpg" "Espressif ESP32-DevKitC V4"
## <a name="hardware"> Hardware </a> &nbsp;&nbsp; [[TOC](#toc)]
This section describes
- the [MCU](#mcu),
- the default [board configuration](#board_configuration),
- [optional hardware configurations](#optional_hardware),
- the [board pinout](#pinout).
### <a name="mcu"> MCU </a> &nbsp;&nbsp; [[TOC](#toc)]
Most features of ESP32 boards are provided by the ESP32 SoC. The following table summarizes these features and gives an overview of which of these features are supported by RIOT. For detailed information about the ESP32, see section \ref esp32_mcu "MCU ESP32".
<center>
MCU | ESP32 | Supported by RIOT
------------|-----------|------------------
Vendor | Espressif | |
Cores | 1 or 2 x Tensilica Xtensa LX6 | 1 core
FPU | yes (ULP - Ultra low power co-processor) | no
RAM | 520 kByte SRAM <br> 16 kByte RTC SRAM | yes
ROM | 520 kByte | yes
Flash | 512 kByte ... 16 MByte | yes
Frequency | 240 MHz, 160 MHz, 80 MHz | yes
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz <br> 31 mA @ 80 MHz <br> 5 uA in deep sleep mode | yes <br> yes <br> yes <br> no
Timers | 4 x 64 bit | yes
ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes
DACs | 2 x DAC with 8 bit | yes
GPIOs | 34 (6 of them are only inputs) | yes
I2Cs | 2 | yes
SPIs | 4 | yes
UARTs | 3 | yes
WiFi | IEEE 802.11 b/g/n built in | yes
Bluetooth | v4.2 BR/EDR and BLE | no
Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes
CAN | version 2.0 | no
IR | up to 8 channels TX/RX | no
Motor PWM | 2 devices x 6 channels | yes
LED PWM | 16 channels | no
Crypto | Hardware acceleration of AES, SHA-2, RSA, ECC, RNG | no
Vcc | 2.5 - 3.6 V | |
Documents | [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) <br> [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) | |
</center>
### <a name="board_configuration"> Board Configuration </a> &nbsp;&nbsp; [[TOC](#toc)]
Generic ESP32-WROOM-32 boards do not have special hardware on board and all GPIOs are simply broken out for flexibility. Therefore, the board configuration is the most flexible one with provides:
18 x ADC channels at maximum
2 x DAC channels at maximum
2 x SPI at maximum
1 x I2C at maximum
2 x UART
Since all GPIOs have broken out, GPIOs can be used for different purposes in different applications. For flexibility, GPIOs can be listed in various peripheral configurations. For example, GPIO13 is used in the ADC channel definition and the definition of the MOSI signal of SPI_DEV(0).
This is possible because GPIOs are only used for a specific peripheral interface when
- the corresponding peripheral module is used, eg. periph_i2c, or
- a corresponding init function is called z. adc_init, dac_init and pwm_init or
- The corresponding peripheral interface is used for the first time, eg. spi_aqcuire.
That is, the purpose for which a GPIO is used depends on which module or function is used first.
For example, if module periph_i2c is not used, the GPIOs listed in I2C configuration can be used for the other purposes.
The following table shows the default board configuration, which is sorted according to the defined functionality of GPIOs. This configuration can be overridden by \ref esp32_app_spec_conf "application-specific configurations".
<center>
\anchor esp32_wroom_32_table_board_configuration
Function | GPIOs | Remarks |Configuration
:---------------|:-------|:--------|:----------------------------------
BUTTON0 | GPIO0 | | |
ADC | GPIO0, GPIO2, GPIO4, GPIO12, GPIO13, <br> GPIO14, GPIO15, GPIO25, GPIO26, GPIO27, <br> GPIO32, GPIO33, GPIO34, GPIO35, GPIO36, <br> GPIO39 | | see \ref esp32_adc_channels "ADC Channels"
DAC | GPIO25, GPIO26 | | \ref esp32_dac_channels "refer"
PWM_DEV(0) | GPIO0, GPIO2, GPIO4, GPIO16, GPIO17 | - | \ref esp32_pwm_channels "DAC Channels"
PWM_DEV(1) | GPIO27, GPIO32, GPIO33 | - | \ref esp32_pwm_channels "PWM Channels"
I2C_DEV(0):SDA | GPIO21 | | \ref esp32_i2c_interfaces "I2C Interfaces"
I2C_DEV(0):SCL | GPIO22 | | \ref esp32_i2c_interfaces "I2C Interfaces"
SPI_DEV(0):CLK | GPIO18 | VSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(0):MISO | GPIO19 | VSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(0):MOSI | GPIO23 | VSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(0):CS0 | GPIO5 | VSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1):CLK | GPIO14 | HSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1):MISO | GPIO12 | HSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1):MOSI | GPIO13 | HSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1):CS0 | GPIO15 | HSPI is used | \ref esp32_spi_interfaces "SPI Interfaces"
UART_DEV(0):TxD | GPIO1 | Console (configuration is fixed) | \ref esp32_uart_interfaces "UART interfaces"
UART_DEV(0):RxD | GPIO3 | Console (configuration is fixed) | \ref esp32_uart_interfaces "UART interfaces"
UART_DEV(1):TxD | GPIO10 | not available in **qout** and **qio** flash mode | \ref esp32_uart_interfaces "UART interfaces"
UART_DEV(1):RxD | GPIO9 | not available in **qout** and **qio** flash mode | \ref esp32_uart_interfaces "UART interfaces"
</center>
@note
- The configuration of ADC channels contains all ESP32 GPIOs that can be used as ADC channels.
- The configuration of DAC channels contains all ESP32 GPIOs that can be used as DAC channels.
- GPIO9 and GIOP10 can only be used in **dout** and **dio** \ref esp32_flash_modes "flash modes".
For detailed information about the configuration of ESP32 boards, see section \ref esp32_comm_periph "Common Peripherals".
### <a name="optional_hardware"> Optional Hardware Configurations </a> &nbsp;&nbsp; [[TOC](#toc)]
MRF24J40-based IEEE 802.15.4 radio modules and ENC28J60-based Ethernet network interface modules have been tested with the board. You could use the following code in your \ref esp32_app_spec_conf "application-specific configuration" to use such modules:
```
#ifdef BOARD_ESP32_WROOM-32
#if MODULE_MRF24J40
#define MRF24J40_PARAM_CS GPIO16 /* MRF24J40 CS signal */
#define MRF24J40_PARAM_RESET GPIO17 /* MRF24J40 RESET signal */
#define MRF24J40_PARAM_INT GPIO34 /* MRF24J40 INT signal */
#endif
#if MODULE_ENC28J80
#define ENC28J80_PARAM_CS GPIO32 /* ENC28J80 CS signal */
#define ENC28J80_PARAM_RESET GPIO33 /* ENC28J80 RESET signal */
#define ENC28J80_PARAM_INT GPIO35 /* ENC28J80 INT signal */
endif
#endif
```
For other parameters, the default values defined by the drivers can be used.
@note The **RESET** signal of MRF24J40 and ENC28J60 based modules can also be connected to the **RST** pin of the board (see \ref esp32_wroom_32_pinout "pinout") to keep the configured GPIO free for other purposes.
### <a name="pinout"> Board Pinout </a> &nbsp;&nbsp; [[TOC](#toc)]
The following figure shows the pinout of the defined default configuration for the EPS32-DevKitC board as an example of generic ESP32-WROOM-32 boards. The light green GPIOs are not used by configured on-board hardware components and can be used for any purpose. However, if optional off-board hardware modules are used, these GPIOs may also be occupied, see \ref esp32_wroom_32_table_board_configuration "optional functions" in table board configuration.
The corresponding board schematics can be found her [here](https://dl.espressif.com/dl/schematics/esp32_devkitc_v4-sch-20180607a.pdf)
\anchor esp32_wroom_32_pinout
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/ESP32-WROOM-32_pinouts.png?inline=false" "EPS32-DevKitC V4 Pinout"
## <a name="flashing"> Flashing the Device </a> &nbsp;&nbsp; [[TOC](#toc)]
Flashing RIOT is quite easy. The board has a Micro-USB connector with reset/boot/flash logic. Just connect the board to your host computer and type using the programming port:
```
make flash BOARD=esp32-wroom-32 ...
```
For detailed information about ESP32 as well as configuring and compiling RIOT for ESP32 boards, see \ref esp32_riot.
*/

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wroom-32
* @{
*
* @file
* @brief Board specific configuration for the Arduino API
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_BOARD_H
#define ARDUINO_BOARD_H
#include "arduino_board_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The on-board LED is not available
*/
#define ARDUINO_LED (0)
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_BOARD_H */
/** @} */

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wroom-32
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
#define ARDUINO_PIN_0 GPIO3 /**< Arduino Uno pin 0 (RxD) */
#define ARDUINO_PIN_1 GPIO1 /**< Arduino Uno pin 1 (TxD) */
#define ARDUINO_PIN_2 GPIO12 /**< Arduino Uno pin 2 */
#define ARDUINO_PIN_3 GPIO27 /**< Arduino Uno pin 3 (PWM) */
#define ARDUINO_PIN_4 GPIO2 /**< Arduino Uno pin 4 */
#define ARDUINO_PIN_5 GPIO32 /**< Arduino Uno pin 5 (PWM) */
#define ARDUINO_PIN_6 GPIO33 /**< Arduino Uno pin 6 (PWM) */
#define ARDUINO_PIN_7 GPIO13 /**< Arduino Uno pin 7 */
#define ARDUINO_PIN_8 GPIO14 /**< Arduino Uno pin 8 */
#define ARDUINO_PIN_9 GPIO0 /**< Arduino Uno pin 9 (PWM) */
#define ARDUINO_PIN_10 GPIO5 /**< Arduino Uno pin 10 (CS0 / PWM) */
#define ARDUINO_PIN_11 GPIO23 /**< Arduino Uno pin 11 (MOSI / PWM) */
#define ARDUINO_PIN_12 GPIO19 /**< Arduino Uno pin 12 (MISO) */
#define ARDUINO_PIN_13 GPIO18 /**< Arduino Uno pin 13 (SCK) */
#define ARDUINO_PIN_A0 GPIO25 /**< Arduino Uno pin A0 */
#define ARDUINO_PIN_A1 GPIO26 /**< Arduino Uno pin A1 */
#define ARDUINO_PIN_A2 GPIO4 /**< Arduino Uno pin A2 */
#define ARDUINO_PIN_A3 GPIO15 /**< Arduino Uno pin A3 */
#define ARDUINO_PIN_A4 GPIO21 /**< Arduino Uno pin A4 (SDA) */
#define ARDUINO_PIN_A5 GPIO22 /**< Arduino Uno pin A5 (SCL) */
/** @ */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_PINMAP_H */
/** @} */

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wroom-32
* @brief Board specific definitions for generic ESP32-WROOM-32 boards
* @{
*
* This configuration can be used for a large set of ESP32 boards that
* use an ESP32-WROOM-32 module and simply break out all GPIOs to external
* pads without having any special hardware or interfaces on-board.
* Examples are Espressif's EPS32-DEVKIT or NodeMCU-ESP32S and a large
* number of clones.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
} /* end extern "C" */
#endif
/**
* @name Button pin definitions
* @{
*/
/**
* Generic ESP32 boards have a BOOT button, which can be used as normal button
* during normal operation. Since the GPIO0 pin is pulled up, the button
* signal is inverted, i.e., pressing the button will give a low signal.
*/
#define BUTTON0_PIN GPIO0
/** @} */
/**
* @name LED (on-board) configuration
*
* Generic ESP32 boards usually do not have on-board LEDs.
* @{
*/
/** @} */
/* include common board definitions as last step */
#include "board_common.h"
#endif /* BOARD_H */
/** @} */

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
/**
* @ingroup boards_esp32_wroom-32
* @brief Board specific configuration of direct mapped GPIOs
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
* @{
*/
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED and Button configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
{
.name = "BOOT",
.pin = BUTTON0_PIN,
.mode = GPIO_IN,
.flags = 0
},
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,207 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_wroom-32
* @brief Peripheral MCU configuration for generic ESP32-WROOM-32 boards
* @{
*
* This configuration can be used for a large set of ESP32 boards that
* use an ESP32-WROOM-32 module and simply break out all GPIOs to external
* pads without having any special hardware or interfaces on-board.
* Examples are Espressif's EPS32-DEVKIT or NodeMCU-ESP32S and a large
* number of clones.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ADC and DAC channel configuration
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as ADC channels
*
* For generic boards, all ADC pins that have broken out are declared as ADC
* channels.
*
* @note As long as the GPIOs listed in ADC_GPIOS are not initialized as ADC
* channels with the ```adc_init``` function, they can be used for other
* purposes.
*/
#ifndef ADC_GPIOS
#define ADC_GPIOS { GPIO0 , GPIO2 , GPIO4 , GPIO12, GPIO13, GPIO14, \
GPIO15, GPIO25, GPIO26, GPIO27, GPIO32, GPIO33, \
GPIO34, GPIO35, GPIO36, GPIO39 }
#endif
/**
* @brief Declaration of GPIOs that can be used as DAC channels
*
* For generic boards the 2 DAC lines GPIO25 and GPIO26 are declared as
* DAC channels.
*
* @note As long as the GPIOs listed in DAC_GPIOS are not initialized as DAC
* channels with the ```dac_init``` function, they can be used for other
* purposes.
*/
#ifndef DAC_GPIOS
#define DAC_GPIOS { GPIO25, GPIO26 }
#endif
/** @} */
/**
* @name I2C configuration
*
* For generic boards, only one I2C interface I2C_DEV(0) is defined.
*
* The GPIOs listed in the configuration are only initialized as I2C signals
* when module ```perpih_i2c``` is used. Otherwise they are not allocated and
* can be used for other purposes.
*
* @{
*/
#ifndef I2C0_SPEED
#define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */
#endif
#ifndef I2C0_SCL
#define I2C0_SCL GPIO22 /**< SCL signal of I2C_DEV(0) [UEXT1] */
#endif
#ifndef I2C0_SDA
#define I2C0_SDA GPIO21 /**< SDA signal of I2C_DEV(0) [UEXT1] */
#endif
/** @} */
/**
* @name PWM channel configuration
*
* For generic boards, two PWM devices are configured. These devices
* contain all GPIOs that are not defined as I2C, SPI or UART for this board.
* Generally, all outputs pins could be used as PWM channels.
*
* @note As long as the according PWM device is not initialized with
* the ```pwm_init```, the GPIOs declared for this device can be used
* for other purposes.
*
* @{
*/
/**
* @brief Declaration of the channels for device PWM_DEV(0),
* at maximum six channels.
*/
#ifndef PWM0_GPIOS
#define PWM0_GPIOS { GPIO0, GPIO2, GPIO4, GPIO16, GPIO17 }
#endif
/**
* @brief Declaration of the channels for device PWM_DEV(1),
* at maximum six channels.
*/
#ifndef PWM1_GPIOS
#define PWM1_GPIOS { GPIO27, GPIO32, GPIO33 }
#endif
/** @} */
/**
* @name SPI configuration
*
* @note The GPIOs listed in the configuration are first initialized as SPI
* signals when the corresponding SPI interface is used for the first time
* by either calling the ```spi_init_cs``` function or the ```spi_acquire```
* function. That is, they are not allocated as SPI signals before and can
* be used for other purposes as long as the SPI interface is not used.
* @{
*/
#ifndef SPI0_DEV
#define SPI0_DEV VSPI /**< VSPI is used as SPI_DEV(0) */
#endif
#ifndef SPI0_SCK
#define SPI0_SCK GPIO18 /**< VSPI SCK */
#endif
#ifndef SPI0_MISO
#define SPI0_MISO GPIO19 /**< VSPI MISO */
#endif
#ifndef SPI0_MOSI
#define SPI0_MOSI GPIO23 /**< VSPI MOSI */
#endif
#ifndef SPI0_CS0
#define SPI0_CS0 GPIO5 /**< VSPI CS0 */
#endif
#ifndef SPI1_DEV
#define SPI1_DEV HSPI /**< HSPI is used as SPI_DEV(1) */
#endif
#ifndef SPI1_SCK
#define SPI1_SCK GPIO14 /**< HSPI SCK */
#endif
#ifndef SPI1_MISO
#define SPI1_MISO GPIO12 /**< HSPI MISO */
#endif
#ifndef SPI1_MOSI
#define SPI1_MOSI GPIO13 /**< HSPI MOSI */
#endif
#ifndef SPI1_CS0
#define SPI1_CS0 GPIO15 /**< HSPI CS0 */
#endif
/** @} */
/**
* @name UART configuration
*
* ESP32 provides 3 UART interaces at maximum:
*
* UART_DEV(0) uses fixed standard configuration.<br>
* UART_DEV(1) is defined here.<br>
* UART_DEV(2) is not used.<br>
*
* @{
*/
#define UART0_TXD GPIO10 /**< direct I/O pin for UART_DEV(0) TxD, can't be changed */
#define UART0_RXD GPIO9 /**< direct I/O pin for UART_DEV(0) RxD, can't be changed */
#if FLASH_MODE_DOUT || FLASH_MODE_DIO || DOXYGEN
#ifndef UART1_TXD
#define UART1_TXD GPIO10 /**< direct I/O pin for UART_DEV(1) TxD */
#endif
#ifndef UART1_RXD
#define UART1_RXD GPIO9 /**< direct I/O pin for UART_DEV(1) RxD */
#endif
#else
#warning Configuration problem: Flash mode is qio or qout, \
GPIO9 and GPIO10 are not available for UART1 as configured
#endif
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common peripheral definitions as last step */
#include "periph_conf_common.h"
#endif /* PERIPH_CONF_H */
/** @} */

View File

@ -0,0 +1,5 @@
MODULE = board
DIRS = $(RIOTBOARD)/common/esp32
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
include $(RIOTBOARD)/common/esp32/Makefile.dep

View File

@ -0,0 +1,15 @@
# common board and CPU features
include $(RIOTBOARD)/common/esp32/Makefile.features
# additional features provided by the board
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_dac
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_spi
# unique features provided by the board
FEATURES_PROVIDED += sdcard_spi
FEATURES_PROVIDED += esp_spi_ram
FEATURES_PROVIDED += arduino

View File

@ -0,0 +1,8 @@
PSEUDOMODULES += esp32_wrover_kit_camera
USEMODULE += boards_common_esp32
# configure the serial interface
PORT_LINUX ?= /dev/ttyUSB1
include $(RIOTBOARD)/common/esp32/Makefile.include

View File

@ -0,0 +1,260 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup boards_esp32_esp-wrover-kit ESP-WROVER-KIT V3
* @ingroup boards_esp32
* @brief Support for for Espressif ESP-WROVER-KIT V3
* @author Gunar Schorcht <gunar@schorcht.net>
## <a name="toc"> Table of Contents </a>
1. [Overview](#overview)
2. [Hardware](#hardware)
1. [MCU](#mcu)
2. [Board Configuration](#board_configuration)
3. [Board Pinout](#pinout)
4. [Optional Hardware Configurations](#optional_hardware)
3. [Flashing the Device](#flashing)
4. [On-Chip Debugging with the device](#debugging)
## <a name="overview"> Overview </a> &nbsp;&nbsp; [[TOC](#toc)]
The Espressif ESP-WROVER-KIT is a development board that uses the ESP32-WROVER module which includes a built-in 4 MByte SPI RAM. Most important features of the board are
- Micro-SD card interface
- OV7670 camera interface
- 3.2" SPI LCD panel
- RGB LED
- USB bridge with JTAG interface
Furthermore, many GPIOs are broken out for extension. The USB bridge based on FDI FT2232HL provides a JTAG interface for OCD debugging through the USB interface.
\htmlonly<style>div.image img[src="https://docs.espressif.com/projects/esp-idf/en/latest/_images/esp32-wrover-kit-layout-front.jpg"]{width:600px;}</style>\endhtmlonly@image html "https://docs.espressif.com/projects/esp-idf/en/latest/_images/esp32-wrover-kit-layout-front.jpg" "ESP-WROVER-KIT V3"
## <a name="hardware"> Hardware </a> &nbsp;&nbsp; [[TOC](#toc)]
This section describes
- the [MCU](#mcu),
- the default [board configuration](#board_configuration),
- [optional hardware configurations](#optional_hardware),
- the [board pinout](#pinout).
### <a name="mcu"> MCU </a> &nbsp;&nbsp; [[TOC](#toc)]
Most features of the board are provided by the ESP32 SoC. The following table summarizes these features and gives an overview of which of these features are supported by RIOT. For detailed information about the ESP32, see section \ref esp32_mcu "MCU ESP32".
<center>
MCU | ESP32 | Supported by RIOT
------------|-----------|------------------
Vendor | Espressif | |
Cores | 1 or 2 x Tensilica Xtensa LX6 | 1 core
FPU | yes (ULP - Ultra low power co-processor) | no
RAM | 520 kByte SRAM <br> 16 kByte RTC SRAM | yes
ROM | 520 kByte | yes
Flash | 512 kByte ... 16 MByte | yes
Frequency | 240 MHz, 160 MHz, 80 MHz | yes
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz <br> 31 mA @ 80 MHz <br> 5 uA in deep sleep mode | yes <br> yes <br> yes <br> no
Timers | 4 x 64 bit | yes
ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes
DACs | 2 x DAC with 8 bit | yes
GPIOs | 34 (6 of them are only inputs) | yes
I2Cs | 2 | yes
SPIs | 4 | yes
UARTs | 3 | yes
WiFi | IEEE 802.11 b/g/n built in | yes
Bluetooth | v4.2 BR/EDR and BLE | no
Ethernet | MAC interface with dedicated DMA and IEEE 1588 support | yes
CAN | version 2.0 | no
IR | up to 8 channels TX/RX | no
Motor PWM | 2 devices x 6 channels | yes
LED PWM | 16 channels | no
Crypto | Hardware acceleration of AES, SHA-2, RSA, ECC, RNG | no
Vcc | 2.5 - 3.6 V | |
Documents | [Datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) <br> [Technical Reference](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) | |
</center>
### <a name="board_configuration"> Board Configuration </a> &nbsp;&nbsp; [[TOC](#toc)]
ESP-WROVER-KIT has the following on-board components
- Micro-SD card interface
- OV7670 camera interface
- 3.2" SPI LCD panel
- RGB LED
- USB bridge with JTAG interface
The following table shows the default board configuration sorted according to the defined functionality of GPIOs for different hardware options. This configuration can be overridden by \ref esp32_app_spec_conf "application-specific configurations".
In the following table following abbreviations are used:
<b>SDC</b> = SD-Card interface is used (module **sdcard_spi** is enabled)<br>
<b>CAM</b> = Camera is plugged in/used
<center>
\anchor esp32_wrover_kit_table_board_configuration
Function | None | SDC | CAM | SDC+CAM | Remarks | Configuration
:-------------------|--------|--------|--------|---------|:---------|----------
ADC_LINE(0) | GPIO34 | GPIO34 | - | - | CAMERA_D6 | \ref esp32_adc_channels "ADC Channels"
ADC_LINE(1) | GPIO35 | GPIO35 | - | - | CAMERA_D7 | \ref esp32_adc_channels "ADC Channels"
ADC_LINE(2) | GPIO36 | GPIO36 | - | - | CAMERA_D4 | \ref esp32_adc_channels "ADC Channels"
ADC_LINE(3) | GPIO39 | GPIO39 | - | - | CAMERA_D5 | \ref esp32_adc_channels "ADC Channels"
PWM_DEV(0):0 / LED0 | GPIO0 | GPIO0 | - | - | LED_RED / CAMERA_RESET | \ref esp32_pwm_channels "PWM Channels"
PWM_DEV(0):2 / LED2 | GPIO4 | GPIO4 | - | - | LED_BLUE / CAMERA_D0 | \ref esp32_pwm_channels "PWM Channels"
LED1 | GPIO2 | GPIO2 | GPIO2 | GPIO2 | LED_GREEN | |
I2C_DEV(0):SCL | GPIO27 | GPIO27 | GPIO27 | GPIO27 | CAMERA_SIO_C | \ref esp32_i2c_interfaces "I2C Interfaces"
I2C_DEV(0):SDA | GPIO26 | GPIO26 | GPIO26 | GPIO27 | CAMERA_SIO_D | \ref esp32_i2c_interfaces "I2C Interfaces"
UART_DEV(0):TX | GPIO1 | GPIO1 | GPIO1 | GPIO1 | | \ref esp32_uart_interfaces "UART interfaces"
UART_DEV(0):RX | GPIO3 | GPIO3 | GPIO3 | GPIO3 | | \ref esp32_uart_interfaces "UART interfaces"
SPI_DEV(0):SCK | GPIO14 | GPIO14 | GPIO14 | GPIO14 | HSPI: SD-Card / Peripherals | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(0):MOSI | GPIO15 | GPIO15 | GPIO15 | GPIO15 | HSPI: SD-Card / Peripherals | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(0):MISO | GPIO2 | GPIO2 | GPIO2 | GPIO2 | HSPI: SD-Card / Peripherals | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(0):CS0 | GPIO13 | GPIO13 | GPIO13 | GPIO13 | HSPI: SD-Card CS | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1)/LCD:SCK | GPIO19 | GPIO19 | - | - | VSPI: LCD / CAMERA_D3 | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1)/LCD:MOSI | GPIO23 | GPIO23 | - | - | VSPI: LCD / CAMERA_HREF | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1)/LCD:MISO | GPIO25 | GPIO25 | - | - | VSPI: LCD / CAMERA_VSYNC | \ref esp32_spi_interfaces "SPI Interfaces"
SPI_DEV(1)/LCD:CS0 | GPIO22 | GPIO22 | - | - | VSPI: LCD / CAMERA_PCLK | \ref esp32_spi_interfaces "SPI Interfaces"
LCD_LED | GPIO5 | GPIO5 | - | - | CAMERA_D1 | |
LCD_SCL | GPIO19 | GPIO19 | - | - | CAMERA_D3 | |
LCD_MOSI | GPIO23 | GPIO23 | - | - | CAMERA_HREF | |
LCD_MISO | GPIO25 | GPIO25 | - | - | CAMERA_VSYNC | |
LCD_CS | GPIO22 | GPIO22 | - | - | CAMERA_PCLK | |
LCD_D/C | GPIO21 | GPIO21 | - | - | CAMERA_XCLK | |
LCD_RESET | GPIO18 | GPIO18 | - | - | CAMERA_D2 | |
CAMERA_D0 | - | - | GPIO4 | GPIO4 | | |
CAMERA_D1 | - | - | GPIO5 | GPIO5 | | |
CAMERA_D2 | - | - | GPIO18 | GPIO18 | | |
CAMERA_D3 | - | - | GPIO19 | GPIO19 | | |
CAMERA_D4 | - | - | GPIO36 | GPIO36 | | |
CAMERA_D5 | - | - | GPIO39 | GPIO39 | | |
CAMERA_D6 | - | - | GPIO34 | GPIO34 | | |
CAMERA_D7 | - | - | GPIO35 | GPIO35 | | |
CAMERA_XCLK | - | - | GPIO21 | GPIO21 | | |
CAMERA_PCLK | - | - | GPIO22 | GPIO22 | | |
CAMERA_HREF | - | - | GPIO23 | GPIO23 | | |
CAMERA_VSYNC | - | - | GPIO25 | GPIO25 | | |
CAMERA_SIO_D | - | - | GPIO26 | GPIO26 | | |
CAMERA_SIO_C | - | - | GPIO27 | GPIO27 | | |
CAMERA_RESET | - | - | GPIO0 | GPIO0 | | |
</center>
Following table shows the default board configuration sorted by GPIOs.
<center>
Pin | None | SDC | CAM | SDC+CAM | Remarks
:------|:-----------------------|:--------------------|:--------------------|:---------------------------|:-----
GPIO0 | PWM_DEV(0):0 / LED0 | PWM_DEV(0):0 / LED0 | CAMERA_RESET | CAMERA_RESET | |
GPIO1 | UART_DEV(0):TX | UART_DEV(0):TX | UART_DEV(0):TX | UART_DEV(0):TX | |
GPIO2 | SPI_DEV(0):MISO / LED1 | SPI_DEV(0):MISO | SPI_DEV(0):MISO | SPI_DEV(0):MISO | HSPI
GPIO3 | UART_DEV(0):RX | UART_DEV(0):RX | UART_DEV(0):RX | UART_DEV(0):RX | |
GPIO4 | PWM_DEV(0):1 / LED2 | PWM_DEV(0):1 / LED2 | CAMERA_D0 | CAMERA_D0 | |
GPIO5 | LCD LED | LCD_LED | CAMERA_D1 | CAMERA_D1 | |
GPIO6 | Flash CLK | Flash CLK | Flash CLK | Flash CLK | |
GPIO7 | Flash SD0 | Flash SD0 | Flash SD0 | Flash SD0 | |
GPIO8 | Flash SD1 | Flash SD1 | Flash SD1 | Flash SD1 | |
GPIO9 | | | | | |
GPIO10 | | | | | |
GPIO11 | Flash CMD | Flash CMD | Flash CMD | Flash CMD | |
GPIO12 | | | | | |
GPIO13 | SPI_DEV(0):CS0 | SPI_DEV(0):CS0 | SPI_DEV(0):CS0 | SPI_DEV(0):CS0 | HSPI / SD-Card CS
GPIO14 | SPI_DEV(0):SCK | SPI_DEV(0):SCK | SPI_DEV(0):SCK | SPI_DEV(0):SCK | HSPI
GPIO15 | SPI_DEV(0):MOSI | SPI_DEV(0):MOSI | SPI_DEV(0):MOSI | SPI_DEV(0):MOSI | HSPI
GPIO16 | N/A | N/A | N/A | N/A | see below
GPIO17 | N/A | N/A | N/A | N/A | see below
GPIO18 | LCD_RESET | LCD_RESET | LCD_RESET | CAMERA_D2 | |
GPIO19 | SPI_DEV(1)/LCD:SCK | SPI_DEV(1)/LCD:SCK | SPI_DEV(1)/LCD:SCK | CAMERA_D3 | VSPI
GPIO21 | LCD_D/C | LCD_D/C | LCD_D/C | CAMERA_XCLK | |
GPIO22 | SPI_DEV(1)/LCD:CS | SPI_DEV(1)/LCD:CS0 | SPI_DEV(1)/LCD:CS0 | CAMERA_PCLK | VSPI
GPIO23 | SPI_DEV(1)/LCD:MOSI | SPI_DEV(1)/LCD:MOSI | SPI_DEV(1)/LCD:MOSI | CAMERA_HREF | VSPI
GPIO25 | SPI_DEV(1)/LCD:MISO | SPI_DEV(1)/LCD:MISO | SPI_DEV(1)/LCD:MISO | CAMERA_VSYNC | VSPI
GPIO26 | I2C_DEV(0):SDA | I2C_DEV(0):SDA | I2C_DEV(0):SDA | I2C_DEV(0)/CAMERASIO_D:SDA | |
GPIO27 | I2C_DEV(0):SCL | I2C_DEV(0):SCL | I2C_DEV(0):SCL | I2C_DEV(0)/CAMERASIO_C:SCL | |
GPIO32 | N/A | N/A | N/A | N/A | see below
GPIO33 | N/A | N/A | N/A | N/A | see below
GPIO34 | ADC_LINE(0) | ADC_LINE(0) | ADC_LINE(0) | CAMERA_D6 | |
GPIO35 | ADC_LINE(1) | ADC_LINE(1) | ADC_LINE(1) | CAMERA_D7 | |
GPIO36 | ADC_LINE(2) | ADC_LINE(2) | ADC_LINE(2) | CAMERA_D4 | |
GPIO39 | ADC_LINE(3) | ADC_LINE(3) | ADC_LINE(3) | CAMERA_D5 | |
</center>
@note
- SPI_DEV(0) uses the HSPI interface with the GPIO2 pin as the MISO signal. Since GPIO2 has bootstrapping functionality, it might be necessary to to press the **Boot** button for flashing RIOT when the SD card or the peripheral hardware is attached to this SPI interface.
- GPIO0 cannot be used as SPI CS signal for external hardware connected to SPI_DEV(0). The reason for this is that the LEDs on this board are high-active and the default state of the LEDs after power-up causes a low level on the corresponding GPIO outputs.
- GPIO2 cannot be used as PWM_DEV(0) channel 1 / LED0 when SPI_DEV(0) is used in any way. Reason is that GPIO2 is the MISO signal when SPI_DEV(0) is used and is therefore an input. PWM channels are outputs.
- It might be necessary to remove the SD card or the peripheral hardware attached to the SPI_DEV(0) interface for flashing RIOT. Reason is that the **SPI_DEV(0)** interface uses the HSPI interface with the GPIO2 pin as the MISO signal, which has bootstrapping functionality.
- GPIO16 and GPIO17 are used for the built-in SPI RAM and are not available on the I/O expansion connector, even though they are labeled there.
- GPIO32 and GPIO33 are attached to a 32 kHz crystal by default. GPIO32 and GPIO33 are standard connected to a 32 kHz crystal. To make them available as a GPIO on the I/O expansion connector, SMD resistors would need to be removed and soldered.
For detailed information about the configuration of ESP32 boards, see
section Peripherals in \ref esp32_riot.
https://docs.espressif.com/projects/esp-idf/en/latest/get-started/get-started-wrover-kit.html
### <a name="optional_hardware"> Optional Hardware Configurations </a> &nbsp;&nbsp; [[TOC](#toc)]
MRF24J40-based IEEE 802.15.4 radio modules and ENC28J60-based Ethernet network interface modules have been tested with the board. You could use the following code in your \ref esp32_app_spec_conf "application-specific configuration" to use such modules:
```
#ifdef BOARD_ESP32_WROVER_KIT
#if MODULE_MRF24J40
#define MRF24J40_PARAM_CS GPIO9 /* MRF24J40 CS signal */
#define MRF24J40_PARAM_INT GPIO10 /* MRF24J40 INT signal */
#define MRF24J40_PARAM_RESET GPIO12 /* MRF24J40 RESET signal */
#endif
#if MODULE_ENC28J80
#define ENC28J80_PARAM_CS GPIO9 /* ENC28J80 CS signal */
#define ENC28J80_PARAM_INT GPIO10 /* ENC28J80 INT signal */
#define ENC28J80_PARAM_RESET GPIO12 /* ENC28J80 RESET signal */
endif
#endif
```
For other parameters, the default values defined by the drivers can be used.
@note
- Only a few GPIOs are available for external hardware on ESP-WROVER-KIT boards. Therefore, MRF24J40 and ENC28J60 based modules use the same GPIOs and only one of these modules can be used simultaneously.
- The **RESET** signal of MRF24J40 and ENC28J60 based modules can also be connected to the **RST** pin of the board (see \ref esp32_wrover_kit_pinout "pinout") to keep the configured GPIO free for other purposes.
### <a name="pinout"> Board Pinout </a> &nbsp;&nbsp; [[TOC](#toc)]
The following picture shows the pinout of the ESP-WROVER-KIT V3 boards as defined by the default board configuration. The light green GPIOs are not used by configured on-board hardware components and can be used for any purpose. However, if optional off-board hardware modules are used, these GPIOs may also be occupied, see \ref esp32_wrover_kit_table_board_configuration "optional functions" in table board configuration.
The corresponding board schematic can be found [here](https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-3.pdf).
\anchor esp32_wrover_kit_pinout
@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp32/ESP-WROVER-KIT_V3_pinout.png?inline=false" "ESP32-WROVER-KIT V3 Pinout"
## <a name="flashing"> Flashing the Device </a> &nbsp;&nbsp; [[TOC](#toc)]
Flashing RIOT is quite straight forward. The board has a Micro-USB connector with reset/boot/flash logic. Just connect the board using the programming port to your host computer and type:
```
make flash BOARD=esp32-wrover-kit ...
```
The USB bridge is based on FDI FT2232HL and offers two USB interfaces:
- the first interface is the JTAG interface for [On-Chip debugging](#debugging)
- the second interface is the console interface, which is also used for flashing
Therefore, you have to declare the USB interface in the make command. For example, if the ESP32-WROVER-KIT is connected to the host computer through the USB interfaces **/dev/ttyUSB0** and **/dev/ttyUSB1**, the make command would be used as following:
```
make flash BOARD=esp32-wrover-kit PORT=/dev/ttyUSB1 ...
```
For detailed information about ESP32 as well as configuring and compiling RIOT for ESP32 boards, see \ref esp32_riot.
## <a name="debugging"> On-Chip Debugging with the Device </a> &nbsp;&nbsp; [[TOC](#toc)]
Since the USB bridge based on FDI FT2232HL provides a JTAG interface for debugging through an USB interface, using ESP-ROVER-KIT is the easiest and most convinient way for On-Chip debugging. Please refer the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html) for details on how to setup and how to use ESP-WROVER-KIT and OpenOCD.
*/

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_esp-wrover-kit
* @{
*
* @file
* @brief Board specific configuration for the Arduino API
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_BOARD_H
#define ARDUINO_BOARD_H
#include "arduino_board_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The on-board LED is not available
*/
#define ARDUINO_LED (0)
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_BOARD_H */
/** @} */

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_esp-wrover-kit
* @{
*
* @file
* @brief Mapping from MCU pins to Arduino pins
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ARDUINO_PINMAP_H
#define ARDUINO_PINMAP_H
#include "periph/gpio.h"
#include "periph/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Mapping of MCU pins to Arduino pins
* @{
*/
#define ARDUINO_PIN_0 GPIO3 /**< Arduino Uno pin 0 (RxD) */
#define ARDUINO_PIN_1 GPIO1 /**< Arduino Uno pin 1 (TxD) */
#define ARDUINO_PIN_2 GPIO19 /**< Arduino Uno pin 2 */
#define ARDUINO_PIN_3 GPIO0 /**< Arduino Uno pin 3 (PWM) */
#define ARDUINO_PIN_4 GPIO22 /**< Arduino Uno pin 4 */
#define ARDUINO_PIN_5 GPIO4 /**< Arduino Uno pin 5 (PWM) */
#define ARDUINO_PIN_6 GPIO23 /**< Arduino Uno pin 6 (PWM) */
#define ARDUINO_PIN_7 GPIO25 /**< Arduino Uno pin 7 */
#define ARDUINO_PIN_8 GPIO9 /**< Arduino Uno pin 8 */
#define ARDUINO_PIN_9 GPIO10 /**< Arduino Uno pin 9 (PWM) */
#define ARDUINO_PIN_10 GPIO13 /**< Arduino Uno pin 10 (CS0 / PWM) */
#define ARDUINO_PIN_11 GPIO15 /**< Arduino Uno pin 11 (MOSI / PWM) */
#define ARDUINO_PIN_12 GPIO2 /**< Arduino Uno pin 12 (MISO) */
#define ARDUINO_PIN_13 GPIO14 /**< Arduino Uno pin 13 (SCK) */
#define ARDUINO_PIN_A0 GPIO34 /**< Arduino Uno pin A0 */
#define ARDUINO_PIN_A1 GPIO35 /**< Arduino Uno pin A1 */
#define ARDUINO_PIN_A2 GPIO36 /**< Arduino Uno pin A2 */
#define ARDUINO_PIN_A3 GPIO39 /**< Arduino Uno pin A3 */
#define ARDUINO_PIN_A4 GPIO26 /**< Arduino Uno pin A4 (SDA) */
#define ARDUINO_PIN_A5 GPIO27 /**< Arduino Uno pin A5 (SCL) */
/** @ */
#ifdef __cplusplus
}
#endif
#endif /* ARDUINO_PINMAP_H */
/** @} */

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_esp-wrover-kit
* @brief Board specific definitions for Espressif ESP-WROVER-KIT V3
* @{
*
* The Espressif ESP-WROVER-KIT is a development board that uses the
* ESP32-WROVER module which includes a built-in 4 MByte SPI RAM. Most
* important features of the board are
*
* - Micro-SD card interface
* - OV7670 camera interface
* - 3.2" SPI LCD panel
* - RGB LED
*
* Furthermore, many GPIOs are broken out for extension. The USB bridge
* based on FDI FT2232HL provides a JTAG interface for debugging through
* the USB interface.
*
* When the camera module is connected, add
* ```
* USEMODULE += esp32_wrover_kit_camera
* ```
* to the makefile of the application to use the according default board
* configuration.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name LED (on-board) configuration
* @{
*/
#if !MODULE_ESP32_WROVER_KIT_CAMERA || DOXYGEN
#define LED0_PIN GPIO0 /**< LED0 is available when the camera is not plugged in */
#define LED0_ACTIVE (1) /**< LED0 is high active */
#endif
#if !MODULE_SDCARD_SPI || DOXYGEN
#define LED1_PIN GPIO2 /**< LED1 is available when the SD-Card is not used */
#define LED1_ACTIVE (1) /**< LED1 is high active */
#endif
#if !MODULE_ESP32_WROVER_KIT_CAMERA || DOXYGEN
#define LED2_PIN GPIO4 /**< LED2 is available when the camera is not plugged in */
#define LED2_ACTIVE (1) /**< LED2 is high active */
#endif
#ifdef LED0_PIN
#define LED_RED_PIN LED0_PIN /**< LED0 is a red LED */
#endif
#ifdef LED1_PIN
#define LED_GREEN_PIN LED1_PIN /**< LED1 is a green LED */
#endif
#ifdef LED2_PIN
#define LED_BLUE_PIN LED2_PIN /**< LED2 is a blue LED */
#endif
/**
* @name SD-Card interface configuration
*
* The SD-Card interface is connected to the HSPI interface. Since HSPI
* becomes SPI_DEV(0) when the camera is connected, the SD card interface
* uses SPI_DEV(0) in this case. Otherwise, SPI_DEV(1) is used.
*
* This configuration cannot be changed.
* @{
*/
#if MODULE_SDCARD_SPI || DOXYGEN
#define SDCARD_SPI_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used when camera is connected */
#define SDCARD_SPI_PARAM_CLK SPI0_SCK /**< HSPI SCK is used (fixed) */
#define SDCARD_SPI_PARAM_MOSI SPI0_MOSI /**< HSPI MOSI is used (fixed) */
#define SDCARD_SPI_PARAM_MISO SPI0_MISO /**< HSPI MISO is used (fixed) */
#define SDCARD_SPI_PARAM_CS SPI0_CS0 /**< HSPI CS1 is used (fixed) */
#define SDCARD_SPI_PARAM_POWER GPIO_UNDEF /**< power control is not used (fixed) */
#endif
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common board definitions as last step */
#include "board_common.h"
#endif /* BOARD_H */
/** @} */

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef GPIO_PARAMS_H
#define GPIO_PARAMS_H
/**
* @ingroup boards_esp32_esp-wrover-kit
* @brief Board specific configuration of direct mapped GPIOs
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
* @{
*/
#include "board.h"
#include "saul/periph.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LED and button configuration
*/
static const saul_gpio_params_t saul_gpio_params[] =
{
#ifdef LED0_PIN
{
.name = "LED red",
.pin = LED0_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INIT_CLEAR
},
#endif
#ifdef LED1_PIN
{
.name = "LED blue",
.pin = LED1_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INIT_CLEAR
},
#endif
#ifdef LED2_PIN
{
.name = "LED green",
.pin = LED2_PIN,
.mode = GPIO_OUT,
.flags = SAUL_GPIO_INIT_CLEAR
}
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PARAMS_H */
/** @} */

View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup boards_esp32_esp-wrover-kit
* @brief Peripheral MCU configuration for Espressif ESP-WROVER-KIT V3
* @{
*
* The Espressif ESP-WROVER-KIT is a development board that uses the
* ESP32-WROVER module which includes a built-in 4 MByte SPI RAM. Most
* important features of the board are
*
* - Micro-SD card interface
* - OV7670 camera interface
* - 3.2" SPI LCD panel
* - RGB LED
*
* Furthermore, many GPIOs are broken out for extension. The USB bridge
* based on FDI FT2232HL provides a JTAG interface for debugging through
* the USB interface.
*
* When the camera module is connected, add
* ```
* USEMODULE += esp32_wrover_kit_camera
* ```
* to the makefile of the application to use the according default board
* configuration.
*
* For detailed information about the configuration of ESP32 boards, see
* section \ref esp32_comm_periph "Common Peripherals".
*
* @note
* Most definitions can be overridden by an \ref esp32_app_spec_conf
* "application-specific board configuration".
*
* @file
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name ADC and DAC channel configuration
* @{
*/
/**
* @brief Declaration of GPIOs that can be used as ADC channels
*
* When the camera is connected there are no GPIOs left that could be used
* as ADC channels.
*
* @note As long as the GPIOs listed in ADC_GPIOS are not initialized as ADC
* channels with the ```adc_init``` function, they can be used for other
* purposes.
*/
#ifndef ADC_GPIOS
#ifndef MODULE_ESP32_WROVER_KIT_CAMERA
#define ADC_GPIOS { GPIO34, GPIO35, GPIO36, GPIO39 }
#else
#define ADC_GPIOS { }
#endif
#endif
/**
* @brief Declaration of GPIOs that can be used as DAC channels
*
* ESP-WROVER-KIT has no GPIOs left that might be used as DAC channels.
*/
#ifndef DAC_GPIOS
#define DAC_GPIOS { }
#endif
/** @} */
/**
* @name I2C configuration
*
* @note The GPIOs listed in the configuration are only initialized as I2C
* signals when module ```perpih_i2c``` is used. Otherwise they are not
* allocated and can be used for other purposes.
*
* @{
*/
#ifndef I2C0_SPEED
#define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */
#endif
#ifndef I2C0_SCL
#define I2C0_SCL GPIO27 /**< SCL signal of I2C_DEV(0) [UEXT1] */
#endif
#ifndef I2C0_SDA
#define I2C0_SDA GPIO26 /**< SDA signal of I2C_DEV(0) [UEXT1] */
#endif
/** @} */
/**
* @name PWM channel configuration
*
* LEDs are used as PWM channels for device PWM_DEV(0).
*
* @note As long as the according PWM device is not initialized with function
* pwm_init, the GPIOs declared for this device can be used for other
* purposes.
*
* @note As long as the according PWM device is not initialized with
* the ```pwm_init```, the GPIOs declared for this device can be used
* for other purposes.
*
* @{
*/
#ifndef PWM0_GPIOS
#if !MODULE_ESP32_WROVER_KIT_CAMERA || DOXYGEN
#define PWM0_GPIOS { LED0_PIN, LED2_PIN } /**< only available when camera is not connected */
#else
#define PWM0_GPIOS { }
#endif
#endif
/** PWM_DEV(1) is not used */
#ifndef PWM1_GPIOS
#define PWM1_GPIOS { }
#endif
/** @} */
/**
* @name SPI configuration
*
* SPI configuration depends on configured/connected components.
*
* HSPI is is always available and therefore used as SPI_DEV(0)
* VSPI is only available when the camera is not plugged.
*
* @{
*/
#ifndef SPI0_DEV
#define SPI0_DEV HSPI /**< HSPI is configured as SPI_DEV(0) */
#endif
#ifndef SPI0_SCK
#define SPI0_SCK GPIO14 /**< SD Card SCL */
#endif
#ifndef SPI0_MOSI
#define SPI0_MOSI GPIO15 /**< SD Card MOSI */
#endif
#ifndef SPI0_MISO
#define SPI0_MISO GPIO2 /**< SD Card MISO */
#endif
#ifndef SPI0_CS0
#define SPI0_CS0 GPIO13 /**< SD Card CS */
#endif
#if !MODULE_ESP32_WROVER_KIT_CAMERA || DOXYGEN
/**
* When the camera is not connected, VSPI is configured and becomes SPI_DEV(1).
*
* @note The GPIOs listed in the configuration are first initialized as SPI
* signals when the corresponding SPI interface is used for the first time
* by either calling the ```spi_init_cs``` function or the ```spi_acquire```
* function. That is, they are not allocated as SPI signals before and can
* be used for other purposes as long as the SPI interface is not used.
*
*/
#ifndef SPI1_DEV
#define SPI1_DEV VSPI
#endif
#ifndef SPI1_SCK
#define SPI1_SCK GPIO19 /**< VSPI SCK used as LCD SCL, can be used to connect peripherals */
#endif
#ifndef SPI1_MOSI
#define SPI1_MOSI GPIO23 /**< VSPI MOSI used as LCD MOSI, can be used to connect peripherals */
#endif
#ifndef SPI1_MISO
#define SPI1_MISO GPIO25 /**< VSPI MISO used as LCD MISO, can be used to connect peripherals */
#endif
#ifndef SPI1_CS0
#define SPI1_CS0 GPIO22 /**< VSPI CS0 used as LCD CS, can be used to connect peripherals */
#endif
#endif /* !MODULE_ESP32_WROVER_KIT_CAMERA || DOXYGEN */
/** @} */
/**
* @name UART configuration
*
* ESP32 provides 3 UART interaces at maximum:
*
* UART_DEV(0) uses fixed standard configuration.<br>
* UART_DEV(1) is not available.<br>
* UART_DEV(2) is not available.<br>
* @{
*/
#define UART0_TXD GPIO10 /**< direct I/O pin for UART_DEV(0) TxD, can't be changed */
#define UART0_RXD GPIO9 /**< direct I/O pin for UART_DEV(0) RxD, can't be changed */
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif
/* include common board definitions as last step */
#include "periph_conf_common.h"
#endif /* PERIPH_CONF_H */
/** @} */

25
cpu/esp32/Makefile Normal file
View File

@ -0,0 +1,25 @@
# Define the module that is built:
MODULE = cpu
# Add a list of subdirectories, that should also be built:
DIRS += periph
DIRS += freertos
DIRS += vendor
ifneq (, $(filter esp_can, $(USEMODULE)))
DIRS += esp-can
endif
ifneq (, $(filter esp_eth, $(USEMODULE)))
DIRS += esp-eth
endif
ifneq (, $(filter esp_now, $(USEMODULE)))
DIRS += esp-now
endif
ifneq (, $(filter esp_wifi, $(USEMODULE)))
DIRS += esp-wifi
endif
include $(RIOTBASE)/Makefile.base

104
cpu/esp32/Makefile.dep Normal file
View File

@ -0,0 +1,104 @@
# additional modules dependencies
ifneq (,$(filter esp_eth,$(USEMODULE)))
USEMODULE += esp_idf_eth
USEMODULE += esp_idf_eth_phy
USEMODULE += gnrc
USEMODULE += netdev_eth
USEMODULE += netopt
USEMODULE += riot_freertos
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include/ethernet
INCLUDES += -I$(ESP32_SDK_DIR)/components/ethernet/include
endif
ifneq (,$(filter esp_now,$(USEMODULE)))
$(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1))))
USEMODULE += esp_wifi_any
USEMODULE += gnrc
USEMODULE += netopt
endif
ifneq (,$(filter esp_wifi,$(USEMODULE)))
$(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1))))
USEMODULE += esp_wifi_any
USEMODULE += gnrc
USEMODULE += netopt
USEMODULE += netdev_eth
endif
ifneq (,$(filter esp_wifi_any,$(USEMODULE)))
# add additional modules used for any WiFi interface
USEMODULE += esp_idf_wpa_supplicant_crypto
USEMODULE += esp_idf_wpa_supplicant_port
USEMODULE += esp_idf_nvs_flash
# crypto and hashes produce symbol conflicts with esp_idf_wpa_supplicant_crypto
DISABLE_MODULE += crypto
DISABLE_MODULE += hashes
endif
ifneq (,$(filter esp_i2c_hw,$(USEMODULE)))
USEMODULE += xtimer
else
# PLEASE NOTE: because of the very poor and faulty hardware implementation
# we use software implementation by default for the moment (if module
# esp_i2c_hw is not explicitly used)
USEMODULE += esp_i2c_sw
endif
ifneq (, $(filter esp_spi_ram, $(DISABLE_MODULE)))
USEMODULE := $(filter-out esp_spi_ram, $(USEMODULE))
endif
# each device has SPI flash memory, but must be explicitly enabled
ifneq (,$(filter esp_spiffs,$(USEMODULE)))
USEMODULE += esp_idf_spi_flash
USEMODULE += spiffs
USEMODULE += vfs
export SPIFFS_STD_OPTION = -std=c99
INCLUDES += -I$(RIOTBASE)/sys/include
INCLUDES += -I$(RIOTBASE)/sys/posix/include
endif
ifneq (,$(filter ndn-riot,$(USEPKG)))
USEMODULE += crypto
USEMODULE += cipher_modes
endif
ifneq (,$(findstring posix,$(USEMODULE)))
USEMODULE += newlib_syscalls_default
endif
ifneq (,$(filter shell,$(USEMODULE)))
USEMODULE += newlib_syscalls_default
USEMODULE += ps
USEMODULE += xtimer
endif
ifneq (,$(filter xtimer,$(USEMODULE)))
USEMODULE += newlib_syscalls_default
endif
ifneq (,$(filter newlib_syscalls_default,$(USEMODULE)))
USEMODULE += stdio_uart
endif
# if SPI RAM is enabled, ESP-IDF heap and quot flash mode have to be used
ifneq (,$(filter esp_spi_ram,$(USEMODULE)))
USEMODULE += esp_idf_heap
export FLASH_MODE = qout
CFLAGS += -DFLASH_MODE_QOUT=1
else
ifeq ($(FLASH_MODE), qio)
CFLAGS += -DFLASH_MODE_QIO=1
endif
ifeq ($(FLASH_MODE), qout)
CFLAGS += -DFLASH_MODE_QOUT=1
endif
ifeq ($(FLASH_MODE), dio)
CFLAGS += -DFLASH_MODE_DIO=1
endif
ifeq ($(FLASH_MODE), dout)
CFLAGS += -DFLASH_MODE_DOUT=1
endif
endif

View File

@ -0,0 +1,6 @@
# Features that are provided by CPU independent on the board
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_pm
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_timer

190
cpu/esp32/Makefile.include Normal file
View File

@ -0,0 +1,190 @@
# check some environment variables first
ifndef ESP32_SDK_DIR
$(info ESP32_SDK_DIR should be defined as /path/to/esp-idf directory)
$(info ESP32_SDK_DIR is set by default to /opt/esp/esp-idf)
export ESP32_SDK_DIR=/opt/esp/esp-idf
endif
# DEFAULT compile configuration
# FLASH_MODE=[ dout | dio | qout | qio ]
# use flash mode dout by default to keep GPIO9 and GPIO10 free for use
export FLASH_MODE ?= dout
# enable GDBSTUP for debugging on exceptions
ifeq ($(ENABLE_GDBSTUB), 1)
USEMODULE += esp_gdbstub
endif
# enable GDB for compilation with debug info
ifeq ($(ENABLE_GDB), 1)
USEMODULE += esp_gdb
endif
# enable modules at command line for testing
ifneq ($(USE_MODULES), )
USEMODULE += $(USE_MODULES)
endif
# SPECIAL module dependencies
# cannot be done in Makefile.dep since Makefile.dep is included too late
ifneq (,$(findstring core_thread_flags,$(USEMODULE)))
USEMODULE += pthread
endif
ifneq (,$(filter esp_gdbstub,$(USEMODULE)))
USEMODULE += esp_gdb
endif
ifneq (,$(filter esp_now,$(USEMODULE)))
USEMODULE += esp_wifi_any
endif
ifneq (,$(filter esp_wifi,$(USEMODULE)))
USEMODULE += esp_wifi_any
endif
# ESP32 pseudomodules
PSEUDOMODULES += esp_eth_hw
PSEUDOMODULES += esp_gdb
PSEUDOMODULES += esp_gdbstub
PSEUDOMODULES += esp_hw_counter
PSEUDOMODULES += esp_i2c_sw
PSEUDOMODULES += esp_i2c_hw
PSEUDOMODULES += esp_idf_newlib
PSEUDOMODULES += esp_spi_ram
PSEUDOMODULES += esp_spiffs
PSEUDOMODULES += esp_wifi_any
export CPU ?= esp32
export TARGET_ARCH ?= xtensa-esp32-elf
export ESPTOOL ?= $(ESP32_SDK_DIR)/components/esptool_py/esptool/esptool.py
USEMODULE += esp_idf
USEMODULE += esp_idf_driver
USEMODULE += esp_idf_esp32
USEMODULE += esp_idf_soc
USEMODULE += log
USEMODULE += periph
USEMODULE += periph_common
USEMODULE += random
USEMODULE += xtensa
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include/esp32
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include/heap
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include/spi_flash
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include/tcpip_adapter
INCLUDES += -I$(ESP32_SDK_DIR)/components/
INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp32/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/heap/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/esp32/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/soc/include
INCLUDES += -I$(RIOTBOARD)/common/$(CPU)/include
INCLUDES += -I$(RIOTCPU)/$(CPU)
CFLAGS += -DRIOT_OS
CFLAGS += -DSCHED_PRIO_LEVELS=32
CFLAGS += -DSDK_NOT_USED -DCONFIG_FREERTOS_UNICORE=1 -DESP_PLATFORM
CFLAGS += -DLOG_TAG_IN_BRACKETS
CFLAGS += -Wno-unused-parameter -Wformat=0
CFLAGS += -mlongcalls -mtext-section-literals -fstrict-volatile-bitfields
CFLAGS += -fdata-sections -fzero-initialized-in-bss
ASFLAGS += --longcalls --text-section-literals
ifneq ($(CONFIGS),)
CFLAGS += $(CONFIGS)
endif
# if any WiFi interface is used, the number of priority levels has to be 32
ifneq (,$(filter esp_wifi_any,$(USEMODULE)))
CFLAGS += -DSCHED_PRIO_LEVELS=32
endif
ifneq (,$(filter esp_gdb,$(USEMODULE)))
CFLAGS += -Og -ggdb -g3
else
CFLAGS += -Os
endif
ifeq ($(QEMU), 1)
CFLAGS += -DQEMU
endif
# LINKFLAGS += -Wl,--verbose
LINKFLAGS += -L$(ESP32_SDK_DIR)/components/esp32
LINKFLAGS += -L$(ESP32_SDK_DIR)/components/esp32/lib
LINKFLAGS += -Wl,--start-group
ifneq (,$(filter esp_wifi_any,$(USEMODULE)))
LINKFLAGS += $(BINDIR)/cpu.a
LINKFLAGS += $(BINDIR)/esp_idf.a
LINKFLAGS += $(BINDIR)/esp_idf_esp32.a
LINKFLAGS += $(BINDIR)/esp_idf_nvs_flash.a
LINKFLAGS += $(BINDIR)/esp_idf_spi_flash.a
LINKFLAGS += $(BINDIR)/riot_freertos.a
LINKFLAGS += -lcore -lrtc -lnet80211 -lpp -lsmartconfig -lcoexist
LINKFLAGS += -lwps -lwpa -lwpa2 -lespnow -lmesh -lphy -lstdc++
endif
ifneq (,$(filter pthread,$(USEMODULE)))
LINKFLAGS += $(BINDIR)/core.a
LINKFLAGS += $(BINDIR)/pthread.a
endif
LINKFLAGS += -lhal -lg -lc -lg
LINKFLAGS += -Wl,--end-group
LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ld/
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp32.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp32.common.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp32.peripherals.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp32.rom.ld
LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp32.rom.nanofmt.ld
LINKFLAGS += -nostdlib -lgcc -u putchar -Wl,-gc-sections
LINKFLAGS += -Wl,--warn-unresolved-symbols
# configure preflasher to convert .elf to .bin before flashing
FLASH_MODE ?= dout # FIX configuration, DO NOT CHANGE
FLASH_FREQ = 40m # FIX configuration, DO NOT CHANGE
FLASH_SIZE ?= 16m
export PREFLASHER = $(ESPTOOL)
export PREFFLAGS = --chip esp32 elf2image
export PREFFLAGS += -fm $(FLASH_MODE) -fs $(FLASH_SIZE) -ff $(FLASH_FREQ)
export PREFFLAGS += -o $(ELFFILE).bin $(ELFFILE);
export PREFFLAGS += echo "" > $(BINDIR)/partitions.csv;
export PREFFLAGS += echo "nvs, data, nvs, 0x9000, 0x6000" >> $(BINDIR)/partitions.csv;
export PREFFLAGS += echo "phy_init, data, phy, 0xf000, 0x1000" >> $(BINDIR)/partitions.csv;
export PREFFLAGS += echo -n "factory, app, factory, 0x10000, " >> $(BINDIR)/partitions.csv;
export PREFFLAGS += ls -l $(ELFFILE).bin | awk '{ print $$5 }' >> $(BINDIR)/partitions.csv;
export PREFFLAGS += python $(RIOTCPU)/$(CPU)/gen_esp32part.py --disable-sha256sum
export PREFFLAGS += --verify $(BINDIR)/partitions.csv $(BINDIR)/partitions.bin
export FLASHDEPS = preflash
# flasher configuration
ifeq ($(QEMU), 1)
export FLASHER = dd
export FFLAGS += if=/dev/zero bs=1M count=4 | tr "\\000" "\\377" > tmp.bin && cat tmp.bin |
export FFLAGS += head -c $$((0x1000)) |
export FFLAGS += cat - $(RIOTCPU)/$(CPU)/bin/bootloader.bin tmp.bin |
export FFLAGS += head -c $$((0x8000)) |
export FFLAGS += cat - $(BINDIR)/partitions.bin tmp.bin |
export FFLAGS += head -c $$((0x10000)) |
export FFLAGS += cat - $(ELFFILE).bin tmp.bin |
export FFLAGS += head -c $$((0x400000)) > $(BINDIR)/esp32flash.bin && rm tmp.bin &&
export FFLAGS += cp $(RIOTCPU)/$(CPU)/bin/rom_0x3ff90000_0x00010000.bin $(BINDIR)/rom1.bin &&
export FFLAGS += cp $(RIOTCPU)/$(CPU)/bin/rom_0x40000000_0x000c2000.bin $(BINDIR)/rom.bin
else
export PROGRAMMER_SPEED ?= 460800
export FLASHER = $(ESPTOOL)
export FFLAGS += --chip esp32 -p $(PORT) -b $(PROGRAMMER_SPEED)
export FFLAGS += --before default_reset --after hard_reset write_flash
export FFLAGS += -z -fm $(FLASH_MODE) -fs detect -ff $(FLASH_FREQ)
export FFLAGS += 0x1000 $(RIOTCPU)/$(CPU)/bin/bootloader.bin
export FFLAGS += 0x8000 $(BINDIR)/partitions.bin
export FFLAGS += 0x10000 $(ELFFILE).bin
endif

1129
cpu/esp32/README.md Normal file

File diff suppressed because it is too large Load Diff

1
cpu/esp32/bin/blank.bin Normal file
View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

BIN
cpu/esp32/bin/bootloader.elf Executable file

Binary file not shown.

BIN
cpu/esp32/bin/null.bin Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

1144
cpu/esp32/doc.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
MODULE=esp_can
include $(RIOTBASE)/Makefile.base

28
cpu/esp32/esp-can/doc.txt Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup cpu_esp32_esp_can ESP32 CAN device driver
* @ingroup cpu_esp32
* @brief CAN device driver implementation for ESP32
* @author Gunar Schorcht <gunar@schorcht.net>
The ESP32 intregates a CAN controller which is compatible with the NXP SJA1000 CAN controller. Thus, it is CAN 2.0B specification compliant and supports two message formats:
- Base frame format (11-bit ID)
- Extended frame format (29-bit ID)
@note
- ESP32 CAN does not support CAN-FD and is not CAN-FD tolerant.
- ESP32 CAN does not support SJA1000's sleep mode and wake-up functionality.
As with the SJA1000, the ESP32 CAN controller provides only the data link layer and physical layer signaling sublayer. Therefore, depending on the physical layer requirements, an external transceiver module is required which converts the CAN-RX and CAN-TX signals of the ESP32 into CAN_H and CAN_L bus signals, e.g., the MCP2551 or SN65HVD23X transceiver for compatibility with ISO 11898-2.
The ```esp_can``` module realizes a low-level CAN driver interface for the ESP32 CAN controller and provides a CAN DLL device that can be used in RIOT's CAN protocol stack. It uses the ESP32 CAN controller in SJA1000 PeliCAN mode. Please refer the [SJA1000 Datasheet](https://www.nxp.com/documents/data_sheet/SJA1000.pdf) for detailed information about the CAN controller and its programming.
*/

1025
cpu/esp32/esp-can/esp_can.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_can
* @brief CAN device driver implementation for ESP32
*
* This module realizes the low-level CAN driver interface for the ESP32 CAN
* controller which is compatible with the NXP SJA1000 CAN controller.
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @file
* @{
*/
#ifndef ESP_CAN_H
#define ESP_CAN_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* ESP_CAN_H */
/** @} */

View File

@ -0,0 +1,3 @@
MODULE=esp_eth
include $(RIOTBASE)/Makefile.base

33
cpu/esp32/esp-eth/doc.txt Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup cpu_esp32_esp_eth ESP32 Ethernet netdev interface
* @ingroup cpu_esp32
* @brief ESP32 ethernet network device driver
*
* This module realizes a netdev interface using the ESP32 Ethernet MAC
* module.
*
* @author Gunar Schorcht <gunar@schorcht.net>
ESP32 provides an <b>Ethernet MAC layer module (EMAC)</b> according to the IEEE 802.3 standard which can be used together with an external physical layer chip (PHY) to realize a 100/10 Mbps Ethernet interface. Supported PHY chips are the Microchip LAN8710/LAN8720 and the Texas Instruments TLK110.
The RIOT port for ESP32 realizes with module ```esp_eth``` a ```netdev``` driver for the EMAC which uses RIOT's standard Ethernet interface.
If the board has one of the supported PHY layer chips connected to the ESP32, the ```esp_eth``` module should be enabled by default in board's ```Makefile.dep``` when module ```netdev_default``` is used.
```
ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
USEMODULE += esp_eth
endif
```
Otherwise, the application has to add the ```esp_eth``` module in its makefile when needed.
@note
The board has to have one of the supported PHY modules to be able to use the Ethernet MAC module.
*/

View File

@ -0,0 +1,428 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_eth
* @{
*
* @file
* @brief Netdev interface for the ESP32 Ethernet MAC (EMAC) module
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifdef MODULE_ESP_ETH
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "log.h"
#include "tools.h"
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "net/gnrc/netif/ethernet.h"
#include "net/gnrc.h"
#include "net/ethernet.h"
#include "net/netdev/eth.h"
#include "xtimer.h"
#include "esp_common.h"
#include "esp_attr.h"
#include "irq_arch.h"
#include "esp_eth_params.h"
#include "esp_eth_netdev.h"
#include "esp32/esp_event_loop.h"
#if !defined(EMAC_PHY_SMI_MDC_PIN) || !defined(EMAC_PHY_SMI_MDIO_PIN)
#error Board definition does not provide EMAC configuration
#endif
#define SYSTEM_EVENT_ETH_RX_DONE (SYSTEM_EVENT_MAX + 1)
#define SYSTEM_EVENT_ETH_TX_DONE (SYSTEM_EVENT_MAX + 2)
#define EMAC_PHY_CLOCK_DELAY (500 * USEC_PER_MSEC) /* given in us */
#ifdef EMAC_PHY_LAN8720
#include "eth_phy/phy_lan8720.h"
#define EMAC_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
#endif
#ifdef EMAC_PHY_TLK110
#include "eth_phy/phy_tlk110.h"
#define EMAC_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config
#endif
/**
* There is only one ESP-ETH device. We define it as static device variable
* to have accesss to the device inside ESP-ETH interrupt routines which do
* not provide an argument that could be used as pointer to the ESP-ETH
* device which triggers the interrupt.
*/
static esp_eth_netdev_t _esp_eth_dev;
/* device thread stack */
static char _esp_eth_stack[ESP_ETH_STACKSIZE];
static void _eth_gpio_config_rmii(void)
{
DEBUG("%s\n", __func__);
/*
* RMII data pins are fixed:
* TXD0 = GPIO19
* TXD1 = GPIO22
* TX_EN = GPIO21
* RXD0 = GPIO25
* RXD1 = GPIO26
* CLK = GPIO0
*/
phy_rmii_configure_data_interface_pins();
/* SMI pins can be configured in board definition */
phy_rmii_smi_configure_pins(EMAC_PHY_SMI_MDC_PIN, EMAC_PHY_SMI_MDIO_PIN);
}
static esp_err_t IRAM_ATTR _eth_input_callback(void *buffer, uint16_t len, void *eb)
{
DEBUG("%s: buf=%p len=%d eb=%p\n", __func__, buffer, len, eb);
CHECK_PARAM_RET (buffer != NULL, -EINVAL);
CHECK_PARAM_RET (len <= ETHERNET_DATA_LEN, -EINVAL);
mutex_lock(&_esp_eth_dev.dev_lock);
memcpy(_esp_eth_dev.rx_buf, buffer, len);
_esp_eth_dev.rx_len = len;
_esp_eth_dev.event = SYSTEM_EVENT_ETH_RX_DONE;
_esp_eth_dev.netdev.event_callback(&_esp_eth_dev.netdev, NETDEV_EVENT_ISR);
mutex_unlock(&_esp_eth_dev.dev_lock);
return ESP_OK;
}
#if EMAC_PHY_POWER_PIN != GPIO_UNDEF
static void _esp_eth_phy_power_enable_gpio(bool enable)
{
assert(EMAC_ETHERNET_PHY_CONFIG.phy_power_enable);
if (!enable) {
EMAC_ETHERNET_PHY_CONFIG.phy_power_enable(false);
}
gpio_init(EMAC_PHY_POWER_PIN, GPIO_OUT);
gpio_write(EMAC_PHY_POWER_PIN, enable);
xtimer_usleep (USEC_PER_MSEC);
if (enable) {
EMAC_ETHERNET_PHY_CONFIG.phy_power_enable(true);
}
}
#endif
static int _esp_eth_init(netdev_t *netdev)
{
DEBUG("%s: netdev=%p\n", __func__, netdev);
esp_eth_netdev_t* dev = (esp_eth_netdev_t*)netdev;
mutex_lock(&dev->dev_lock);
esp_err_t ret = ESP_OK;
eth_config_t config = EMAC_ETHERNET_PHY_CONFIG;
/* Set configuration */
config.phy_addr = EMAC_PHY_ADDRESS;
config.clock_mode = EMAC_PHY_CLOCK_MODE;
config.gpio_config = _eth_gpio_config_rmii;
config.tcpip_input = _eth_input_callback;
#if EMAC_PHY_POWER_PIN != GPIO_UNDEF
/*
* Replace the default 'power enable' function with an example-specific
* one that toggles a power GPIO.
*/
config.phy_power_enable = phy_device_power_enable_via_gpio;
#endif
/* initialize EMAC with config */
if (ret == ESP_OK && (ret = esp_eth_init(&config)) != ESP_OK) {
LOG_TAG_ERROR("esp_eth", "initialization failed");
}
/*
* after activating clock logic it can take some time before we can
* enable EMAC
*/
xtimer_usleep (EMAC_PHY_CLOCK_DELAY);
if (ret == ESP_OK && (ret = esp_eth_enable()) != ESP_OK) {
LOG_TAG_ERROR("esp_eth", "enable failed");
}
#ifdef MODULE_NETSTATS_L2
memset(&netdev->stats, 0, sizeof(netstats_t));
#endif
mutex_unlock(&dev->dev_lock);
return (ret == ESP_OK) ? 0 : -1;
}
static int _esp_eth_send(netdev_t *netdev, const iolist_t *iolist)
{
DEBUG("%s: netdev=%p iolist=%p\n", __func__, netdev, iolist);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (iolist != NULL, -EINVAL);
esp_eth_netdev_t* dev = (esp_eth_netdev_t*)netdev;
if (!_esp_eth_dev.link_up) {
DEBUG("%s: link is down\n", __func__);
return -ENODEV;
}
mutex_lock(&dev->dev_lock);
dev->tx_len = 0;
/* load packet data into TX buffer */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
if (dev->tx_len + iol->iol_len > ETHERNET_DATA_LEN) {
mutex_unlock(&dev->dev_lock);
return -EOVERFLOW;
}
memcpy (dev->tx_buf + dev->tx_len, iol->iol_base, iol->iol_len);
dev->tx_len += iol->iol_len;
}
#if ENABLE_DEBUG
printf ("%s: send %d byte\n", __func__, dev->tx_len);
/* esp_hexdump (dev->tx_buf, dev->tx_len, 'b', 16); */
#endif
int ret = 0;
/* send the the packet to the peer(s) mac address */
if (esp_eth_tx(dev->tx_buf, dev->tx_len) == ESP_OK) {
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_success++;
netdev->stats.tx_bytes += dev->tx_len;
#endif
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
}
else {
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_failed++;
#endif
ret = -EIO;
}
mutex_unlock(&dev->dev_lock);
return ret;
}
static int _esp_eth_recv(netdev_t *netdev, void *buf, size_t len, void *info)
{
DEBUG("%s: netdev=%p buf=%p len=%u info=%p\n",
__func__, netdev, buf, len, info);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
esp_eth_netdev_t* dev = (esp_eth_netdev_t*)netdev;
mutex_lock(&dev->dev_lock);
uint8_t size = dev->rx_len;
if (!buf && !len) {
/* return the size without dropping received data */
mutex_unlock(&dev->dev_lock);
return size;
}
if (!buf && len) {
/* return the size and drop received data */
mutex_unlock(&dev->dev_lock);
dev->rx_len = 0;
return size;
}
if (buf && len && dev->rx_len) {
/* return the packet */
if (dev->rx_len > len) {
LOG_TAG_ERROR("esp_eth", "Not enough space in receive buffer "
"for %d byte\n", dev->rx_len);
mutex_unlock(&dev->dev_lock);
return -ENOBUFS;
}
#if ENABLE_DEBUG
/* esp_hexdump (dev->rx_buf, dev->rx_len, 'b', 16); */
#endif
/* copy received date and reset the receive length */
memcpy(buf, dev->rx_buf, dev->rx_len);
dev->rx_len = 0;
#ifdef MODULE_NETSTATS_L2
netdev->stats.rx_count++;
netdev->stats.rx_bytes += size;
#endif
mutex_unlock(&dev->dev_lock);
return size;
}
mutex_unlock(&dev->dev_lock);
return -EINVAL;
}
static int _esp_eth_get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
{
DEBUG("%s: netdev=%p opt=%s val=%p len=%u\n",
__func__, netdev, netopt2str(opt), val, max_len);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (val != NULL, -EINVAL);
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len == ETHERNET_ADDR_LEN);
esp_eth_get_mac((uint8_t *)val);
return ETHERNET_ADDR_LEN;
default:
return netdev_eth_get(netdev, opt, val, max_len);
}
}
static int _esp_eth_set(netdev_t *netdev, netopt_t opt, const void *val, size_t max_len)
{
DEBUG("%s: netdev=%p opt=%s val=%p len=%u\n",
__func__, netdev, netopt2str(opt), val, max_len);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (val != NULL, -EINVAL);
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len == ETHERNET_ADDR_LEN);
esp_eth_set_mac((uint8_t *)val);
return ETHERNET_ADDR_LEN;
default:
return netdev_eth_set(netdev, opt, val, max_len);
}
}
static void _esp_eth_isr(netdev_t *netdev)
{
DEBUG("%s: netdev=%p\n", __func__, netdev);
CHECK_PARAM (netdev != NULL);
esp_eth_netdev_t *dev = (esp_eth_netdev_t *) netdev;
switch (dev->event) {
case SYSTEM_EVENT_ETH_RX_DONE:
/* if data were received */
if (dev->rx_len) {
dev->netdev.event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
}
break;
case SYSTEM_EVENT_ETH_CONNECTED:
dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_UP);
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_DOWN);
break;
default:
break;
}
_esp_eth_dev.event = SYSTEM_EVENT_MAX; /* no event */
return;
}
static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_ETH_START:
DEBUG("%s: Ethernet started\n", __func__);
break;
case SYSTEM_EVENT_ETH_STOP:
DEBUG("%s: Ethernet started\n", __func__);
break;
case SYSTEM_EVENT_ETH_CONNECTED:
DEBUG("%s Ethernet link up\n", __func__);
_esp_eth_dev.link_up = true;
if (SYSTEM_EVENT_MAX) {
_esp_eth_dev.event = SYSTEM_EVENT_ETH_CONNECTED;
_esp_eth_dev.netdev.event_callback(&_esp_eth_dev.netdev, NETDEV_EVENT_ISR);
}
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
DEBUG("%s: Ethernet link up\n", __func__);
_esp_eth_dev.link_up = false;
if (SYSTEM_EVENT_MAX) {
_esp_eth_dev.event = SYSTEM_EVENT_ETH_DISCONNECTED;
_esp_eth_dev.netdev.event_callback(&_esp_eth_dev.netdev, NETDEV_EVENT_ISR);
}
break;
default:
DEBUG("%s: event=%d\n", __func__, event->event_id);
break;
}
return ESP_OK;
}
static const netdev_driver_t _esp_eth_driver =
{
.send = _esp_eth_send,
.recv = _esp_eth_recv,
.init = _esp_eth_init,
.isr = _esp_eth_isr,
.get = _esp_eth_get,
.set = _esp_eth_set,
};
extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler,
void *arg);
void auto_init_esp_eth (void)
{
LOG_TAG_INFO("esp_eth", "initializing ESP32 Ethernet MAC (EMAC) device\n");
/* initialize locking */
mutex_init(&_esp_eth_dev.dev_lock);
/* init esp system event loop */
esp_system_event_add_handler(_esp_system_event_handler, NULL);
/* set the netdev driver */
_esp_eth_dev.netdev.driver = &_esp_eth_driver;
/* initialize netdev data structure */
_esp_eth_dev.event = SYSTEM_EVENT_MAX; /* no event */
_esp_eth_dev.link_up = false;
_esp_eth_dev.rx_len = 0;
_esp_eth_dev.tx_len = 0;
_esp_eth_dev.netif = gnrc_netif_ethernet_create(_esp_eth_stack,
ESP_ETH_STACKSIZE,
ESP_ETH_PRIO,
"netdev-esp-eth",
(netdev_t *)&_esp_eth_dev);
}
#endif /* MODULE_ESP_ETH */
/**@}*/

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_eth
* @{
*
* @file
* @brief Netdev interface for the ESP32 Ethernet MAC module
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ESP_ETH_NETDEV_H
#define ESP_ETH_NETDEV_H
#include "net/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t esp_eth_driver;
/**
* @brief Device descriptor for ESP-ETH devices
*/
typedef struct
{
netdev_t netdev; /**< netdev parent struct */
uint8_t rx_len; /**< number of bytes received */
uint8_t rx_buf[ETHERNET_DATA_LEN]; /**< receive buffer */
uint8_t tx_len; /**< number of bytes in transmit buffer */
uint8_t tx_buf[ETHERNET_DATA_LEN]; /**< transmit buffer */
uint32_t event; /**< received event */
bool link_up; /**< indicates whether link is up */
gnrc_netif_t* netif; /**< reference to the corresponding netif */
mutex_t dev_lock; /**< device is already in use */
} esp_eth_netdev_t;
#ifdef __cplusplus
}
#endif
#endif /* ESP_ETH_NETDEV_H */
/** @} */

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_eth
* @{
*
* @file
* @brief Parameters for the netdev interface for ESP32 Ethernet MAC module
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ESP_ETH_PARAMS_H
#define ESP_ETH_PARAMS_H
#if defined(MODULE_ESP_ETH) || defined(DOXYGEN)
/**
* @name Set default configuration parameters for the ESP-ETH netdev driver
* @{
*/
#ifndef ESP_ETH_STACKSIZE
/** The size of the stack used for the ESP-ETH netdev driver thread */
#define ESP_ETH_STACKSIZE THREAD_STACKSIZE_DEFAULT
#endif
#ifndef ESP_ETH_PRIO
/** The priority of the ESP-ETH netdev driver thread */
#define ESP_ETH_PRIO GNRC_NETIF_PRIO
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* MODULE_ESP_ETH || DOXYGEN */
#endif /* ESP_ETH_PARAMS_H */
/**@}*/

View File

@ -0,0 +1,3 @@
MODULE=esp_now
include $(RIOTBASE)/Makefile.base

42
cpu/esp32/esp-now/dox.txt Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup cpu_esp32_esp_now ESP-NOW netdev interface
* @ingroup cpu_esp32
* @brief WiFi based ESP-NOW network device driver
*
* @author Gunar Schorcht <gunar@schorcht.net>
This module realizes a netdev interface using Espressif's ESP-NOW technology which uses the built-in WiFi module.
With ESP-NOW, the ESP32 provides a connectionless communication technology, featuring short packet transmission. It applies the IEEE802.11 Action Vendor frame technology, along with the IE function developed by Espressif, and CCMP encryption technology, realizing a secure, connectionless communication solution.
The RIOT port for ESP32 implements in module ```esp_now``` a ```netdev``` driver which uses ESP-NOW to provide a link layer interface to a meshed network of ESP32 nodes. In this network, each node can send short packets with up to 250 data bytes to all other nodes that are visible in its range.
@note Due to symbol conflicts in the ```esp_idf_wpa_supplicant_crypto``` module used by the ```esp_now``` with RIOT's ```crypto``` and ```hashes``` modules, ESP-NOW cannot be used for application that use these modules. Therefore, the module ```esp_now``` is not enabled automatically if the ```netdev_default``` module is used. Instead, the application has to add the ```esp_now``` module in its makefile when needed.<br>
```
USEMODULE += esp_now
```
For ESP-NOW, ESP32 nodes are used in WiFi SoftAP + Station mode to advertise their SSID and become visible to other ESP32 nodes. The SSID of an ESP32 node is the concatenation of the prefix ```RIOT_ESP_``` with the MAC address of its SoftAP WiFi interface. The driver periodically scans all visible ESP32 nodes.
The following parameters are defined for ESP-NOW nodes. These parameters can be overriden by [application-specific board configurations](#esp32_application_specific_board_configuration).
<center>
Parameter | Default | Description
:---------|:--------|:-----------
ESP_NOW_SCAN_PERIOD | 10000000UL | Defines the period in us at which an node scans for other nodes in its range. The default period is 10 s.
ESP_NOW_SOFT_AP_PASSPHRASE | ThisistheRIOTporttoESP | Defines the passphrase (max. 64 chars) that is used for the SoftAP interface of an nodes. It has to be same for all nodes in one network.
ESP_NOW_CHANNEL | 6 | Defines the channel that is used as the broadcast medium by all nodes together.
ESP_NOW_KEY | NULL | Defines a key that is used for encrypted communication between nodes. If it is NULL, encryption is disabled. The key has to be of type ```uint8_t[16]``` and has to be exactly 16 bytes long.
</center>
*/

View File

@ -0,0 +1,872 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_now
* @{
*
* @file
* @brief Netdev interface for the ESP-NOW WiFi P2P protocol
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifdef MODULE_ESP_NOW
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "log.h"
#include "tools.h"
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "net/gnrc/netif/raw.h"
#include "net/gnrc.h"
#include "xtimer.h"
#include "esp_common.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "esp_now.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "irq_arch.h"
#include "nvs_flash/include/nvs_flash.h"
#include "esp_now_params.h"
#include "esp_now_netdev.h"
#include "net/ipv6/hdr.h"
#include "net/gnrc/ipv6/nib.h"
#define ESP_NOW_UNICAST 1
#define ESP_NOW_WIFI_STA 1
#define ESP_NOW_WIFI_SOFTAP 2
#define ESP_NOW_WIFI_STA_SOFTAP (ESP_NOW_WIFI_STA + ESP_NOW_WIFI_SOFTAP)
#define ESP_NOW_AP_PREFIX "RIOT_ESP_"
#define ESP_NOW_AP_PREFIX_LEN (strlen(ESP_NOW_AP_PREFIX))
/**
* There is only one ESP-NOW device. We define it as static device variable
* to have accesss to the device inside ESP-NOW interrupt routines which do
* not provide an argument that could be used as pointer to the ESP-NOW
* device which triggers the interrupt.
*/
static esp_now_netdev_t _esp_now_dev;
static const netdev_driver_t _esp_now_driver;
/* device thread stack */
static char _esp_now_stack[ESP_NOW_STACKSIZE];
static inline int _get_mac_from_iid(uint8_t *iid, uint8_t *mac)
{
CHECK_PARAM_RET (iid != NULL, -EINVAL);
CHECK_PARAM_RET (mac != NULL, -EINVAL);
/* interface id according to */
/* https://tools.ietf.org/html/rfc4291#section-2.5.1 */
mac[0] = iid[0] ^ 0x02; /* invert bit1 */
mac[1] = iid[1];
mac[2] = iid[2];
mac[3] = iid[5];
mac[4] = iid[6];
mac[5] = iid[7];
return 0;
}
#if ESP_NOW_UNICAST
static xtimer_t _esp_now_scan_peers_timer;
static bool _esp_now_scan_peers_done = false;
static bool _esp_now_add_peer (uint8_t* bssid, uint8_t channel, uint8_t* key)
{
if (esp_now_is_peer_exist(bssid)) {
return false;
}
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, bssid, ESP_NOW_ETH_ALEN);
peer.channel = channel;
peer.ifidx = ESP_IF_WIFI_AP;
if (esp_now_params.key) {
peer.encrypt = true;
memcpy(peer.lmk, esp_now_params.key, ESP_NOW_KEY_LEN);
}
esp_err_t ret = esp_now_add_peer(&peer);
DEBUG("esp_now_add_peer node %02x:%02x:%02x:%02x:%02x:%02x "
"added with return value %d\n",
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], ret);
return (ret == ESP_OK);
}
#define ESP_NOW_APS_BLOCK_SIZE 8 /* has to be power of two */
static wifi_ap_record_t* aps = NULL;
static uint32_t aps_size = 0;
static void IRAM_ATTR esp_now_scan_peers_done (void)
{
mutex_lock(&_esp_now_dev.dev_lock);
esp_err_t ret;
uint16_t ap_num;
ret = esp_wifi_scan_get_ap_num(&ap_num);
DEBUG("wifi_scan_get_ap_num ret=%d num=%d\n", ret ,ap_num);
if (ret == ESP_OK && ap_num) {
uint32_t state;
/* reallocation of memory must not be disturbed */
critical_enter_var(state);
/* allocate memory for APs record list blockwise and fetch them the list */
if (ap_num > aps_size) {
if (aps) {
/* free allocated AP record list memory */
aps_size = 0;
free (aps);
}
/* allocate new memory */
aps_size = (ap_num & ~(ESP_NOW_APS_BLOCK_SIZE - 1)) + ESP_NOW_APS_BLOCK_SIZE;
aps = malloc(sizeof(wifi_ap_record_t) * aps_size);
ap_num = aps_size;
}
critical_exit_var(state);
ret = esp_wifi_scan_get_ap_records(&ap_num, aps);
DEBUG("wifi_scan_get_aps ret=%d num=%d\n", ret, ap_num);
critical_enter_var(state);
/* iterate over APs records */
for (uint16_t i = 0; i < ap_num; i++) {
/* check whether the AP is an ESP_NOW node which is not already a peer */
if (strncmp((char*)aps[i].ssid, ESP_NOW_AP_PREFIX, ESP_NOW_AP_PREFIX_LEN) == 0 &&
!esp_now_is_peer_exist(aps[i].bssid)) {
/* add the AP as peer */
_esp_now_add_peer(aps[i].bssid, aps[i].primary, esp_now_params.key);
}
}
critical_exit_var(state);
}
#if ENABLE_DEBUG
esp_now_peer_num_t peer_num;
esp_now_get_peer_num (&peer_num);
DEBUG("associated peers total=%d, encrypted=%d\n",
peer_num.total_num, peer_num.encrypt_num);
#endif
_esp_now_scan_peers_done = true;
/* set the time for next scan */
xtimer_set (&_esp_now_scan_peers_timer, esp_now_params.scan_period);
mutex_unlock(&_esp_now_dev.dev_lock);
}
static void esp_now_scan_peers_start (void)
{
DEBUG("%s\n", __func__);
wifi_scan_config_t scan_cfg = {
.ssid = NULL,
.bssid = NULL,
.channel = esp_now_params.channel,
.show_hidden = true,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time.active.min = 0,
.scan_time.active.max = 120 /* TODO tune value */
};
esp_wifi_scan_start(&scan_cfg, false);
}
#define ESP_NOW_EVENT_SCAN_PEERS 1
static kernel_pid_t esp_now_event_handler_pid;
char esp_now_event_handler_stack [THREAD_STACKSIZE_DEFAULT];
static void *esp_now_event_handler (void *arg)
{
msg_t event;
while (1) {
msg_receive(&event);
switch (event.content.value) {
case ESP_NOW_EVENT_SCAN_PEERS:
esp_now_scan_peers_start ();
break;
}
}
return NULL;
}
static void IRAM_ATTR esp_now_scan_peers_timer_cb (void* arg)
{
DEBUG("%s\n", __func__);
static msg_t event = { .content = { .value = ESP_NOW_EVENT_SCAN_PEERS } };
msg_send(&event, esp_now_event_handler_pid);
}
#else
static const uint8_t _esp_now_mac[6] = { 0x82, 0x73, 0x79, 0x84, 0x79, 0x83 }; /* RIOTOS */
#endif /* ESP_NOW_UNICAST */
static IRAM_ATTR void esp_now_recv_cb (const uint8_t *mac, const uint8_t *data, int len)
{
#if ESP_NOW_UNICAST
if (!_esp_now_scan_peers_done) {
/* if peers are not scanned, we cannot receive anything */
return;
}
#endif
if (_esp_now_dev.rx_len) {
/* there is already a packet in receive buffer, we drop the new one */
return;
}
critical_enter();
#if 0 /* don't printf anything in ISR */
printf ("%s\n", __func__);
printf ("%s: received %d byte from %02x:%02x:%02x:%02x:%02x:%02x\n",
__func__, len,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
esp_hexdump (data, len, 'b', 16);
#endif
_esp_now_dev.rx_len = len;
memcpy(_esp_now_dev.rx_buf, data, len);
memcpy(_esp_now_dev.rx_mac, mac, ESP_NOW_ADDR_LEN);
if (_esp_now_dev.netdev.event_callback) {
_esp_now_dev.netdev.event_callback((netdev_t*)&_esp_now_dev, NETDEV_EVENT_ISR);
}
critical_exit();
}
static int _esp_now_sending = 0;
static void IRAM_ATTR esp_now_send_cb (const uint8_t *mac, esp_now_send_status_t status)
{
DEBUG("%s: sent to %02x:%02x:%02x:%02x:%02x:%02x with status %d\n",
__func__,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], status);
if (_esp_now_sending) {
_esp_now_sending--;
}
}
/*
* Event handler for esp system events.
*/
static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
DEBUG("%s WiFi started\n", __func__);
break;
case SYSTEM_EVENT_SCAN_DONE:
DEBUG("%s WiFi scan done\n", __func__);
esp_now_scan_peers_done();
break;
default:
break;
}
return ESP_OK;
}
/**
* Default WiFi configuration, overwrite them with your configs
*/
#ifndef CONFIG_WIFI_STA_SSID
#define CONFIG_WIFI_STA_SSID "RIOT_AP"
#endif
#ifndef CONFIG_WIFI_STA_PASSWORD
#define CONFIG_WIFI_STA_PASSWORD "ThisistheRIOTporttoESP"
#endif
#ifndef CONFIG_WIFI_STA_CHANNEL
#define CONFIG_WIFI_STA_CHANNEL 0
#endif
#define CONFIG_WIFI_STA_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
#define CONFIG_WIFI_STA_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
#define CONFIG_WIFI_STA_RSSI -127
#define CONFIG_WIFI_STA_AUTHMODE WIFI_AUTH_WPA_WPA2_PSK
#define CONFIG_WIFI_AP_PASSWORD ESP_NOW_SOFT_AP_PASSPHRASE
#define CONFIG_WIFI_AP_CHANNEL ESP_NOW_CHANNEL
#define CONFIG_WIFI_AP_AUTH WIFI_AUTH_WPA_WPA2_PSK
#define CONFIG_WIFI_AP_HIDDEN false
#define CONFIG_WIFI_AP_BEACON 100
#define CONFIG_WIFI_AP_MAX_CONN 4
extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler,
void *arg);
static void esp_now_setup (esp_now_netdev_t* dev)
{
DEBUG("%s: %p\n", __func__, dev);
/*
* Init the WiFi driver. TODO It is not only required before ESP_NOW is
* initialized but also before other WiFi functions are used. Once other
* WiFi functions are realized it has to be moved to a more common place.
*/
extern portMUX_TYPE g_intr_lock_mux;
mutex_init(&g_intr_lock_mux);
esp_system_event_add_handler (_esp_system_event_handler, NULL);
esp_err_t result;
#if CONFIG_ESP32_WIFI_NVS_ENABLED
result = nvs_flash_init();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now",
"nfs_flash_init failed with return value %d\n", result);
return;
}
#endif
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
result = esp_wifi_init(&cfg);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now",
"esp_wifi_init failed with return value %d\n", result);
return;
}
#ifdef CONFIG_WIFI_COUNTRY
/* TODO */
#endif
/* we use predefined station configuration */
wifi_config_t wifi_config_sta = {
.sta = {
.ssid = CONFIG_WIFI_STA_SSID,
.password = CONFIG_WIFI_STA_PASSWORD,
.channel = CONFIG_WIFI_STA_CHANNEL,
.scan_method = CONFIG_WIFI_STA_SCAN_METHOD,
.sort_method = CONFIG_WIFI_STA_SORT_METHOD,
.threshold.rssi = CONFIG_WIFI_STA_RSSI,
.threshold.authmode = CONFIG_WIFI_STA_AUTHMODE
}
};
/* get SoftAP interface mac address and store it as device addresss */
esp_read_mac(dev->addr, ESP_MAC_WIFI_SOFTAP);
/* prepare the ESP_NOW configuration for SoftAP */
wifi_config_t wifi_config_ap = {};
strcpy ((char*)wifi_config_ap.ap.password, esp_now_params.softap_pass);
sprintf((char*)wifi_config_ap.ap.ssid, "%s%02x%02x%02x%02x%02x%02x",
ESP_NOW_AP_PREFIX,
dev->addr[0], dev->addr[1], dev->addr[2],
dev->addr[3], dev->addr[4], dev->addr[5]);
wifi_config_ap.ap.ssid_len = strlen((char*)wifi_config_ap.ap.ssid);
wifi_config_ap.ap.channel = esp_now_params.channel;
wifi_config_ap.ap.authmode = CONFIG_WIFI_AP_AUTH;
wifi_config_ap.ap.ssid_hidden = CONFIG_WIFI_AP_HIDDEN;
wifi_config_ap.ap.max_connection = CONFIG_WIFI_AP_MAX_CONN;
wifi_config_ap.ap.beacon_interval = CONFIG_WIFI_AP_BEACON;
/* set the WiFi interface to Station + SoftAP mode without DHCP */
result = esp_wifi_set_mode(WIFI_MODE_STA | WIFI_MODE_AP);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now",
"esp_wifi_set_mode failed with return value %d\n",
result);
return;
}
/* set the Station and SoftAP configuration */
result = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now", "esp_wifi_set_config station failed with "
"return value %d\n", result);
return;
}
result = esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config_ap);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now",
"esp_wifi_set_mode softap failed with return value %d\n",
result);
return;
}
/* start the WiFi driver */
result = esp_wifi_start();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now",
"esp_wifi_start failed with return value %d\n", result);
return;
}
#if ESP_NOW_UNICAST==0 /* TODO */
/* all ESP-NOW nodes get the shared mac address on their station interface */
wifi_set_macaddr(STATION_IF, (uint8_t*)_esp_now_mac);
#endif
/* set the netdev driver */
dev->netdev.driver = &_esp_now_driver;
/* initialize netdev data structure */
dev->peers_all = 0;
dev->peers_enc = 0;
mutex_init(&dev->dev_lock);
/* initialize ESP-NOW and register callback functions */
result = esp_now_init();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_now", "esp_now_init failed with return value %d\n",
result);
return;
}
esp_now_register_send_cb (esp_now_send_cb);
esp_now_register_recv_cb (esp_now_recv_cb);
#if ESP_NOW_UNICAST
/* create the ESP_NOW event handler thread */
esp_now_event_handler_pid = thread_create(esp_now_event_handler_stack,
sizeof(esp_now_event_handler_stack),
ESP_NOW_PRIO + 1,
THREAD_CREATE_WOUT_YIELD |
THREAD_CREATE_STACKTEST,
esp_now_event_handler,
NULL, "net-esp-now-event");
/* timer for peer scan initialization */
_esp_now_scan_peers_done = false;
_esp_now_scan_peers_timer.callback = &esp_now_scan_peers_timer_cb;
_esp_now_scan_peers_timer.arg = dev;
/* execute the first scan */
esp_now_scan_peers_done();
#else /* ESP_NOW_UNICAST */
#if 0
int res = esp_now_add_peer((uint8_t*)_esp_now_mac, ESP_NOW_ROLE_COMBO,
esp_now_params.channel, NULL, 0);
DEBUG("%s: multicast node added %d\n", __func__, res);
#endif
#endif /* ESP_NOW_UNICAST */
}
static int _init(netdev_t *netdev)
{
DEBUG("%s: %p\n", __func__, netdev);
#ifdef MODULE_NETSTATS_L2
memset(&netdev->stats, 0x00, sizeof(netstats_t));
#endif
return 0;
}
static int _send(netdev_t *netdev, const iolist_t *iolist)
{
#if ESP_NOW_UNICAST
if (!_esp_now_scan_peers_done) {
return -ENODEV;
}
#endif
DEBUG("%s: %p %p\n", __func__, netdev, iolist);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (iolist != NULL, -EINVAL);
esp_now_netdev_t* dev = (esp_now_netdev_t*)netdev;
mutex_lock(&dev->dev_lock);
dev->tx_len = 0;
/* load packet data into TX buffer */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
if (dev->tx_len + iol->iol_len > ESP_NOW_MAX_SIZE) {
mutex_unlock(&dev->dev_lock);
return -EOVERFLOW;
}
memcpy (dev->tx_buf + dev->tx_len, iol->iol_base, iol->iol_len);
dev->tx_len += iol->iol_len;
}
#if ENABLE_DEBUG
printf ("%s: send %d byte\n", __func__, dev->tx_len);
/* esp_hexdump (dev->tx_buf, dev->tx_len, 'b', 16); */
#endif
_esp_now_sending = 1;
uint8_t* _esp_now_dst = 0;
#if ESP_NOW_UNICAST
ipv6_hdr_t* ipv6_hdr = (ipv6_hdr_t*)dev->tx_buf;
uint8_t _esp_now_dst_from_iid[6];
if (ipv6_hdr->dst.u8[0] == 0xff) {
/* packets to multicast prefix ff::/8 are sent to all peers */
DEBUG("multicast to all peers\n");
_esp_now_dst = 0;
_esp_now_sending = dev->peers_all;
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_mcast_count++;
#endif
}
else if ((byteorder_ntohs(ipv6_hdr->dst.u16[0]) & 0xffc0) == 0xfe80) {
/* for link local addresses fe80::/10, the MAC address is derived from dst address */
_get_mac_from_iid(&ipv6_hdr->dst.u8[8], _esp_now_dst_from_iid);
DEBUG("link local to %02x:%02x:%02x:%02x:%02x:%02x\n",
_esp_now_dst_from_iid[0], _esp_now_dst_from_iid[1],
_esp_now_dst_from_iid[2], _esp_now_dst_from_iid[3],
_esp_now_dst_from_iid[4], _esp_now_dst_from_iid[5]);
_esp_now_dst = _esp_now_dst_from_iid;
_esp_now_sending = 1;
}
else {
#ifdef MODULE_GNRC_IPV6_NIB
/* for other addresses, try to find an entry in NIB cache */
gnrc_ipv6_nib_nc_t nce;
int ret = gnrc_ipv6_nib_get_next_hop_l2addr (&ipv6_hdr->dst, dev->netif,
NULL, &nce);
if (ret == 0) {
/* entry was found in NIB, use MAC adress from the NIB cache entry */
DEBUG("global, next hop to neighbor %02x:%02x:%02x:%02x:%02x:%02x\n",
nce.l2addr[0], nce.l2addr[1], nce.l2addr[2],
nce.l2addr[3], nce.l2addr[4], nce.l2addr[5]);
_esp_now_dst = nce.l2addr;
_esp_now_sending = 1;
}
else {
#endif
/* entry was not found in NIB, send to all peers */
DEBUG("global, no neibhbor found, multicast to all peers\n");
_esp_now_dst = 0;
_esp_now_sending = dev->peers_all;
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_mcast_count++;
#endif
#ifdef MODULE_GNRC_IPV6_NIB
}
#endif
}
#else /* ESP_NOW_UNICAST */
ipv6_hdr_t* ipv6_hdr = (ipv6_hdr_t*)dev->tx_buf;
uint8_t _esp_now_dst_from_iid[6];
_esp_now_dst = (uint8_t*)_esp_now_mac;
_esp_now_sending = 1;
if (ipv6_hdr->dst.u8[0] == 0xff) {
/* packets to multicast prefix ff::/8 are sent to all peers */
DEBUG("multicast to all peers\n");
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_mcast_count++;
#endif
}
else if ((byteorder_ntohs(ipv6_hdr->dst.u16[0]) & 0xffc0) == 0xfe80) {
/* for link local addresses fe80::/10, the MAC address is derived from dst address */
_get_mac_from_iid(&ipv6_hdr->dst.u8[8], _esp_now_dst_from_iid);
DEBUG("link local to %02x:%02x:%02x:%02x:%02x:%02x\n",
_esp_now_dst_from_iid[0], _esp_now_dst_from_iid[1],
_esp_now_dst_from_iid[2], _esp_now_dst_from_iid[3],
_esp_now_dst_from_iid[4], _esp_now_dst_from_iid[5]);
if (esp_now_is_peer_exist(_esp_now_dst_from_iid) > 0) {
_esp_now_dst = _esp_now_dst_from_iid;
}
}
else
{
/* for other addresses, try to find an entry in NIB cache */
gnrc_ipv6_nib_nc_t nce;
int ret = gnrc_ipv6_nib_get_next_hop_l2addr (&ipv6_hdr->dst, dev->netif,
NULL, &nce);
if (ret == 0 && esp_now_is_peer_exist(nce.l2addr) > 0) {
/* entry was found in NIB, use MAC adress from the NIB cache entry */
DEBUG("global, next hop to neighbor %02x:%02x:%02x:%02x:%02x:%02x\n",
nce.l2addr[0], nce.l2addr[1], nce.l2addr[2],
nce.l2addr[3], nce.l2addr[4], nce.l2addr[5]);
_esp_now_dst = nce.l2addr;
}
else {
/* entry was not found in NIB, send to all peers */
DEBUG("global, no neibhbor found, multicast to all peers\n");
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_mcast_count++;
#endif
}
}
#endif /* ESP_NOW_UNICAST */
if (_esp_now_dst) {
DEBUG("%s: send to esp_now addr %02x:%02x:%02x:%02x:%02x:%02x\n", __func__,
_esp_now_dst[0], _esp_now_dst[1], _esp_now_dst[2],
_esp_now_dst[3], _esp_now_dst[4], _esp_now_dst[5]);
}
/* send the the packet to the peer(s) mac address */
if (esp_now_send (_esp_now_dst, dev->tx_buf, dev->tx_len) == 0) {
while (_esp_now_sending > 0) {
thread_yield_higher();
}
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_bytes += dev->tx_len;
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
#endif
mutex_unlock(&dev->dev_lock);
return dev->tx_len;
}
else {
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_failed++;
#endif
}
mutex_unlock(&dev->dev_lock);
return -EIO;
}
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
{
DEBUG("%s: %p %p %u %p\n", __func__, netdev, buf, len, info);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
esp_now_netdev_t* dev = (esp_now_netdev_t*)netdev;
mutex_lock(&dev->dev_lock);
uint8_t size = dev->rx_len;
if (!buf && !len) {
/* return the size without dropping received data */
mutex_unlock(&dev->dev_lock);
return size;
}
if (!buf && len) {
/* return the size and drop received data */
mutex_unlock(&dev->dev_lock);
dev->rx_len = 0;
return size;
}
if (buf && len && dev->rx_len) {
if (dev->rx_len > len) {
DEBUG("[esp_now] No space in receive buffers\n");
mutex_unlock(&dev->dev_lock);
return -ENOBUFS;
}
#if ENABLE_DEBUG
printf ("%s: received %d byte from %02x:%02x:%02x:%02x:%02x:%02x\n",
__func__, dev->rx_len,
dev->rx_mac[0], dev->rx_mac[1], dev->rx_mac[2],
dev->rx_mac[3], dev->rx_mac[4], dev->rx_mac[5]);
/* esp_hexdump (dev->rx_buf, dev->rx_len, 'b', 16); */
#endif
if (esp_now_is_peer_exist(dev->rx_mac) <= 0) {
_esp_now_add_peer(dev->rx_mac, esp_now_params.channel, esp_now_params.key);
}
memcpy(buf, dev->rx_buf, dev->rx_len);
dev->rx_len = 0;
#ifdef MODULE_NETSTATS_L2
netdev->stats.rx_count++;
netdev->stats.rx_bytes += size;
#endif
mutex_unlock(&dev->dev_lock);
return size;
}
mutex_unlock(&dev->dev_lock);
return -EINVAL;
}
static inline int _get_iid(esp_now_netdev_t *dev, eui64_t *value, size_t max_len)
{
CHECK_PARAM_RET (max_len >= sizeof(eui64_t), -EOVERFLOW);
/* interface id according to */
/* https://tools.ietf.org/html/rfc4291#section-2.5.1 */
value->uint8[0] = dev->addr[0] ^ 0x02; /* invert bit1 */
value->uint8[1] = dev->addr[1];
value->uint8[2] = dev->addr[2];
value->uint8[3] = 0xff;
value->uint8[4] = 0xfe;
value->uint8[5] = dev->addr[3];
value->uint8[6] = dev->addr[4];
value->uint8[7] = dev->addr[5];
return sizeof(eui64_t);
}
static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
{
DEBUG("%s: %s %p %p %u\n", __func__, netopt2str(opt), netdev, val, max_len);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (val != NULL, -EINVAL);
esp_now_netdev_t *dev = (esp_now_netdev_t *)netdev;
int res = -ENOTSUP;
switch (opt) {
case NETOPT_DEVICE_TYPE:
CHECK_PARAM_RET (max_len >= sizeof(uint16_t), -EOVERFLOW);
*((uint16_t *)val) = NETDEV_TYPE_RAW;
res = sizeof(uint16_t);
break;
#ifdef MODULE_GNRC
case NETOPT_PROTO:
CHECK_PARAM_RET(max_len == sizeof(gnrc_nettype_t), -EOVERFLOW);
*((gnrc_nettype_t *)val) = dev->proto;
res = sizeof(gnrc_nettype_t);
break;
#endif
case NETOPT_MAX_PACKET_SIZE:
CHECK_PARAM_RET (max_len >= sizeof(uint16_t), -EOVERFLOW);
*((uint16_t *)val) = ESP_NOW_MAX_SIZE;
res = sizeof(uint16_t);
break;
case NETOPT_ADDR_LEN:
case NETOPT_SRC_LEN:
CHECK_PARAM_RET (max_len >= sizeof(uint16_t), -EOVERFLOW);
*((uint16_t *)val) = sizeof(dev->addr);
res = sizeof(uint16_t);
break;
case NETOPT_ADDRESS:
CHECK_PARAM_RET (max_len >= sizeof(dev->addr), -EOVERFLOW);
memcpy(val, dev->addr, sizeof(dev->addr));
res = sizeof(dev->addr);
break;
case NETOPT_IPV6_IID:
res = _get_iid(dev, val, max_len);
break;
#ifdef MODULE_NETSTATS_L2
case NETOPT_STATS:
CHECK_PARAM_RET (max_len == sizeof(uintptr_t), -EOVERFLOW);
*((netstats_t **)val) = &netdev->stats;
res = sizeof(uintptr_t);
break;
#endif
default:
DEBUG("%s: %s not supported\n", __func__, netopt2str(opt));
break;
}
return res;
}
static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t max_len)
{
DEBUG("%s: %s %p %p %u\n", __func__, netopt2str(opt), netdev, val, max_len);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (val != NULL, -EINVAL);
esp_now_netdev_t *dev = (esp_now_netdev_t *) netdev;
int res = -ENOTSUP;
switch (opt) {
#ifdef MODULE_GNRC
case NETOPT_PROTO:
CHECK_PARAM_RET(max_len == sizeof(gnrc_nettype_t), -EOVERFLOW);
dev->proto = *((gnrc_nettype_t *)val);
res = sizeof(gnrc_nettype_t);
break;
#endif
case NETOPT_ADDRESS:
CHECK_PARAM_RET(max_len >= sizeof(dev->addr), -EOVERFLOW);
memcpy(dev->addr, val, sizeof(dev->addr));
res = sizeof(dev->addr);
break;
default:
DEBUG("%s: %s not supported\n", __func__, netopt2str(opt));
break;
}
return res;
}
static void _isr(netdev_t *netdev)
{
DEBUG("%s: %p\n", __func__, netdev);
CHECK_PARAM (netdev != NULL);
esp_now_netdev_t *dev = (esp_now_netdev_t *) netdev;
dev->netdev.event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
return;
}
static const netdev_driver_t _esp_now_driver =
{
.send = _send,
.recv = _recv,
.init = _init,
.isr = _isr,
.get = _get,
.set = _set,
};
void auto_init_esp_now (void)
{
LOG_TAG_INFO("esp_now", "initializing ESP-NOW device\n");
esp_now_setup(&_esp_now_dev);
_esp_now_dev.netif = gnrc_netif_raw_create(_esp_now_stack,
ESP_NOW_STACKSIZE, ESP_NOW_PRIO,
"net-esp-now",
(netdev_t *)&_esp_now_dev);
}
#endif /* MODULE_ESP_NOW */
/** @} */

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_now
* @{
*
* @file
* @brief Netdev interface for the ESP-NOW WiFi P2P protocol
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ESP_NOW_NETDEV_H
#define ESP_NOW_NETDEV_H
#include "net/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Maximum packet size that can be used with ESP-NOW
*/
#define ESP_NOW_MAX_SIZE (250)
/**
* @brief Length of ESP-NOW addresses
*/
#define ESP_NOW_ADDR_LEN ETHERNET_ADDR_LEN
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t esp_now_driver;
/**
* @brief Device descriptor for ESP-NOW devices
*/
typedef struct
{
netdev_t netdev; /**< netdev parent struct */
uint8_t addr[ESP_NOW_ADDR_LEN]; /**< device addr (MAC address) */
uint8_t rx_len; /**< number of bytes received */
uint8_t rx_buf[ESP_NOW_MAX_SIZE]; /**< receive buffer */
uint8_t rx_mac[ESP_NOW_ADDR_LEN]; /**< source address */
uint8_t tx_len; /**< number of bytes in transmit buffer */
uint8_t tx_buf[ESP_NOW_MAX_SIZE]; /**< transmit buffer */
gnrc_netif_t* netif; /**< reference to the corresponding netif */
#ifdef MODULE_GNRC
gnrc_nettype_t proto; /**< protocol for upper layer */
#endif
uint8_t peers_all; /**< number of peers reachable */
uint8_t peers_enc; /**< number of encrypted peers */
mutex_t dev_lock; /**< device is already in use */
} esp_now_netdev_t;
#ifdef __cplusplus
}
#endif
#endif /* ESP_NOW_NETDEV_H */
/** @} */

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_now
* @{
*
* @file
* @brief Parameters for the netdev interface for ESP-NOW WiFi P2P
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ESP_NOW_PARAMS_H
#define ESP_NOW_PARAMS_H
#if defined(MODULE_ESP_NOW) || defined(DOXYGEN)
/**
* @name Set default configuration parameters for the ESP-NOW netdev driver
* @{
*/
#ifndef ESP_NOW_STACKSIZE
/** The size of the stack used for the ESP-NOW netdev driver thread */
#define ESP_NOW_STACKSIZE THREAD_STACKSIZE_DEFAULT
#endif
#ifndef ESP_NOW_PRIO
/** The priority of the ESP-NOW netdev driver thread */
#define ESP_NOW_PRIO GNRC_NETIF_PRIO
#endif
#ifndef ESP_NOW_SCAN_PERIOD
/** Period in us at which the node scans for other nodes in its range */
#define ESP_NOW_SCAN_PERIOD (10000000UL)
#endif
#ifndef ESP_NOW_SOFT_AP_PASS
/** Passphrase (max. 64 chars) used for the SoftAP interface of the nodes */
#define ESP_NOW_SOFT_AP_PASS "ThisistheRIOTporttoESP"
#endif
#ifndef ESP_NOW_CHANNEL
/** Channel used as broadcast medium by all ESP-NOW nodes together */
#define ESP_NOW_CHANNEL (6)
#endif
#ifndef ESP_NOW_KEY
/**
* @brief Key used for the communication between ESP-NOW nodes
*
* The key has to be defined to enable encrypted communication between ESP-NOW
* nodes. The key has to be of type *uint8_t [16]* and has to be exactly
* 16 bytes long. If the key is NULL (the default) communication is not
* encrypted.
*
* Please note: If encrypted communication is used, a maximum of 6 nodes can
* communicate with each other, while in unencrypted mode, up to 20 nodes can
* communicate.
*/
#define ESP_NOW_KEY (NULL)
#endif
#ifndef ESP_NOW_PARAMS
#define ESP_NOW_PARAMS { .key = ESP_NOW_KEY, \
.scan_period = ESP_NOW_SCAN_PERIOD, \
.softap_pass = ESP_NOW_SOFT_AP_PASS, \
.channel = ESP_NOW_CHANNEL }
#endif
/**
* @brief struct holding all params needed for device initialization
*/
typedef struct
{
uint8_t* key; /**< key of type uint8_t [16] or NULL (no encryption) */
uint32_t scan_period; /**< Period at which the node scans for other nodes */
char* softap_pass; /**< Passphrase used for the SoftAP interface */
uint8_t channel; /**< Channel used for ESP-NOW nodes */
} esp_now_params_t;
#ifdef __cplusplus
extern "C" {
#endif
static const esp_now_params_t esp_now_params = ESP_NOW_PARAMS;
#ifdef __cplusplus
}
#endif
#endif /* MODULE_ESP_NOW || DOXYGEN */
#endif /* ESP_NOW_PARAMS_H */
/**@}*/

View File

@ -0,0 +1,3 @@
MODULE=esp_wifi
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,18 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup cpu_esp32_esp_wifi ESP WiFi netdev interface
* @ingroup cpu_esp32
* @brief WiFi AP-based network device driver
*
* This module realizes a netdev interface using the built-in
* WiFi module and AP infrastructure.
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/

View File

@ -0,0 +1,434 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_wifi
* @{
*
* @file
* @brief Netdev interface for the ESP WiFi AP-based communication
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifdef MODULE_ESP_WIFI
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "log.h"
#include "tools.h"
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "net/gnrc/netif/ethernet.h"
#include "net/gnrc/netif/raw.h"
#include "net/gnrc.h"
#include "net/ethernet.h"
#include "net/netdev/eth.h"
#include "xtimer.h"
#include "esp_common.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "esp_now.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_internal.h"
#include "irq_arch.h"
#include "nvs_flash/include/nvs_flash.h"
#include "esp_wifi_params.h"
#include "esp_wifi_netdev.h"
#include "net/ipv6/hdr.h"
#include "net/gnrc/ipv6/nib.h"
#define SYSTEM_EVENT_WIFI_RX_DONE (SYSTEM_EVENT_MAX + 3)
#define SYSTEM_EVENT_WIFI_TX_DONE (SYSTEM_EVENT_MAX + 4)
/**
* There is only one ESP WiFi device. We define it as static device variable
* to have accesss to the device inside ESP WiFi interrupt routines which do
* not provide an argument that could be used as pointer to the ESP WiFi
* device which triggers the interrupt.
*/
static esp_wifi_netdev_t _esp_wifi_dev;
static const netdev_driver_t _esp_wifi_driver;
/* device thread stack */
static char _esp_wifi_stack[ESP_WIFI_STACKSIZE];
extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler,
void *arg);
esp_err_t _esp_wifi_rx_cb(void *buffer, uint16_t len, void *eb)
{
DEBUG("%s: buf=%p len=%d eb=%p\n", __func__, buffer, len, eb);
CHECK_PARAM_RET (buffer != NULL, -EINVAL);
CHECK_PARAM_RET (len <= ETHERNET_DATA_LEN, -EINVAL);
mutex_lock(&_esp_wifi_dev.dev_lock);
memcpy(_esp_wifi_dev.rx_buf, buffer, len);
_esp_wifi_dev.rx_len = len;
_esp_wifi_dev.event = SYSTEM_EVENT_WIFI_RX_DONE;
_esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);
mutex_unlock(&_esp_wifi_dev.dev_lock);
return ESP_OK;
}
/*
* Event handler for esp system events.
*/
static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
DEBUG("%s WiFi started\n", __func__);
break;
case SYSTEM_EVENT_SCAN_DONE:
DEBUG("%s WiFi scan done\n", __func__);
break;
case SYSTEM_EVENT_STA_CONNECTED:
DEBUG("%s WiFi connected\n", __func__);
_esp_wifi_dev.connected = true;
_esp_wifi_dev.event = SYSTEM_EVENT_ETH_CONNECTED;
_esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
DEBUG("%s WiFi disconnected\n", __func__);
_esp_wifi_dev.connected = false;
_esp_wifi_dev.event = SYSTEM_EVENT_ETH_DISCONNECTED;
_esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR);
break;
default:
break;
}
return ESP_OK;
}
/** TODO better place
* Default WiFi configuration, overwrite them with your configs
*/
#ifndef CONFIG_WIFI_STA_SSID
#define CONFIG_WIFI_STA_SSID "RIOT_AP"
#endif
#ifndef CONFIG_WIFI_STA_PASSWORD
#define CONFIG_WIFI_STA_PASSWORD "ThisistheRIOTporttoESP"
#endif
#ifndef CONFIG_WIFI_STA_CHANNEL
#define CONFIG_WIFI_STA_CHANNEL 0
#endif
#define CONFIG_WIFI_STA_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
#define CONFIG_WIFI_STA_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
#define CONFIG_WIFI_STA_RSSI -127
#define CONFIG_WIFI_STA_AUTHMODE WIFI_AUTH_WPA_WPA2_PSK
static void esp_wifi_setup (esp_wifi_netdev_t* dev)
{
DEBUG("%s: %p\n", __func__, dev);
/*
* Init the WiFi driver. TODO It is not only required before ESP_WIFI is
* initialized but also before other WiFi functions are used. Once other
* WiFi functions are realized it has to be moved to a more common place.
*/
extern portMUX_TYPE g_intr_lock_mux;
mutex_init(&g_intr_lock_mux);
esp_system_event_add_handler (_esp_system_event_handler, NULL);
esp_err_t result;
#if CONFIG_ESP32_WIFI_NVS_ENABLED
result = nvs_flash_init();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "nfs_flash_init failed with return value %d\n", result);
return;
}
#endif
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
result = esp_wifi_init(&cfg);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_init failed with return value %d\n", result);
return;
}
#ifdef CONFIG_WIFI_COUNTRY
/* TODO */
#endif
/* we use predefined station configuration */
wifi_config_t wifi_config_sta = {
.sta = {
.ssid = CONFIG_WIFI_STA_SSID,
.password = CONFIG_WIFI_STA_PASSWORD,
.channel = CONFIG_WIFI_STA_CHANNEL,
.scan_method = CONFIG_WIFI_STA_SCAN_METHOD,
.sort_method = CONFIG_WIFI_STA_SORT_METHOD,
.threshold.rssi = CONFIG_WIFI_STA_RSSI,
.threshold.authmode = CONFIG_WIFI_STA_AUTHMODE
}
};
result = esp_wifi_set_mode(WIFI_MODE_STA);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_mode failed with return value %d\n", result);
return;
}
/* set the Station and SoftAP configuration */
result = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta);
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_set_config station failed with return value %d\n", result);
return;
}
/* start the WiFi driver */
result = esp_wifi_start();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_start failed with return value %d\n", result);
return;
}
/* register RX callback function */
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb);
/* set the netdev driver */
dev->netdev.driver = &_esp_wifi_driver;
/* initialize netdev data structure */
dev->connected = false;
mutex_init(&dev->dev_lock);
result = esp_wifi_connect();
if (result != ESP_OK) {
LOG_TAG_ERROR("esp_wifi", "esp_wifi_connect failed with return value %d\n", result);
return;
}
}
static int _esp_wifi_init(netdev_t *netdev)
{
DEBUG("%s: %p\n", __func__, netdev);
#ifdef MODULE_NETSTATS_L2
memset(&netdev->stats, 0x00, sizeof(netstats_t));
#endif
return 0;
}
static int _esp_wifi_send(netdev_t *netdev, const iolist_t *iolist)
{
DEBUG("%s: netdev=%p iolist=%p\n", __func__, netdev, iolist);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (iolist != NULL, -EINVAL);
esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)netdev;
if (!_esp_wifi_dev.connected) {
DEBUG("%s: WiFi is not connected\n", __func__);
return -ENODEV;
}
mutex_lock(&dev->dev_lock);
dev->tx_len = 0;
/* load packet data into TX buffer */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
if (dev->tx_len + iol->iol_len > ETHERNET_DATA_LEN) {
mutex_unlock(&dev->dev_lock);
return -EOVERFLOW;
}
memcpy (dev->tx_buf + dev->tx_len, iol->iol_base, iol->iol_len);
dev->tx_len += iol->iol_len;
}
#if ENABLE_DEBUG
printf ("%s: send %d byte\n", __func__, dev->tx_len);
/* esp_hexdump (dev->tx_buf, dev->tx_len, 'b', 16); */
#endif
int ret = 0;
/* send the the packet to the peer(s) mac address */
if (esp_wifi_internal_tx(ESP_IF_WIFI_STA, dev->tx_buf, dev->tx_len) == ESP_OK) {
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_success++;
netdev->stats.tx_bytes += dev->tx_len;
#endif
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
}
else {
DEBUG("%s: sending WiFi packet failed\n", __func__);
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_failed++;
#endif
ret = -EIO;
}
mutex_unlock(&dev->dev_lock);
return ret;
}
static int _esp_wifi_recv(netdev_t *netdev, void *buf, size_t len, void *info)
{
DEBUG("%s: %p %p %u %p\n", __func__, netdev, buf, len, info);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)netdev;
mutex_lock(&dev->dev_lock);
uint8_t size = dev->rx_len;
if (!buf && !len) {
/* return the size without dropping received data */
mutex_unlock(&dev->dev_lock);
return size;
}
if (!buf && len) {
/* return the size and drop received data */
mutex_unlock(&dev->dev_lock);
dev->rx_len = 0;
return size;
}
if (buf && len && dev->rx_len) {
if (dev->rx_len > len) {
DEBUG("[esp_wifi] No space in receive buffers\n");
mutex_unlock(&dev->dev_lock);
return -ENOBUFS;
}
#if ENABLE_DEBUG
/* esp_hexdump (dev->rx_buf, dev->rx_len, 'b', 16); */
#endif
/* copy received date and reset the receive length */
memcpy(buf, dev->rx_buf, dev->rx_len);
dev->rx_len = 0;
#ifdef MODULE_NETSTATS_L2
netdev->stats.rx_count++;
netdev->stats.rx_bytes += size;
#endif
mutex_unlock(&dev->dev_lock);
return size;
}
mutex_unlock(&dev->dev_lock);
return -EINVAL;
}
static int _esp_wifi_get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
{
DEBUG("%s: %s %p %p %u\n", __func__, netopt2str(opt), netdev, val, max_len);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (val != NULL, -EINVAL);
esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)netdev;
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len == ETHERNET_ADDR_LEN);
esp_wifi_get_mac(ESP_MAC_WIFI_STA,(uint8_t *)val);
return ETHERNET_ADDR_LEN;
case NETOPT_IS_WIRED:
return true;
case NETOPT_LINK_CONNECTED:
return dev->connected;
default:
return netdev_eth_get(netdev, opt, val, max_len);
}
}
static int _esp_wifi_set(netdev_t *netdev, netopt_t opt, const void *val, size_t max_len)
{
DEBUG("%s: %s %p %p %u\n", __func__, netopt2str(opt), netdev, val, max_len);
CHECK_PARAM_RET (netdev != NULL, -ENODEV);
CHECK_PARAM_RET (val != NULL, -EINVAL);
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len == ETHERNET_ADDR_LEN);
esp_wifi_set_mac(ESP_MAC_WIFI_STA, (uint8_t *)val);
return ETHERNET_ADDR_LEN;
default:
return netdev_eth_set(netdev, opt, val, max_len);
}
}
static void _esp_wifi_isr(netdev_t *netdev)
{
DEBUG("%s: %p\n", __func__, netdev);
CHECK_PARAM (netdev != NULL);
esp_wifi_netdev_t *dev = (esp_wifi_netdev_t *) netdev;
switch (dev->event) {
case SYSTEM_EVENT_WIFI_RX_DONE:
if (dev->rx_len) {
dev->netdev.event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
}
case SYSTEM_EVENT_STA_CONNECTED:
dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_UP);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_DOWN);
break;
default:
break;
}
_esp_wifi_dev.event = SYSTEM_EVENT_MAX; /* no event */
return;
}
static const netdev_driver_t _esp_wifi_driver =
{
.send = _esp_wifi_send,
.recv = _esp_wifi_recv,
.init = _esp_wifi_init,
.isr = _esp_wifi_isr,
.get = _esp_wifi_get,
.set = _esp_wifi_set,
};
void auto_init_esp_wifi (void)
{
LOG_TAG_DEBUG("esp_wifi", "initializing ESP WiFi device\n");
esp_wifi_setup(&_esp_wifi_dev);
_esp_wifi_dev.event = SYSTEM_EVENT_MAX; /* no event */
_esp_wifi_dev.netif = gnrc_netif_ethernet_create(_esp_wifi_stack,
ESP_WIFI_STACKSIZE, ESP_WIFI_PRIO,
"netdev-esp-wifi",
(netdev_t *)&_esp_wifi_dev);
}
#endif /* MODULE_ESP_WIFI */
/**@}*/

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_wifi
* @{
*
* @file
* @brief Netdev interface for the ESP WiFi AP-based communication
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ESP_WIFI_NETDEV_H
#define ESP_WIFI_NETDEV_H
#include "net/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t esp_wifi_driver;
/**
* @brief Device descriptor for ESP WiFi devices
*/
typedef struct
{
netdev_t netdev; /**< netdev parent struct */
uint8_t rx_len; /**< number of bytes received */
uint8_t rx_buf[ETHERNET_DATA_LEN]; /**< receive buffer */
uint8_t tx_len; /**< number of bytes in transmit buffer */
uint8_t tx_buf[ETHERNET_DATA_LEN]; /**< transmit buffer */
uint32_t event; /**< received event */
bool connected; /**< indicates whether connected to AP */
gnrc_netif_t* netif; /**< reference to the corresponding netif */
mutex_t dev_lock; /**< device is already in use */
} esp_wifi_netdev_t;
#ifdef __cplusplus
}
#endif
#endif /* ESP_WIFI_NETDEV_H */
/** @} */

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32_esp_wifi
* @{
*
* @file
* @brief Parameters for the netdev interface for ESP WiFi module
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef ESP_WIFI_PARAMS_H
#define ESP_WIFI_PARAMS_H
#if defined(MODULE_ESP_WIFI) || defined(DOXYGEN)
/**
* @name Set default configuration parameters for the ESP WiFi netdev driver
* @{
*/
#ifndef ESP_WIFI_STACKSIZE
/** The size of the stack used for the ESP WiFi netdev driver thread */
#define ESP_WIFI_STACKSIZE THREAD_STACKSIZE_DEFAULT
#endif
#ifndef ESP_WIFI_PRIO
/** The priority of the ESP WiFi netdev driver thread */
#define ESP_WIFI_PRIO GNRC_NETIF_PRIO
#endif
/**@}*/
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* MODULE_ESP_WIFI || DOXYGEN */
#endif /* ESP_WIFI_PARAMS_H */
/**@}*/

103
cpu/esp32/esp_events.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief ESP system event handler
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH)
#define ENABLE_DEBUG 0
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "log.h"
#include "esp_attr.h"
#include "esp_event_loop.h"
#include "irq_arch.h"
#define MAX_HANDLER_NUM 5
static system_event_cb_t _handler[MAX_HANDLER_NUM] = {};
static void* _handler_arg[MAX_HANDLER_NUM] = {};
esp_err_t esp_system_event_add_handler (system_event_cb_t handler, void *arg)
{
int i;
/* determine next free handler entry */
for (i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] == NULL) {
break;
}
}
/* return if there is no free entry */
if (i == MAX_HANDLER_NUM) {
return ESP_FAIL;
}
/* set the handler and argument entry */
_handler[i] = handler;
_handler_arg[i] = arg;
return ESP_OK;
}
esp_err_t esp_system_event_del_handler (system_event_cb_t handler)
{
int i;
/* determine the handler entry */
for (i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] == handler) {
break;
}
}
/* return if entry was not found */
if (i == MAX_HANDLER_NUM) {
return ESP_FAIL;
}
/* clean handler and arg entry */
_handler[i] = NULL;
_handler_arg[i] = NULL;
return ESP_OK;
}
static esp_err_t esp_system_event_handler(void *ctx, system_event_t *event)
{
for (int i = 0; i < MAX_HANDLER_NUM; i++) {
if (_handler[i] != NULL) {
_handler[i](_handler_arg[i], event);
}
}
return ESP_OK;
}
#endif
void esp_event_handler_init(void)
{
#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH)
esp_event_loop_init(esp_system_event_handler, NULL);
#endif
}

190
cpu/esp32/esp_xtimer.c Normal file
View File

@ -0,0 +1,190 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief ETS timer to xtimer mapper
*
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#define ENABLE_DEBUG 0
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "log.h"
#include "esp_attr.h"
#include "irq_arch.h"
#include "xtimer.h"
#include "rom/ets_sys.h"
struct _ets_to_xtimer {
ETSTimer *ets_timer;
xtimer_t xtimer;
};
/* maximum number of ETS timer to xtimer mapper objects */
/* TODO tune the value */
#define ETS_TO_TIMER_NUM 40
/* table of ETS timer to xtimer mapper objects */
static struct _ets_to_xtimer _ets_to_xtimer_map[ETS_TO_TIMER_NUM] = {};
/**
* @brief Get the ETS timer to xtimer mapper object for the given timer.
*
* If there is no object, the function registers a new one and returns it.
* If there is no more object available, it returns NULL.
*
* @param pointer to the ETS timer
* @return pointer to the mapper object or NULL in case of error
*/
struct _ets_to_xtimer* _ets_to_xtimer_get(ETSTimer *timer)
{
/* search for an existing mapper object */
for (int i = 0; i < ETS_TO_TIMER_NUM; i++) {
if (_ets_to_xtimer_map[i].ets_timer == timer) {
return &_ets_to_xtimer_map[i];
}
}
/* search for a free mapper object */
for (int i = 0; i < ETS_TO_TIMER_NUM; i++) {
if (_ets_to_xtimer_map[i].ets_timer == NULL) {
_ets_to_xtimer_map[i].ets_timer = timer;
return &_ets_to_xtimer_map[i];
}
}
LOG_TAG_ERROR("esp_xtimer", "There is no free ETS timer to xtimer mapper "
"object available\n");
return NULL;
}
/**
* @brief Free the ETS timer to xtimer mapper object for the given timer.
* @param pointer to the ETS timer
*/
void _ets_to_xtimer_free(ETSTimer *timer)
{
/* search for an existing mapper object */
for (int i = 0; i < ETS_TO_TIMER_NUM; i++) {
if (_ets_to_xtimer_map[i].ets_timer == timer) {
_ets_to_xtimer_map[i].ets_timer = NULL;
return;
}
}
DEBUG("%s There is no ETS timer to xtimer for ETS timer %p\n",
__func__, timer);
}
/* xtimer call back function, distributes ets_timer callbacks */
void IRAM_ATTR _ets_to_xtimer_callback (void *arg)
{
struct _ets_to_xtimer* e2xt = (struct _ets_to_xtimer*)arg;
CHECK_PARAM (e2xt != NULL);
CHECK_PARAM (e2xt->ets_timer != NULL);
irq_isr_enter();
/* if timer is periodic, start it again with period */
if (e2xt->ets_timer->timer_period) {
ets_timer_arm_us(e2xt->ets_timer, e2xt->ets_timer->timer_period, true);
}
/* execute the ets_timer callback function */
e2xt->ets_timer->timer_func(e2xt->ets_timer->timer_arg);
irq_isr_exit();
}
void ets_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunc, void *parg)
{
DEBUG("%s timer=%p pfunc=%p parg=%p\n", __func__, ptimer, pfunc, parg);
struct _ets_to_xtimer* e2xt = _ets_to_xtimer_get(ptimer);
CHECK_PARAM(e2xt != NULL);
e2xt->ets_timer->timer_func = pfunc;
e2xt->ets_timer->timer_arg = parg;
e2xt->xtimer.callback = &_ets_to_xtimer_callback;
e2xt->xtimer.arg = (void*)e2xt;
}
void ets_timer_done(ETSTimer *ptimer)
{
DEBUG("%s timer=%p\n", __func__, ptimer);
struct _ets_to_xtimer* e2xt = _ets_to_xtimer_get(ptimer);
CHECK_PARAM(e2xt != NULL);
e2xt->ets_timer->timer_func = NULL;
e2xt->ets_timer->timer_arg = NULL;
}
void ets_timer_arm_us(ETSTimer *timer, uint32_t tmout, bool repeat)
{
DEBUG("%s timer=%p tmout=%u repeat=%d\n", __func__, timer, tmout, repeat);
struct _ets_to_xtimer* e2xt = _ets_to_xtimer_get(timer);
CHECK_PARAM(e2xt != NULL);
CHECK_PARAM(e2xt->xtimer.callback != NULL);
xtimer_set(&e2xt->xtimer, tmout);
e2xt->ets_timer->timer_expire = e2xt->xtimer.target;
e2xt->ets_timer->timer_period = repeat ? tmout : 0;
}
void ets_timer_arm(ETSTimer *timer, uint32_t tmout, bool repeat)
{
ets_timer_arm_us(timer, tmout * USEC_PER_MSEC, repeat);
}
void ets_timer_disarm(ETSTimer *timer)
{
DEBUG("%s timer=%p\n", __func__, timer);
struct _ets_to_xtimer* e2xt = _ets_to_xtimer_get(timer);
CHECK_PARAM(e2xt != NULL);
xtimer_remove(&e2xt->xtimer);
}
void ets_timer_init(void)
{
/* initialization is not necessary */
}
void ets_timer_deinit(void)
{
/* deinitialization is not necessary */
}
void os_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *parg)
__attribute__((alias("ets_timer_setfn")));
void os_timer_disarm(ETSTimer *ptimer)
__attribute__((alias("ets_timer_disarm")));
void os_timer_arm_us(ETSTimer *ptimer,uint32_t u_seconds,bool repeat_flag)
__attribute__((alias("ets_timer_arm_us")));
void os_timer_arm(ETSTimer *ptimer,uint32_t milliseconds,bool repeat_flag)
__attribute__((alias("ets_timer_arm")));
void os_timer_done(ETSTimer *ptimer)
__attribute__((alias("ets_timer_done")));

207
cpu/esp32/exceptions.c Normal file
View File

@ -0,0 +1,207 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief ESP32 exception handling
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#define ENABLE_DEBUG 0
#include "debug.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include "esp_common.h"
#include "irq.h"
#include "log.h"
#include "periph/pm.h"
#include "ps.h"
#include "esp/common_macros.h"
#include "esp/xtensa_ops.h"
#include "rom/ets_sys.h"
#include "rom/rtc.h"
#include "rom/uart.h"
#include "sdk_conf.h"
#include "xtensa/corebits.h"
#include "freertos/xtensa_api.h"
#ifdef MODULE_ESP_GDBSTUB
#include "esp_gdbstub.h"
#endif
#ifdef MODULE_ESP_IDF_HEAP
#include "heap/esp_heap_caps.h"
#endif
extern void malloc_stats (void);
extern unsigned int get_free_heap_size (void);
extern uint8_t _eheap; /* end of heap (defined in esp32.common.ld) */
extern uint8_t _sheap; /* start of heap (defined in esp32.common.ld) */
static const char* exception_names [] =
{
"IllegalInstructionCause", /* 0 */
"SyscallCause", /* 1 */
"InstructionFetchErrorCause", /* 2 */
"LoadStoreErrorCause", /* 3 */
"Level1InterruptCause", /* 4 */
"AllocaCause", /* 5 */
"IntegerDivideByZeroCause", /* 6 */
"", /* 7 - reserved */
"PrivilegedCause", /* 8 */
"LoadStoreAlignmentCause", /* 9 */
"", /* 10 - reserved */
"", /* 11 - reserved */
"InstrPIFDataErrorCause", /* 12 */
"LoadStorePIFDataErrorCause", /* 13 */
"InstrPIFAddrErrorCause", /* 14 */
"LoadStorePIFAddrErrorCause", /* 15 */
"InstTLBMissCause", /* 16 */
"InstTLBMultiHitCause", /* 17 */
"InstFetchPrivilegeCause", /* 18 */
"", /* 19 - reserved */
"InstFetchProhibitedCause", /* 20 */
"", /* 21 - reserved */
"", /* 22 - reserved */
"", /* 23 - reserved */
"LoadStoreTLBMissCause", /* 24 */
"LoadStoreTLBMultiHitCause", /* 25 */
"LoadStorePrivilegeCause", /* 26 */
"", /* 27 - reserved */
"LoadProhibitedCause", /* 28 */
"StoreProhibitedCause", /* 29 */
"", /* 30 - reserved */
"", /* 31 - reserved */
"Coprocessor0Disabled", /* 32 */
"Coprocessor1Disabled", /* 33 */
"Coprocessor2Disabled", /* 34 */
"Coprocessor3Disabled", /* 35 */
"Coprocessor4Disabled", /* 36 */
"Coprocessor5Disabled", /* 37 */
"Coprocessor6Disabled", /* 38 */
"Coprocessor7Disabled", /* 39 */
};
const char *reg_names[] = {
"pc ", "ps ",
"a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ",
"a6 ", "a7 ", "a8 ", "a9 ", "a10 ", "a11 ",
"a12 ", "a13 ", "a14 ", "A15 ", "SAR ",
"exccause", "excvaddr", "lbeg ", "lend ", "lcount "
};
void IRAM NORETURN exception_handler (XtExcFrame *frame)
{
uint32_t excsave1;
uint32_t epc1;
uint32_t epc2;
uint32_t epc3;
uint32_t epc4;
RSR(excsave1, excsave1);
RSR(epc1, epc1);
RSR(epc2, epc2);
RSR(epc3, epc3);
RSR(epc4, epc4);
#ifdef MODULE_ESP_GDBSTUB
esp_gdbstub_panic_handler(frame);
#endif
ets_printf("EXCEPTION!! exccause=%d (%s) @%08x excvaddr=%08x\n\n",
frame->exccause, exception_names[frame->exccause],
excsave1, frame->excvaddr);
#if defined(DEVELHELP)
#if defined(MODULE_PS)
ets_printf("processes:\n");
ps();
ets_printf("\n");
#endif /* MODULE_PS */
#ifdef MODULE_ESP_IDF_HEAP
heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);
#else
ets_printf("\nheap: %u (free %u) byte\n", &_eheap - &_sheap, get_free_heap_size());
#endif /* MODULE_ESP_IDF_HEAP */
ets_printf("\nregister set\n");
ets_printf("pc : %08x\t", frame->pc);
ets_printf("ps : %08x\t", frame->ps);
ets_printf("exccause: %08x\t", frame->exccause);
ets_printf("excvaddr: %08x\n", frame->excvaddr);
ets_printf("epc1 : %08x\t", epc1);
ets_printf("epc2 : %08x\t", epc2);
ets_printf("epc3 : %08x\t", epc3);
ets_printf("epc4 : %08x\n", epc4);
ets_printf("a0 : %08x\t", frame->a0);
ets_printf("a1 : %08x\t", frame->a1);
ets_printf("a2 : %08x\t", frame->a2);
ets_printf("a3 : %08x\n", frame->a3);
ets_printf("a4 : %08x\t", frame->a4);
ets_printf("a5 : %08x\t", frame->a5);
ets_printf("a6 : %08x\t", frame->a6);
ets_printf("a7 : %08x\n", frame->a7);
ets_printf("a8 : %08x\t", frame->a8);
ets_printf("a9 : %08x\t", frame->a9);
ets_printf("a10 : %08x\t", frame->a10);
ets_printf("a11 : %08x\n", frame->a11);
ets_printf("a12 : %08x\t", frame->a12);
ets_printf("a13 : %08x\t", frame->a13);
ets_printf("a14 : %08x\t", frame->a14);
ets_printf("a15 : %08x\n", frame->a15);
ets_printf("lbeg : %08x\t", frame->lbeg);
ets_printf("lend : %08x\t", frame->lend);
ets_printf("lcount : %08x\n", frame->lcount);
#endif /* DEVELHELP */
/* restart */
/* TODO: Improvement
Normally, we should try to restart the system. However, this
will not work after some exceptions, e.g., the LoadStoreErrorCause.
Therefore, we break the execution and wait for the WDT reset. Maybe
there is better way. If debugger is active, 'break 0,0' stops
execution in debugger. */
__asm__ volatile ("break 0,0");
UNREACHABLE();
}
void init_exceptions (void)
{
xt_set_exception_handler(EXCCAUSE_UNALIGNED, exception_handler);
xt_set_exception_handler(EXCCAUSE_ILLEGAL, exception_handler);
xt_set_exception_handler(EXCCAUSE_INSTR_ERROR, exception_handler);
xt_set_exception_handler(EXCCAUSE_LOAD_STORE_ERROR, exception_handler);
xt_set_exception_handler(EXCCAUSE_LOAD_PROHIBITED, exception_handler);
xt_set_exception_handler(EXCCAUSE_STORE_PROHIBITED, exception_handler);
xt_set_exception_handler(EXCCAUSE_PRIVILEGED, exception_handler);
}
void IRAM NORETURN panic_arch(void)
{
#if defined(DEVELHELP)
#ifdef MODULE_ESP_IDF_HEAP
heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);
#else
ets_printf("\nheap: %u (free %u) byte\n", &_eheap - &_sheap, get_free_heap_size());
#endif /* MODULE_ESP_IDF_HEAP */
#endif /* DEVELHELP */
/* restart */
software_reset();
UNREACHABLE();
}

View File

@ -0,0 +1,3 @@
MODULE=riot_freertos
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* FreeRTOS to RIOT-OS adaption module for source code compatibility
*/
#ifndef DOXYGEN
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <string.h>
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
EventGroupHandle_t xEventGroupCreate (void)
{
ets_printf("%s\n", __func__);
return NULL;
}
void vEventGroupDelete (EventGroupHandle_t xEventGroup)
{
ets_printf("%s\n", __func__);
return NULL;
}
EventBits_t xEventGroupSetBits (EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet)
{
ets_printf("%s\n", __func__);
return NULL;
}
EventBits_t xEventGroupClearBits (EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
{
ets_printf("%s\n", __func__);
return NULL;
}
EventBits_t xEventGroupWaitBits (const EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait)
{
ets_printf("%s\n", __func__);
return NULL;
}
#endif /* DOXYGEN */

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* FreeRTOS to RIOT-OS adaption module for source code compatibility
*/
#ifndef DOXYGEN
#define ENABLE_DEBUG 0
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "log.h"
#include "freertos/FreeRTOS.h"
uint32_t xPortGetTickRateHz(void) {
return MSEC_PER_SEC / portTICK_PERIOD_MS;
}
BaseType_t xPortInIsrContext(void)
{
/* is working on single core in that way */
return irq_is_in();
}
#endif /* DOXYGEN */

364
cpu/esp32/freertos/queue.c Normal file
View File

@ -0,0 +1,364 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* FreeRTOS to RIOT-OS adaption module for source code compatibility
*/
#ifndef DOXYGEN
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "esp_attr.h"
#include "log.h"
#include "mutex.h"
#include "rmutex.h"
#include "thread.h"
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#undef portENTER_CRITICAL
#undef portEXIT_CRITICAL
#define portENTER_CRITICAL(mux) vTaskEnterCritical(mux)
#define portEXIT_CRITICAL(mux) vTaskExitCritical(mux)
/*
* In FreeRTOS different types of semaphores, mutexes and queues are all
* mapped to a single generic queue type. With all these different types,
* single functions for send, receive, give and take are then used. To be
* able to dsitinguish between these different types in RIOT, we need typed
* objects.
*/
typedef struct {
uint8_t type; /* type of the queue, MUST be the first element */
mutex_t mutex; /* mutex to secure operations on the queue */
list_node_t sending; /* threads that are waiting to send */
list_node_t receiving; /* threads that are waiting to receive */
uint8_t* queue; /* the queue of waiting items */
uint32_t item_size; /* size of each item in the queue */
uint32_t item_num; /* num of items that can be stored in queue */
uint32_t item_front; /* first item in queue */
uint32_t item_tail; /* last item in queue */
uint32_t item_level; /* num of items stored in queue */
} _queue_t;
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
const uint8_t ucQueueType )
{
DEBUG("%s pid=%d len=%u size=%u type=%u ", __func__,
thread_getpid(), uxQueueLength, uxItemSize, ucQueueType);
uint32_t queue_size = uxQueueLength * uxItemSize;
_queue_t* queue = malloc(sizeof(_queue_t) + queue_size);
mutex_init(&queue->mutex);
queue->type = ucQueueType;
queue->receiving.next = NULL;
queue->sending.next = NULL;
queue->queue = (queue_size) ? (uint8_t*)queue + sizeof(_queue_t) : NULL;
queue->item_num = uxQueueLength;
queue->item_size = uxItemSize;
queue->item_front = 0;
queue->item_tail = 0;
queue->item_level = 0;
DEBUG("queue=%p\n", queue);
return queue;
}
#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0 )
QueueHandle_t xQueueCreateCountingSemaphore (const UBaseType_t uxMaxCount,
const UBaseType_t uxInitialCount)
{
_queue_t* queue;
CHECK_PARAM_RET(uxMaxCount != 0, NULL);
CHECK_PARAM_RET(uxInitialCount <= uxMaxCount, NULL);
queue = xQueueGenericCreate(uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH,
queueQUEUE_TYPE_COUNTING_SEMAPHORE);
DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), queue);
if (queue != NULL) {
queue->item_level = uxInitialCount;
queue->item_tail = (queue->item_front + queue->item_level) % queue->item_num;
}
return queue;
}
void vQueueDelete( QueueHandle_t xQueue )
{
DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), xQueue);
CHECK_PARAM(xQueue != NULL);
free(xQueue);
}
BaseType_t IRAM_ATTR _queue_generic_send(QueueHandle_t xQueue,
const void * const pvItemToQueue,
const BaseType_t xCopyPosition,
TickType_t xTicksToWait,
BaseType_t * const pxHigherPriorityTaskWoken)
{
DEBUG("%s pid=%d prio=%d queue=%p pos=%d wait=%u woken=%p\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority,
xQueue, xCopyPosition, xTicksToWait, pxHigherPriorityTaskWoken);
_queue_t* queue = (_queue_t*)xQueue;
CHECK_PARAM_RET(queue != NULL, pdFAIL);
while (1) {
taskENTER_CRITICAL(&queue->mutex);
/* is there still space in the queue */
if (queue->item_level < queue->item_num || xCopyPosition == queueOVERWRITE) {
uint32_t write_pos;
/* determin the write position in the queue and update positions */
if (xCopyPosition == queueSEND_TO_BACK) {
write_pos = queue->item_tail;
queue->item_tail = (queue->item_tail + 1) % queue->item_num;
queue->item_level++;
}
else if (xCopyPosition == queueSEND_TO_FRONT) {
queue->item_front = (queue->item_front - 1) % queue->item_num;
queue->item_level++;
write_pos = queue->item_front;
}
else { /* queueOVERWRITE */
write_pos = queue->item_front;
if (queue->item_level == 0) {
queue->item_level++;
}
}
/* if the item has no 0 size, copy it to the according place in queue */
if (queue->item_size && queue->queue && pvItemToQueue) {
memcpy(queue->queue + write_pos * queue->item_size,
pvItemToQueue, queue->item_size);
}
/* unlock waiting receiving thread */
if (queue->receiving.next != NULL) {
list_node_t *next = list_remove_head(&queue->receiving);
thread_t *process = container_of((clist_node_t*)next, thread_t, rq_entry);
uint8_t process_priority = process->priority;
uint8_t my_priority = sched_threads[thread_getpid()]->priority;
if (pxHigherPriorityTaskWoken) {
*pxHigherPriorityTaskWoken = process_priority < my_priority;
}
DEBUG("%s pid=%d queue=%p unlock waiting\n", __func__,
thread_getpid(), xQueue);
sched_set_status(process, STATUS_PENDING);
sched_switch(process_priority);
}
DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__,
thread_getpid(), xQueue);
taskEXIT_CRITICAL(&queue->mutex);
return pdPASS;
}
else if (xTicksToWait == 0) {
/* if there was no space and timeout = 0, return with error */
DEBUG("%s pid=%d queue=%p return errQUEUE_FULL\n", __func__,
thread_getpid(), xQueue);
taskEXIT_CRITICAL(&queue->mutex);
return errQUEUE_FULL;
}
else {
/* suspend the calling thread to wait for space in the queue */
thread_t *me = (thread_t*)sched_active_thread;
sched_set_status(me, STATUS_SEND_BLOCKED);
/* waiting list is sorted by priority */
thread_add_to_list(&queue->sending, me);
DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__,
thread_getpid(), xQueue);
taskEXIT_CRITICAL(&queue->mutex);
thread_yield_higher();
/* TODO timeout handling with xTicksToWait */
DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__,
thread_getpid(), xQueue);
}
}
return errQUEUE_FULL;
}
BaseType_t IRAM_ATTR _queue_generic_recv (QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait,
const BaseType_t xJustPeeking,
BaseType_t * const pxHigherPriorityTaskWoken)
{
DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%u woken=%p\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority,
xQueue, xTicksToWait, xJustPeeking, pxHigherPriorityTaskWoken);
_queue_t* queue = (_queue_t*)xQueue;
CHECK_PARAM_RET(queue != NULL, pdFAIL);
while (1) {
taskENTER_CRITICAL(&queue->mutex);
if (queue->item_level == 0 && xTicksToWait == 0) {
/* if there was no element in queue and timeout = 0, return with error */
DEBUG("%s pid=%d queue=%p return errQUEUE_EMPTY\n", __func__,
thread_getpid(), xQueue);
taskEXIT_CRITICAL(&queue->mutex);
return errQUEUE_EMPTY;
}
if (queue->item_level > 0) {
/* if the item has no 0 size, copy it from queue to buffer */
if (queue->item_size && queue->item_num && queue->queue && pvBuffer) {
memcpy(pvBuffer,
queue->queue + queue->item_front * queue->item_size,
queue->item_size);
}
/* when only peeking leave the element in queue */
if (xJustPeeking == pdFALSE) {
queue->item_front = (queue->item_front + 1) % queue->item_num;
queue->item_level--;
/* unlock waiting sending thread */
if (queue->sending.next != NULL) {
list_node_t *next = list_remove_head(&queue->sending);
thread_t *process = container_of((clist_node_t*)next,
thread_t, rq_entry);
uint16_t process_priority = process->priority;
uint8_t my_priority = sched_threads[thread_getpid()]->priority;
if (pxHigherPriorityTaskWoken) {
*pxHigherPriorityTaskWoken = process_priority < my_priority;
}
DEBUG("%s pid=%d queue=%p unlock waiting\n", __func__,
thread_getpid(), xQueue);
sched_set_status(process, STATUS_PENDING);
sched_switch(process_priority);
}
}
DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__,
thread_getpid(), xQueue);
taskEXIT_CRITICAL(&queue->mutex);
return pdPASS;
}
else {
/* suspend the calling thread to wait for an item in the queue */
thread_t *me = (thread_t*)sched_active_thread;
sched_set_status(me, STATUS_RECEIVE_BLOCKED);
/* waiting list is sorted by priority */
thread_add_to_list(&queue->receiving, me);
DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__,
thread_getpid(), xQueue);
taskEXIT_CRITICAL(&queue->mutex);
thread_yield_higher();
/* TODO timeout handling with xTicksToWait */
DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__,
thread_getpid(), xQueue);
}
}
}
BaseType_t IRAM_ATTR xQueueGenericSend( QueueHandle_t xQueue,
const void * const pvItemToQueue,
TickType_t xTicksToWait,
const BaseType_t xCopyPosition )
{
DEBUG("%s pid=%d prio=%d queue=%p wait=%u pos=%d\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority,
xQueue, xTicksToWait, xCopyPosition);
return _queue_generic_send(xQueue, pvItemToQueue, xCopyPosition,
xTicksToWait, NULL);
}
BaseType_t IRAM_ATTR xQueueGenericSendFromISR( QueueHandle_t xQueue,
const void * const pvItemToQueue,
BaseType_t * const pxHigherPriorityTaskWoken,
const BaseType_t xCopyPosition )
{
DEBUG("%s pid=%d prio=%d queue=%p pos=%d woken=%p\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority,
xQueue, xCopyPosition, pxHigherPriorityTaskWoken);
return _queue_generic_send(xQueue, pvItemToQueue, xCopyPosition,
0, pxHigherPriorityTaskWoken);
}
BaseType_t IRAM_ATTR xQueueGenericReceive (QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait,
const BaseType_t xJustPeeking)
{
DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%d\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority,
xQueue, xTicksToWait, xJustPeeking);
return _queue_generic_recv(xQueue, pvBuffer, xTicksToWait,
xJustPeeking, NULL);
}
BaseType_t IRAM_ATTR xQueueReceiveFromISR (QueueHandle_t xQueue,
void * const pvBuffer,
BaseType_t * const pxHigherPriorityTaskWoken)
{
DEBUG("%s pid=%d prio=%d queue=%p woken=%p\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority,
xQueue, pxHigherPriorityTaskWoken);
return _queue_generic_recv(xQueue, pvBuffer, 0,
0, pxHigherPriorityTaskWoken);
}
UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue )
{
_queue_t* queue = (_queue_t*)xQueue;
CHECK_PARAM_RET(queue != NULL, 0);
return queue->item_level;
}
BaseType_t xQueueGiveFromISR (QueueHandle_t xQueue,
BaseType_t * const pxHigherPriorityTaskWoken)
{
ets_printf("%s\n", __func__);
return pdFALSE;
}
#endif /* DOXYGEN */

178
cpu/esp32/freertos/semphr.c Normal file
View File

@ -0,0 +1,178 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* FreeRTOS to RIOT-OS adaption module for source code compatibility
*/
#ifndef DOXYGEN
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "irq_arch.h"
#include "log.h"
#include "mutex.h"
#include "rmutex.h"
#include "freertos/FreeRTOS.h"
/*
* In FreeRTOS different types of semaphores, mutexes and queues are all
* mapped to a single generic queue type. With all these different types,
* single functions for send, receive, give and take are then used. To be
* able to dsitinguish between these different types in RIOT, we need typed
* objects.
*/
typedef struct {
uint8_t type; /* type of the mutex, MUST be the first element */
mutex_t mutex; /* the mutex */
} _mutex_t;
typedef struct {
uint8_t type; /* type of the mutex, MUST be the first element */
rmutex_t rmutex; /* the mutex */
} _rmutex_t;
SemaphoreHandle_t xSemaphoreCreateMutex(void)
{
_mutex_t* _tmp = (_mutex_t*)malloc (sizeof(_mutex_t));
_tmp->type = queueQUEUE_TYPE_MUTEX;
mutex_init(&_tmp->mutex);
DEBUG("%s mutex=%p\n", __func__, _tmp);
return _tmp;
}
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )
{
DEBUG("%s mutex=%p\n", __func__, xSemaphore);
CHECK_PARAM(xSemaphore != NULL);
free(xSemaphore);
}
BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore)
{
DEBUG("%s mutex=%p\n", __func__, xSemaphore);
CHECK_PARAM_RET(xSemaphore != NULL, pdFALSE);
uint8_t type = ((_mutex_t*)xSemaphore)->type;
mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex;
switch (type) {
case queueQUEUE_TYPE_MUTEX:
mutex_unlock(mutex);
break;
case queueQUEUE_TYPE_RECURSIVE_MUTEX:
return xSemaphoreGiveRecursive (xSemaphore);
default:
return xQueueGenericSend(xSemaphore, NULL, 0, queueSEND_TO_BACK);
}
return pdTRUE;
}
BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait)
{
DEBUG("%s mutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait);
CHECK_PARAM_RET(xSemaphore != NULL, pdFALSE);
uint8_t type = ((_mutex_t*)xSemaphore)->type;
mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex;
switch (type) {
case queueQUEUE_TYPE_MUTEX:
{
if (xTicksToWait == 0) {
return (mutex_trylock(mutex) == 0) ? pdTRUE : pdFALSE;
}
else {
mutex_lock(mutex);
/* TODO timeout handling */
return pdTRUE;
}
break;
}
case queueQUEUE_TYPE_RECURSIVE_MUTEX:
return xSemaphoreTakeRecursive (xSemaphore, xTicksToWait);
default:
return xQueueGenericReceive(xSemaphore, NULL, xTicksToWait, pdFALSE);
}
}
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void)
{
_rmutex_t* _tmp = (_rmutex_t*)malloc (sizeof(_rmutex_t));
_tmp->type = queueQUEUE_TYPE_RECURSIVE_MUTEX;
rmutex_init(&_tmp->rmutex);
DEBUG("%s rmutex=%p\n", __func__, _tmp);
return _tmp;
}
BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore)
{
DEBUG("%s rmutex=%p\n", __func__, xSemaphore);
CHECK_PARAM_RET(xSemaphore != NULL, pdFALSE);
CHECK_PARAM_RET(((_rmutex_t*)xSemaphore)->type ==
queueQUEUE_TYPE_RECURSIVE_MUTEX, pdFALSE);
rmutex_unlock(&((_rmutex_t*)xSemaphore)->rmutex);
return pdTRUE;
}
BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait)
{
DEBUG("%s rmutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait);
CHECK_PARAM_RET(xSemaphore != NULL, pdFALSE);
CHECK_PARAM_RET(((_rmutex_t*)xSemaphore)->type ==
queueQUEUE_TYPE_RECURSIVE_MUTEX, pdFALSE);
BaseType_t ret = pdTRUE;
rmutex_t* rmutex = &((_rmutex_t*)xSemaphore)->rmutex;
if (xTicksToWait == 0) {
ret = (rmutex_trylock(rmutex) == 0) ? pdTRUE : pdFALSE;
}
else {
rmutex_lock(&((_rmutex_t*)xSemaphore)->rmutex);
/* TODO timeout handling */
}
return ret;
}
void vPortCPUAcquireMutex(portMUX_TYPE *mux)
{
DEBUG("%s pid=%d prio=%d mux=%p\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority, mux);
critical_enter();
mutex_lock(mux); /* lock the mutex with interrupts disabled */
critical_exit();
}
void vPortCPUReleaseMutex(portMUX_TYPE *mux)
{
DEBUG("%s pid=%d prio=%d mux=%p\n", __func__,
thread_getpid(), sched_threads[thread_getpid()]->priority, mux);
critical_enter();
mutex_unlock(mux); /* unlock the mutex with interrupts disabled */
critical_exit();
}
#endif /* DOXYGEN */

173
cpu/esp32/freertos/task.c Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2018 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* FreeRTOS to RIOT-OS adaption module for source code compatibility
*/
#ifndef DOXYGEN
#define ENABLE_DEBUG 0
#include "debug.h"
#include <string.h>
#include "esp_common.h"
#include "esp_attr.h"
#include "log.h"
#include "syscalls.h"
#include "thread.h"
#include "xtimer.h"
#include "soc/soc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define MHZ 1000000
/**
* @brief Architecture specific data of thread control blocks
*/
typedef struct {
uint32_t saved_int_state;
uint32_t critical_nesting;
} thread_arch_ext_t;
volatile thread_arch_ext_t threads_arch_exts[KERNEL_PID_LAST + 1] = {};
BaseType_t xTaskCreatePinnedToCore (TaskFunction_t pvTaskCode,
const char * const pcName,
const uint32_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pvCreatedTask,
const BaseType_t xCoreID)
{
/* FreeRTOS priority values have to be inverted */
uxPriority = SCHED_PRIO_LEVELS - uxPriority - 1;
DEBUG("%s name=%s size=%d prio=%d pvCreatedTask=%p ",
__func__, pcName, usStackDepth, uxPriority, pvCreatedTask);
char* stack = malloc(usStackDepth + sizeof(thread_t));
if (!stack) {
return pdFALSE;
}
kernel_pid_t pid = thread_create(stack,
usStackDepth + sizeof(thread_t),
uxPriority,
THREAD_CREATE_WOUT_YIELD |
THREAD_CREATE_STACKTEST,
(thread_task_func_t)pvTaskCode,
pvParameters, pcName);
DEBUG("pid=%d\n", pid);
if (pvCreatedTask) {
*pvCreatedTask = (TaskHandle_t)(0L + pid);
}
return (pid < 0) ? pdFALSE : pdTRUE;
}
BaseType_t xTaskCreate (TaskFunction_t pvTaskCode,
const char * const pcName,
const uint32_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pvCreatedTask)
{
return xTaskCreatePinnedToCore (pvTaskCode,
pcName,
usStackDepth,
pvParameters,
uxPriority,
pvCreatedTask,
PRO_CPU_NUM);
}
void vTaskDelete (TaskHandle_t xTaskToDelete)
{
DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToDelete);
CHECK_PARAM(xTaskToDelete != NULL);
uint32_t pid = (uint32_t)xTaskToDelete;
/* remove old task from scheduling */
thread_t* thread = (thread_t*)sched_threads[pid];
sched_set_status(thread, STATUS_STOPPED);
sched_threads[pid] = NULL;
sched_num_threads--;
sched_active_thread = NULL;
/* determine the new running task */
sched_run();
}
TaskHandle_t xTaskGetCurrentTaskHandle(void)
{
DEBUG("%s pid=%d\n", __func__, thread_getpid());
uint32_t pid = thread_getpid();
return (TaskHandle_t)pid;
}
void vTaskDelay( const TickType_t xTicksToDelay )
{
uint64_t us = xTicksToDelay * MHZ / xPortGetTickRateHz();
xtimer_usleep(us);
}
TickType_t xTaskGetTickCount (void)
{
return system_get_time() / USEC_PER_MSEC / portTICK_PERIOD_MS;
}
void vTaskEnterCritical( portMUX_TYPE *mux )
{
/* determine calling thread pid (can't fail) */
kernel_pid_t my_pid = thread_getpid();
DEBUG("%s pid=%d prio=%d mux=%p\n", __func__,
my_pid, sched_threads[my_pid]->priority, mux);
/* disable interrupts */
uint32_t state = irq_disable();
/* aquire the mutex with interrupts disabled */
mutex_lock(mux); /* TODO should be only a spin lock */
/* increment nesting counter and save old interrupt level */
threads_arch_exts[my_pid].critical_nesting++;
if (threads_arch_exts[my_pid].critical_nesting == 1) {
threads_arch_exts[my_pid].saved_int_state = state;
}
}
void vTaskExitCritical( portMUX_TYPE *mux )
{
/* determine calling thread pid (can't fail) */
kernel_pid_t my_pid = thread_getpid();
DEBUG("%s pid=%d prio=%d mux=%p\n", __func__,
my_pid, sched_threads[my_pid]->priority, mux);
/* release the mutex with interrupts disabled */
mutex_unlock(mux); /* TODO should be only a spin lock */
/* decrement nesting counter and restore old interrupt level */
if (threads_arch_exts[my_pid].critical_nesting) {
threads_arch_exts[my_pid].critical_nesting--;
if (threads_arch_exts[my_pid].critical_nesting == 0) {
irq_restore(threads_arch_exts[my_pid].saved_int_state);
}
}
}
#endif /* DOXYGEN */

Some files were not shown because too many files have changed in this diff Show More