mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	init commit for nrf52
This commit is contained in:
		| @@ -35,6 +35,7 @@ from esphome.const import ( | |||||||
|     PLATFORM_ESP8266, |     PLATFORM_ESP8266, | ||||||
|     PLATFORM_RP2040, |     PLATFORM_RP2040, | ||||||
|     SECRETS_FILES, |     SECRETS_FILES, | ||||||
|  |     PLATFORM_NRF52, | ||||||
| ) | ) | ||||||
| from esphome.core import CORE, EsphomeError, coroutine | from esphome.core import CORE, EsphomeError, coroutine | ||||||
| from esphome.helpers import indent, is_ip_address | from esphome.helpers import indent, is_ip_address | ||||||
| @@ -297,6 +298,38 @@ def upload_using_platformio(config, port): | |||||||
|     return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args) |     return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def update_progress(progress=0, done=False, log_message=""): | ||||||
|  |     import click | ||||||
|  |  | ||||||
|  |     del done, log_message  # Unused parameters | ||||||
|  |     if progress == 0: | ||||||
|  |         return | ||||||
|  |  | ||||||
|  |     if progress % 40 == 0: | ||||||
|  |         click.echo("#", nl=True) | ||||||
|  |     else: | ||||||
|  |         click.echo("#", nl=False) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def upload_adafruit_nrfutil(config, port): | ||||||
|  |     from esphome import platformio_api | ||||||
|  |     from pathlib import Path | ||||||
|  |     from nordicsemi.dfu.dfu_transport_serial import DfuTransportSerial | ||||||
|  |     from nordicsemi.dfu.dfu_transport import DfuEvent | ||||||
|  |     from nordicsemi.dfu.dfu import Dfu | ||||||
|  |  | ||||||
|  |     idedata = platformio_api.get_idedata(config) | ||||||
|  |     dfu_package = str(Path(idedata.firmware_elf_path).with_suffix(".zip")) | ||||||
|  |     serial_backend = DfuTransportSerial(port) | ||||||
|  |     serial_backend.register_events_callback(DfuEvent.PROGRESS_EVENT, update_progress) | ||||||
|  |     dfu = Dfu(dfu_package, dfu_transport=serial_backend) | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         dfu.dfu_send_images() | ||||||
|  |     except Exception as e: | ||||||
|  |         raise EsphomeError(f"Unable to send image: {e}") | ||||||
|  |  | ||||||
|  |  | ||||||
| def upload_program(config, args, host): | def upload_program(config, args, host): | ||||||
|     if get_port_type(host) == "SERIAL": |     if get_port_type(host) == "SERIAL": | ||||||
|         if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266): |         if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266): | ||||||
| @@ -309,7 +342,10 @@ def upload_program(config, args, host): | |||||||
|         if CORE.target_platform in (PLATFORM_BK72XX, PLATFORM_RTL87XX): |         if CORE.target_platform in (PLATFORM_BK72XX, PLATFORM_RTL87XX): | ||||||
|             return upload_using_platformio(config, host) |             return upload_using_platformio(config, host) | ||||||
|  |  | ||||||
|         return 1  # Unknown target platform |         if CORE.target_platform in (PLATFORM_NRF52): | ||||||
|  |             return upload_adafruit_nrfutil(config, host) | ||||||
|  |  | ||||||
|  |         raise EsphomeError(f"Unknown target platform: {CORE.target_platform}") | ||||||
|  |  | ||||||
|     if CONF_OTA not in config: |     if CONF_OTA not in config: | ||||||
|         raise EsphomeError( |         raise EsphomeError( | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ from esphome.const import ( | |||||||
|     PLATFORM_ESP32, |     PLATFORM_ESP32, | ||||||
|     PLATFORM_ESP8266, |     PLATFORM_ESP8266, | ||||||
|     PLATFORM_RP2040, |     PLATFORM_RP2040, | ||||||
|  |     PLATFORM_NRF52, | ||||||
| ) | ) | ||||||
| from esphome.core import CORE, EsphomeError, Lambda, coroutine_with_priority | from esphome.core import CORE, EsphomeError, Lambda, coroutine_with_priority | ||||||
| from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant | from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant | ||||||
| @@ -101,6 +102,8 @@ ESP_ARDUINO_UNSUPPORTED_USB_UARTS = [USB_SERIAL_JTAG] | |||||||
|  |  | ||||||
| UART_SELECTION_RP2040 = [USB_CDC, UART0, UART1] | UART_SELECTION_RP2040 = [USB_CDC, UART0, UART1] | ||||||
|  |  | ||||||
|  | UART_SELECTION_NRF52 = [USB_CDC] | ||||||
|  |  | ||||||
| HARDWARE_UART_TO_UART_SELECTION = { | HARDWARE_UART_TO_UART_SELECTION = { | ||||||
|     UART0: logger_ns.UART_SELECTION_UART0, |     UART0: logger_ns.UART_SELECTION_UART0, | ||||||
|     UART0_SWAP: logger_ns.UART_SELECTION_UART0_SWAP, |     UART0_SWAP: logger_ns.UART_SELECTION_UART0_SWAP, | ||||||
| @@ -140,6 +143,8 @@ def uart_selection(value): | |||||||
|         component = get_libretiny_component() |         component = get_libretiny_component() | ||||||
|         if component in UART_SELECTION_LIBRETINY: |         if component in UART_SELECTION_LIBRETINY: | ||||||
|             return cv.one_of(*UART_SELECTION_LIBRETINY[component], upper=True)(value) |             return cv.one_of(*UART_SELECTION_LIBRETINY[component], upper=True)(value) | ||||||
|  |     if CORE.is_nrf52: | ||||||
|  |         return cv.one_of(*UART_SELECTION_NRF52, upper=True)(value) | ||||||
|     raise NotImplementedError |     raise NotImplementedError | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -179,6 +184,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|                 rp2040=USB_CDC, |                 rp2040=USB_CDC, | ||||||
|                 bk72xx=DEFAULT, |                 bk72xx=DEFAULT, | ||||||
|                 rtl87xx=DEFAULT, |                 rtl87xx=DEFAULT, | ||||||
|  |                 nrf52=USB_CDC, | ||||||
|             ): cv.All( |             ): cv.All( | ||||||
|                 cv.only_on( |                 cv.only_on( | ||||||
|                     [ |                     [ | ||||||
| @@ -187,6 +193,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|                         PLATFORM_RP2040, |                         PLATFORM_RP2040, | ||||||
|                         PLATFORM_BK72XX, |                         PLATFORM_BK72XX, | ||||||
|                         PLATFORM_RTL87XX, |                         PLATFORM_RTL87XX, | ||||||
|  |                         PLATFORM_NRF52, | ||||||
|                     ] |                     ] | ||||||
|                 ), |                 ), | ||||||
|                 uart_selection, |                 uart_selection, | ||||||
| @@ -263,7 +270,7 @@ async def to_code(config): | |||||||
|     if config.get(CONF_ESP8266_STORE_LOG_STRINGS_IN_FLASH): |     if config.get(CONF_ESP8266_STORE_LOG_STRINGS_IN_FLASH): | ||||||
|         cg.add_build_flag("-DUSE_STORE_LOG_STR_IN_FLASH") |         cg.add_build_flag("-DUSE_STORE_LOG_STR_IN_FLASH") | ||||||
|  |  | ||||||
|     if CORE.using_arduino: |     if CORE.using_arduino and not CORE.is_nrf52: | ||||||
|         if config[CONF_HARDWARE_UART] == USB_CDC: |         if config[CONF_HARDWARE_UART] == USB_CDC: | ||||||
|             cg.add_build_flag("-DARDUINO_USB_CDC_ON_BOOT=1") |             cg.add_build_flag("-DARDUINO_USB_CDC_ON_BOOT=1") | ||||||
|             if CORE.is_esp32 and get_esp32_variant() == VARIANT_ESP32C3: |             if CORE.is_esp32 and get_esp32_variant() == VARIANT_ESP32C3: | ||||||
|   | |||||||
| @@ -26,6 +26,10 @@ | |||||||
| #include "esphome/core/hal.h" | #include "esphome/core/hal.h" | ||||||
| #include "esphome/core/log.h" | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_NRF52 | ||||||
|  | #include <Adafruit_TinyUSB.h> // for Serial | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace logger { | namespace logger { | ||||||
|  |  | ||||||
| @@ -228,10 +232,11 @@ void Logger::pre_setup() { | |||||||
|   if (this->baud_rate_ > 0) { |   if (this->baud_rate_ > 0) { | ||||||
| #ifdef USE_ARDUINO | #ifdef USE_ARDUINO | ||||||
|     switch (this->uart_) { |     switch (this->uart_) { | ||||||
|  | #ifndef USE_NRF52 | ||||||
|       case UART_SELECTION_UART0: |       case UART_SELECTION_UART0: | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
|       case UART_SELECTION_UART0_SWAP: |       case UART_SELECTION_UART0_SWAP: | ||||||
| #endif | #endif  // USE_ESP8266 | ||||||
| #ifdef USE_RP2040 | #ifdef USE_RP2040 | ||||||
|         this->hw_serial_ = &Serial1; |         this->hw_serial_ = &Serial1; | ||||||
|         Serial1.begin(this->baud_rate_); |         Serial1.begin(this->baud_rate_); | ||||||
| @@ -242,14 +247,15 @@ void Logger::pre_setup() { | |||||||
| #else | #else | ||||||
|         this->hw_serial_ = &Serial; |         this->hw_serial_ = &Serial; | ||||||
|         Serial.begin(this->baud_rate_); |         Serial.begin(this->baud_rate_); | ||||||
| #endif | #endif  // ARDUINO_USB_CDC_ON_BOOT | ||||||
| #endif | #endif  // USE_RP2040 | ||||||
|  | #endif  // USE_NRF52 | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
|         if (this->uart_ == UART_SELECTION_UART0_SWAP) { |         if (this->uart_ == UART_SELECTION_UART0_SWAP) { | ||||||
|           Serial.swap(); |           Serial.swap(); | ||||||
|         } |         } | ||||||
|         Serial.setDebugOutput(ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE); |         Serial.setDebugOutput(ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE); | ||||||
| #endif | #endif  // USE_ESP8266 | ||||||
|         break; |         break; | ||||||
|       case UART_SELECTION_UART1: |       case UART_SELECTION_UART1: | ||||||
| #ifdef USE_RP2040 | #ifdef USE_RP2040 | ||||||
| @@ -258,10 +264,10 @@ void Logger::pre_setup() { | |||||||
| #else | #else | ||||||
|         this->hw_serial_ = &Serial1; |         this->hw_serial_ = &Serial1; | ||||||
|         Serial1.begin(this->baud_rate_); |         Serial1.begin(this->baud_rate_); | ||||||
| #endif | #endif  // USE_RP2040 | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
|         Serial1.setDebugOutput(ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE); |         Serial1.setDebugOutput(ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE); | ||||||
| #endif | #endif  // USE_ESP8266 | ||||||
|         break; |         break; | ||||||
| #if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ | #if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ | ||||||
|     !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) |     !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) | ||||||
| @@ -290,7 +296,7 @@ void Logger::pre_setup() { | |||||||
| #endif  // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32C3 | #endif  // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32C3 | ||||||
|         break; |         break; | ||||||
| #endif  // USE_ESP32 && (USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32C3) | #endif  // USE_ESP32 && (USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32C3) | ||||||
| #ifdef USE_RP2040 | #if defined(USE_RP2040) || defined(USE_NRF52) | ||||||
|       case UART_SELECTION_USB_CDC: |       case UART_SELECTION_USB_CDC: | ||||||
|         this->hw_serial_ = &Serial; |         this->hw_serial_ = &Serial; | ||||||
|         Serial.begin(this->baud_rate_); |         Serial.begin(this->baud_rate_); | ||||||
| @@ -401,7 +407,7 @@ void Logger::set_log_level(const std::string &tag, int log_level) { | |||||||
|   this->log_levels_.push_back(LogLevelOverride{tag, log_level}); |   this->log_levels_.push_back(LogLevelOverride{tag, log_level}); | ||||||
| } | } | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) | #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_NRF52) | ||||||
| UARTSelection Logger::get_uart() const { return this->uart_; } | UARTSelection Logger::get_uart() const { return this->uart_; } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ namespace esphome { | |||||||
|  |  | ||||||
| namespace logger { | namespace logger { | ||||||
|  |  | ||||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) | #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_NRF52) | ||||||
| /** Enum for logging UART selection | /** Enum for logging UART selection | ||||||
|  * |  * | ||||||
|  * Advanced configuration (pin selection, etc) is not supported. |  * Advanced configuration (pin selection, etc) is not supported. | ||||||
| @@ -37,7 +37,9 @@ enum UARTSelection { | |||||||
|   UART_SELECTION_UART1, |   UART_SELECTION_UART1, | ||||||
|   UART_SELECTION_UART2, |   UART_SELECTION_UART2, | ||||||
| #else | #else | ||||||
|  | #ifndef USE_NRF52 | ||||||
|   UART_SELECTION_UART0 = 0, |   UART_SELECTION_UART0 = 0, | ||||||
|  | #endif | ||||||
|   UART_SELECTION_UART1, |   UART_SELECTION_UART1, | ||||||
| #if defined(USE_ESP32) | #if defined(USE_ESP32) | ||||||
| #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ | #if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ | ||||||
| @@ -58,7 +60,7 @@ enum UARTSelection { | |||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
|   UART_SELECTION_UART0_SWAP, |   UART_SELECTION_UART0_SWAP, | ||||||
| #endif  // USE_ESP8266 | #endif  // USE_ESP8266 | ||||||
| #ifdef USE_RP2040 | #if defined(USE_RP2040) || defined(USE_NRF52) | ||||||
|   UART_SELECTION_USB_CDC, |   UART_SELECTION_USB_CDC, | ||||||
| #endif  // USE_RP2040 | #endif  // USE_RP2040 | ||||||
| #endif  // USE_LIBRETINY | #endif  // USE_LIBRETINY | ||||||
| @@ -78,7 +80,7 @@ class Logger : public Component { | |||||||
| #ifdef USE_ESP_IDF | #ifdef USE_ESP_IDF | ||||||
|   uart_port_t get_uart_num() const { return uart_num_; } |   uart_port_t get_uart_num() const { return uart_num_; } | ||||||
| #endif | #endif | ||||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) | #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_NRF52) | ||||||
|   void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; } |   void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; } | ||||||
|   /// Get the UART used by the logger. |   /// Get the UART used by the logger. | ||||||
|   UARTSelection get_uart() const; |   UARTSelection get_uart() const; | ||||||
| @@ -165,6 +167,9 @@ class Logger : public Component { | |||||||
| #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) | #if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) | ||||||
|   UARTSelection uart_{UART_SELECTION_UART0}; |   UARTSelection uart_{UART_SELECTION_UART0}; | ||||||
| #endif | #endif | ||||||
|  | #ifdef USE_NRF52 | ||||||
|  |   UARTSelection uart_{UART_SELECTION_USB_CDC}; | ||||||
|  | #endif | ||||||
| #ifdef USE_LIBRETINY | #ifdef USE_LIBRETINY | ||||||
|   UARTSelection uart_{UART_SELECTION_DEFAULT}; |   UARTSelection uart_{UART_SELECTION_DEFAULT}; | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										112
									
								
								esphome/components/nrf52/gpio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								esphome/components/nrf52/gpio.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | #ifdef USE_NRF52 | ||||||
|  |  | ||||||
|  | #include "gpio.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include <functional> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace nrf52 { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "nrf52"; | ||||||
|  |  | ||||||
|  | static int IRAM_ATTR flags_to_mode(gpio::Flags flags, uint8_t pin) { | ||||||
|  | // For nRF52 extra modes are available. | ||||||
|  | // Standard drive is typically 2mA (min 1mA) '0' sink (low) or '1' source (high). High drive (VDD > 2.7V) is typically 10mA low, 9mA high (min 6mA) | ||||||
|  | // OUTPUT_S0S1 Standard '0', standard '1' same as OUTPUT | ||||||
|  | // OUTPUT_H0S1 High drive '0', standard '1' | ||||||
|  | // OUTPUT_S0H1 Standard '0', high drive '1' | ||||||
|  | // OUTPUT_H0H1 High drive '0', high 'drive '1'' | ||||||
|  | // OUTPUT_D0S1 Disconnect '0' standard '1' (normally used for wired-or connections) | ||||||
|  | // OUTPUT_D0H1 Disconnect '0', high drive '1' (normally used for wired-or connections) | ||||||
|  | // OUTPUT_S0D1 Standard '0'. disconnect '1' (normally used for wired-and connections) | ||||||
|  | // OUTPUT_H0D1 High drive '0', disconnect '1' (normally used for wired-and connections) | ||||||
|  | // NOTE P0.27 should be only low (standard) drive, low frequency | ||||||
|  |   if (flags == gpio::FLAG_INPUT) {  // NOLINT(bugprone-branch-clone) | ||||||
|  |     return INPUT; | ||||||
|  |   } else if (flags == gpio::FLAG_OUTPUT) { | ||||||
|  |     return OUTPUT; | ||||||
|  |   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { | ||||||
|  |     return INPUT_PULLUP; | ||||||
|  |   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { | ||||||
|  |     return INPUT_PULLDOWN; | ||||||
|  |   } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { | ||||||
|  |       return OUTPUT_S0D1; | ||||||
|  |   } else { | ||||||
|  |     return INPUT; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct ISRPinArg { | ||||||
|  |   uint8_t pin; | ||||||
|  |   bool inverted; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //TODO implement | ||||||
|  | //TODO test | ||||||
|  | void (*irq_cb)(void *); | ||||||
|  | void* irq_arg; | ||||||
|  | static void pin_irq(void){ | ||||||
|  |   irq_cb(irq_arg); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ISRInternalGPIOPin NRF52GPIOPin::to_isr() const { | ||||||
|  |   auto *arg = new ISRPinArg{};  // NOLINT(cppcoreguidelines-owning-memory) | ||||||
|  |   arg->pin = pin_; | ||||||
|  |   arg->inverted = inverted_; | ||||||
|  |   return ISRInternalGPIOPin((void *) arg); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NRF52GPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { | ||||||
|  |   uint32_t mode = ISR_DEFERRED; | ||||||
|  |   switch (type) { | ||||||
|  |     case gpio::INTERRUPT_RISING_EDGE: | ||||||
|  |       mode |= inverted_ ? FALLING : RISING; | ||||||
|  |       break; | ||||||
|  |     case gpio::INTERRUPT_FALLING_EDGE: | ||||||
|  |       mode |= inverted_ ? RISING : FALLING; | ||||||
|  |       break; | ||||||
|  |     case gpio::INTERRUPT_ANY_EDGE: | ||||||
|  |       mode |= CHANGE; | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   irq_cb = func; | ||||||
|  |   irq_arg = arg; | ||||||
|  |   attachInterrupt(pin_, pin_irq, mode); | ||||||
|  | } | ||||||
|  | void NRF52GPIOPin::pin_mode(gpio::Flags flags) { | ||||||
|  |   pinMode(pin_, flags_to_mode(flags, pin_));  // NOLINT | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string NRF52GPIOPin::dump_summary() const { | ||||||
|  |   char buffer[32]; | ||||||
|  |   snprintf(buffer, sizeof(buffer), "GPIO%u", pin_); | ||||||
|  |   return buffer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool NRF52GPIOPin::digital_read() { | ||||||
|  |   return bool(digitalRead(pin_)) != inverted_;  // NOLINT | ||||||
|  | } | ||||||
|  | void NRF52GPIOPin::digital_write(bool value) { | ||||||
|  |   digitalWrite(pin_, value != inverted_ ? 1 : 0);  // NOLINT | ||||||
|  | } | ||||||
|  | void NRF52GPIOPin::detach_interrupt() const { | ||||||
|  |    detachInterrupt(pin_);  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace nrf52 | ||||||
|  |  | ||||||
|  | // using namespace nrf52; | ||||||
|  |  | ||||||
|  | // TODO seems to not work??? | ||||||
|  | bool IRAM_ATTR ISRInternalGPIOPin::digital_read() { | ||||||
|  |   auto *arg = reinterpret_cast<nrf52::ISRPinArg *>(arg_); | ||||||
|  |   return bool(digitalRead(arg->pin)) != arg->inverted;  // NOLINT | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_NRF52 | ||||||
							
								
								
									
										38
									
								
								esphome/components/nrf52/gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								esphome/components/nrf52/gpio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef USE_NRF52 | ||||||
|  |  | ||||||
|  | #include <Arduino.h> | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace nrf52 { | ||||||
|  |  | ||||||
|  | class NRF52GPIOPin : public InternalGPIOPin { | ||||||
|  |  public: | ||||||
|  |   void set_pin(uint8_t pin) { pin_ = pin; } | ||||||
|  |   void set_inverted(bool inverted) { inverted_ = inverted; } | ||||||
|  |   void set_flags(gpio::Flags flags) { flags_ = flags; } | ||||||
|  |  | ||||||
|  |   void setup() override { pin_mode(flags_); } | ||||||
|  |   void pin_mode(gpio::Flags flags) override; | ||||||
|  |   bool digital_read() override; | ||||||
|  |   void digital_write(bool value) override; | ||||||
|  |   std::string dump_summary() const override; | ||||||
|  |   void detach_interrupt() const override; | ||||||
|  |   ISRInternalGPIOPin to_isr() const override; | ||||||
|  |   uint8_t get_pin() const override { return pin_; } | ||||||
|  |   bool is_inverted() const override { return inverted_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override; | ||||||
|  |  | ||||||
|  |   uint8_t pin_; | ||||||
|  |   bool inverted_; | ||||||
|  |   gpio::Flags flags_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace nrf52 | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_NRF52 | ||||||
							
								
								
									
										58
									
								
								esphome/components/nrf52/gpio.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								esphome/components/nrf52/gpio.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | from esphome import pins | ||||||
|  |  | ||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_MODE, | ||||||
|  |     CONF_INVERTED, | ||||||
|  |     CONF_NUMBER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | nrf52_ns = cg.esphome_ns.namespace("nrf52") | ||||||
|  | NRF52GPIOPin = nrf52_ns.class_("NRF52GPIOPin", cg.InternalGPIOPin) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _translate_pin(value): | ||||||
|  |     if isinstance(value, dict) or value is None: | ||||||
|  |         raise cv.Invalid( | ||||||
|  |             "This variable only supports pin numbers, not full pin schemas " | ||||||
|  |             "(with inverted and mode)." | ||||||
|  |         ) | ||||||
|  |     if isinstance(value, int): | ||||||
|  |         return value | ||||||
|  |     try: | ||||||
|  |         return int(value) | ||||||
|  |     except ValueError: | ||||||
|  |         pass | ||||||
|  |     # e.g. P0.27 | ||||||
|  |     if len(value) >= len("P0.0") and value[0] == "P" and value[2] == ".": | ||||||
|  |         return cv.int_(value[len("P")].strip()) * 32 + cv.int_( | ||||||
|  |             value[len("P0.") :].strip() | ||||||
|  |         ) | ||||||
|  |     raise cv.Invalid(f"Invalid pin: {value}") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def validate_gpio_pin(value): | ||||||
|  |     value = _translate_pin(value) | ||||||
|  |     if value < 0 or value > (32 + 16): | ||||||
|  |         raise cv.Invalid(f"NRF52: Invalid pin number: {value}") | ||||||
|  |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NRF52_PIN_SCHEMA = cv.All( | ||||||
|  |     pins.gpio_base_schema( | ||||||
|  |         NRF52GPIOPin, | ||||||
|  |         validate_gpio_pin, | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pins.PIN_SCHEMA_REGISTRY.register("nrf52", NRF52_PIN_SCHEMA) | ||||||
|  | async def nrf52_pin_to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     num = config[CONF_NUMBER] | ||||||
|  |     cg.add(var.set_pin(num)) | ||||||
|  |     cg.add(var.set_inverted(config[CONF_INVERTED])) | ||||||
|  |     cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE]))) | ||||||
|  |     return var | ||||||
| @@ -1548,6 +1548,7 @@ class SplitDefault(Optional): | |||||||
|         bk72xx=vol.UNDEFINED, |         bk72xx=vol.UNDEFINED, | ||||||
|         rtl87xx=vol.UNDEFINED, |         rtl87xx=vol.UNDEFINED, | ||||||
|         host=vol.UNDEFINED, |         host=vol.UNDEFINED, | ||||||
|  |         nrf52=vol.UNDEFINED, | ||||||
|     ): |     ): | ||||||
|         super().__init__(key) |         super().__init__(key) | ||||||
|         self._esp8266_default = vol.default_factory(esp8266) |         self._esp8266_default = vol.default_factory(esp8266) | ||||||
| @@ -1579,6 +1580,7 @@ class SplitDefault(Optional): | |||||||
|         self._bk72xx_default = vol.default_factory(bk72xx) |         self._bk72xx_default = vol.default_factory(bk72xx) | ||||||
|         self._rtl87xx_default = vol.default_factory(rtl87xx) |         self._rtl87xx_default = vol.default_factory(rtl87xx) | ||||||
|         self._host_default = vol.default_factory(host) |         self._host_default = vol.default_factory(host) | ||||||
|  |         self._nrf52 = vol.default_factory(nrf52) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def default(self): |     def default(self): | ||||||
| @@ -1621,6 +1623,8 @@ class SplitDefault(Optional): | |||||||
|             return self._rtl87xx_default |             return self._rtl87xx_default | ||||||
|         if CORE.is_host: |         if CORE.is_host: | ||||||
|             return self._host_default |             return self._host_default | ||||||
|  |         if CORE.is_nrf52: | ||||||
|  |             return self._nrf52 | ||||||
|         raise NotImplementedError |         raise NotImplementedError | ||||||
|  |  | ||||||
|     @default.setter |     @default.setter | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ PLATFORM_HOST = "host" | |||||||
| PLATFORM_BK72XX = "bk72xx" | PLATFORM_BK72XX = "bk72xx" | ||||||
| PLATFORM_RTL87XX = "rtl87xx" | PLATFORM_RTL87XX = "rtl87xx" | ||||||
| PLATFORM_LIBRETINY_OLDSTYLE = "libretiny" | PLATFORM_LIBRETINY_OLDSTYLE = "libretiny" | ||||||
|  | PLATFORM_NRF52 = "nrf52" | ||||||
|  |  | ||||||
| TARGET_PLATFORMS = [ | TARGET_PLATFORMS = [ | ||||||
|     PLATFORM_ESP32, |     PLATFORM_ESP32, | ||||||
| @@ -23,6 +24,7 @@ TARGET_PLATFORMS = [ | |||||||
|     PLATFORM_BK72XX, |     PLATFORM_BK72XX, | ||||||
|     PLATFORM_RTL87XX, |     PLATFORM_RTL87XX, | ||||||
|     PLATFORM_LIBRETINY_OLDSTYLE, |     PLATFORM_LIBRETINY_OLDSTYLE, | ||||||
|  |     PLATFORM_NRF52, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"} | SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"} | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ from esphome.const import ( | |||||||
|     PLATFORM_RTL87XX, |     PLATFORM_RTL87XX, | ||||||
|     PLATFORM_RP2040, |     PLATFORM_RP2040, | ||||||
|     PLATFORM_HOST, |     PLATFORM_HOST, | ||||||
|  |     PLATFORM_NRF52, | ||||||
| ) | ) | ||||||
| from esphome.coroutine import FakeAwaitable as _FakeAwaitable | from esphome.coroutine import FakeAwaitable as _FakeAwaitable | ||||||
| from esphome.coroutine import FakeEventLoop as _FakeEventLoop | from esphome.coroutine import FakeEventLoop as _FakeEventLoop | ||||||
| @@ -659,6 +660,10 @@ class EsphomeCore: | |||||||
|     def is_host(self): |     def is_host(self): | ||||||
|         return self.target_platform == PLATFORM_HOST |         return self.target_platform == PLATFORM_HOST | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def is_nrf52(self): | ||||||
|  |         return self.target_platform == PLATFORM_NRF52 | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def target_framework(self): |     def target_framework(self): | ||||||
|         return self.data[KEY_CORE][KEY_TARGET_FRAMEWORK] |         return self.data[KEY_CORE][KEY_TARGET_FRAMEWORK] | ||||||
|   | |||||||
| @@ -20,6 +20,8 @@ | |||||||
| #elif defined(USE_LIBRETINY) | #elif defined(USE_LIBRETINY) | ||||||
| #include <FreeRTOS.h> | #include <FreeRTOS.h> | ||||||
| #include <semphr.h> | #include <semphr.h> | ||||||
|  | #elif defined(USE_NRF52) | ||||||
|  | #include <Arduino.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #define HOT __attribute__((hot)) | #define HOT __attribute__((hot)) | ||||||
| @@ -546,7 +548,7 @@ class Mutex { | |||||||
|   Mutex &operator=(const Mutex &) = delete; |   Mutex &operator=(const Mutex &) = delete; | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) | #if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_NRF52) | ||||||
|   SemaphoreHandle_t handle_; |   SemaphoreHandle_t handle_; | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user