ESP32 Support Sponsored by AutonoSky

nsh console running on USB
param module running
working with i2c and common drivers
provided implementation for drv_pwm_output.h
i2cdetect working as expected with no device
mavlink started succesfully
mounts sd card and logger runs
logger to file succesfully
pwm_servo implemented without using Nuttx lib
pwm_out outputs expected waveforms
- however currently if the frequency is higher than what the pwm_out
driver runs, there will be aliasing, based on how the registers gets
resets
wifi softap working
- Seeing wifi hotspot
- cant connect due to wrong password
- problems with adjusting ssid and password
wifi ssid and password being set accordinglu
connected to wifi hotspot with dhpcd
- made some changes to nuttx to only build for SoftAP mode, however this
was effectivelyy removing the ifdef for STATION mode. Should investigate
the coexist option again
added ifdef to not use timer 0 when wifi enabled
- reverted esp32 rt_timer to make use of timer 0 by default

fix setting incorrect bit in hrt timer register

- hrt running as expected, but on startup the pwm_out driver starts up
at about 200Hz and then rises over a minute or so 250Hz. Not sure if
this was present previously, and could be due to Wifi running at time
priority on timer 0

pull xtensa compilers in setup.ubuntu.sh
revert logger stacksize and cmake argument
esp32 chip revision and PX4 UUID implemented

spi board reset implemented, formatting checked

devkit acts on startup as a wifi bridge for comms

- the most usefull setting for the general developer when buying a esp32 devkit
- testing Mavlink shell using ./Tools/mavlink_shell.py
- todo: Test mavlink messages being forward

improve wifi telemetry by increasing prio

- Remove power save mode on wifi
- increased daemon thread schedule priority to 50

compiles without Nuttx changes

- updated compiler settings to match those of nuttx on px4 side

add espressif_esp32 to excluded boards

ci: allow docker to find xtensa compilers
This commit is contained in:
henrykotze
2025-08-19 11:09:56 -07:00
committed by Ramon Roche
parent b3c7667f41
commit 8b58c01cd7
62 changed files with 8450 additions and 1 deletions
@@ -129,7 +129,11 @@ bool SerialImpl::configure()
default:
speed = _baudrate;
#ifdef CONFIG_ARCH_CHIP_ESP32
PX4_WARN("Using non-standard baudrate: %u", _baudrate);
#else
PX4_WARN("Using non-standard baudrate: %lu", _baudrate);
#endif
break;
}
@@ -0,0 +1,34 @@
############################################################################
#
# Copyright (c) 2019 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
add_subdirectory(${PX4_CHIP})
@@ -0,0 +1,6 @@
add_subdirectory(hrt hrt)
add_subdirectory(version version)
add_subdirectory(board_critmon board_critmon)
add_subdirectory(board_reset board_reset)
add_subdirectory(spi spi)
add_subdirectory(io_pins io_pins)
@@ -0,0 +1,36 @@
############################################################################
#
# Copyright (C) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(arch_board_critmon
board_critmon.c
)
@@ -0,0 +1,66 @@
/************************************************************************************
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
/************************************************************************************
* Included Files
************************************************************************************/
#include <nuttx/config.h>
#include <arch/board/board.h>
#if defined(CONFIG_SCHED_CRITMONITOR) || defined(CONFIG_SCHED_IRQMONITOR)
/************************************************************************************
* Public Functions
************************************************************************************/
#error "missing implementation for up_critmon_gettime() and up_critmon_convert()"
/************************************************************************************
* Name: up_critmon_gettime
************************************************************************************/
// uint32_t up_critmon_gettime(void)
// {
// }
/************************************************************************************
* Name: up_critmon_convert
************************************************************************************/
// void up_critmon_convert(uint32_t elapsed, FAR struct timespec *ts)
// {
// }
#endif /* CONFIG_SCHED_CRITMONITOR */
@@ -0,0 +1,43 @@
############################################################################
#
# Copyright (C) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(arch_board_reset
board_reset.cpp
)
# up_systemreset
if (NOT DEFINED CONFIG_BUILD_FLAT)
target_link_libraries(arch_board_reset PRIVATE nuttx_karch)
else()
target_link_libraries(arch_board_reset PRIVATE nuttx_arch)
endif()
@@ -0,0 +1,105 @@
/****************************************************************************
*
* Copyright (C) 2021 PX4 Development Team. All rights reserved.
* Author: @author David Sidrane <david_s5@nscdg.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file board_reset.cpp
* Implementation of RP2040 based Board RESET API
*/
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/shutdown.h>
#include <systemlib/px4_macros.h>
#include <errno.h>
#include <nuttx/board.h>
#include <nuttx/arch.h>
#include "esp32_systemreset.h"
// Functions in here are modified so that board_reset() function resembles
// the one available in nuttx's boards/raspberrypi-pico folder.
#ifdef CONFIG_BOARDCTL_RESET
/****************************************************************************
* Name: board_reset
*
* Description:
* Reset board. Support for this function is required by board-level
* logic if CONFIG_BOARDCTL_RESET is selected.
*
* Input Parameters:
* status - Status information provided with the reset event. This
* meaning of this status information is board-specific. If not
* used by a board, the value zero may be provided in calls to
* board_reset().
*
* Returned Value:
* If this function returns, then it was not possible to power-off the
* board due to some constraints. The return value int this case is a
* board-specific reason for the failure to shutdown.
*
****************************************************************************/
int board_reset(int status)
{
up_systemreset();
return 0;
}
#endif /* CONFIG_BOARDCTL_RESET */
#if defined(SUPPORT_ALT_CAN_BOOTLOADER)
/****************************************************************************
* Name: board_booted_by_px4
*
* Description:
* Determines if the the boot loader was PX4
*
* Input Parameters:
* none
*
* Returned Value:
* true if booted byt a PX4 bootloader.
*
****************************************************************************/
bool board_booted_by_px4(void)
{
uint32_t *vectors = (uint32_t *) STM32_FLASH_BASE;
/* Nuttx uses common vector */
return (vectors[2] == vectors[3]) && (vectors[4] == vectors[5]);
}
#endif
@@ -0,0 +1,41 @@
############################################################################
#
# Copyright (c) 2015-2019 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(arch_hrt
hrt.c
)
target_compile_options(arch_hrt
PRIVATE
${MAX_CUSTOM_OPT_LEVEL}
-Wno-cast-align # TODO: fix and enable
)
@@ -0,0 +1,636 @@
/****************************************************************************
*
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file drv_hrt.c
*
* High-resolution timer callouts and timekeeping.
*
* This can use any general or advanced STM32 timer.
*
* Note that really, this could use systick too, but that's
* monopolised by NuttX and stealing it would just be awkward.
*
* We don't use the NuttX STM32 driver per se; rather, we
* claim the timer and then drive it directly.
*/
#include <px4_platform_common/px4_config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <sys/types.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include <time.h>
#include <queue.h>
#include <errno.h>
#include <string.h>
#include "esp32_irq.h"
#include <xtensa.h>
#include <board_config.h>
#include <drivers/drv_hrt.h>
#ifdef CONFIG_DEBUG_HRT
# define hrtinfo _info
#else
# define hrtinfo(x...)
#endif
#ifdef HRT_TIMER
/* HRT configuration */
#if HRT_TIMER == 0
# define HRT_TIM_BASE 0x3ff5f000
# define HRT_TIMER_PERIPH 14
# define HRT_TIMER_PRIO 1
# define HRT_TIMER_VECTOR 5 + HRT_TIMER_PERIPH
# define HRT_TIMER_CLOCK 80 * 1000000
# define HRT_TIMER_BASE 0x3ff5f000
# define HRT_TIMER_CLR_OFFSET 0x00a4
# define HRT_TIMER_INT_ENA_OFFSET 0x0098
# define HRT_TIMER_INT_CLR 1 << 0
# if CONFIG_ESP32_WIFI
# error must not set CONFIG_ESP32_WIFI=y and HRT_TIMER=0. WIFI makes use of TIMER=0
# endif
#elif HRT_TIMER == 1
# define HRT_TIM_BASE 0x3ff5f000 + 0x0024
# define HRT_TIMER_PERIPH 15
# define HRT_TIMER_PRIO 1
# define HRT_TIMER_VECTOR 5 + HRT_TIMER_PERIPH
# define HRT_TIMER_CLOCK 80 * 1000000
# define HRT_TIMER_BASE 0x3ff5f000 + 0x0024
# define HRT_TIMER_CLR_OFFSET 0x0080
# define HRT_TIMER_INT_ENA_OFFSET 0x0074
# define HRT_TIMER_INT_CLR 1 << 1
# if CONFIG_ESP32_TIMER1
# error must not set CONFIG_ESP32_TIMER1=y and HRT_TIMER=1
# endif
#elif HRT_TIMER == 2
# define HRT_TIM_BASE 0x3ff5f000 + 0x1000
# define HRT_TIMER_PERIPH 18
# define HRT_TIMER_PRIO 1
# define HRT_TIMER_VECTOR 5 + HRT_TIMER_PERIPH
# define HRT_TIMER_CLOCK 80 * 1000000
# define HRT_TIMER_BASE 0x3ff5f000 + 0x1000
# define HRT_TIMER_CLR_OFFSET 0x00a4
# define HRT_TIMER_INT_ENA_OFFSET 0x0098
# define HRT_TIMER_INT_CLR 1 << 0
# if CONFIG_ESP32_TIMER2
# error must not set CONFIG_ESP32_TIMER2=y and HRT_TIMER=2
# endif
#elif HRT_TIMER == 3
# define HRT_TIM_BASE 0x3ff5f000 + 0x0024 + 0x1000
# define HRT_TIMER_PERIPH 19
# define HRT_TIMER_PRIO 1
# define HRT_TIMER_VECTOR 5 + HRT_TIMER_PERIPH
# define HRT_TIMER_CLOCK 80 * 1000000
# define HRT_TIMER_BASE 0x3ff5f000 + 0x0024 + 0x1000
# define HRT_TIMER_CLR_OFFSET 0x0080
# define HRT_TIMER_INT_ENA_OFFSET 0x0074
# define HRT_TIMER_INT_CLR 1 << 1
# if CONFIG_ESP32_TIMER3
# error must not set CONFIG_ESP32_TIMER3=y and HRT_TIMER=3
# endif
#else
# error HRT_TIMER must be a value between 0 and 3
#endif
#define REG(_reg) (*(volatile uint32_t *)(HRT_TIMER_BASE + _reg))
#define HRT_CONFIG_OFFSET 0x00
#define HRT_LOAD_LO_OFFSET 0x0018
#define HRT_LOAD_HI_OFFSET 0x001c
#define HRT_LOAD_OFFSET 0x0020
#define HRT_ALARM_LO_OFFSET 0x0010
#define HRT_ALARM_HI_OFFSET 0x0014
#define HRT_UPDATE_OFFSET 0x000c
#define HRT_LO_OFFSET 0x0004
#define HRT_HI_OFFSET 0x0008
#define HRT_DIVIDER_S 13
#define HRT_DIVIDER_M 0xffff << 13
#define HRT_ALARM_EN 1 << 10
#define HRT_AUTORELOAD 1 << 29
#define HRT_TIMER_LEVEL_INT_EN 1 << 11
#define HRT_TIMER_INT_ENA 1 << 0
#define HRT_TIMER_EN 1 << 31
#define HRT_INCREASE 1 << 30
#define rLO REG(HRT_LO_OFFSET)
#define rHI REG(HRT_HI_OFFSET)
#define rUPDATE REG(HRT_UPDATE_OFFSET)
#define rALARMLO REG(HRT_ALARM_LO_OFFSET)
#define rALARMHI REG(HRT_ALARM_HI_OFFSET)
/*
* HRT clock must be a multiple of 1MHz greater than 1MHz
*/
#if (HRT_TIMER_CLOCK % 1000000) != 0
# error HRT_TIMER_CLOCK must be a multiple of 1MHz
#endif
#if HRT_TIMER_CLOCK <= 1000000
# error HRT_TIMER_CLOCK must be greater than 1MHz
#endif
/**
* Minimum/maximum deadlines.
*
* These are suitable for use with a 16-bit timer/counter clocked
* at 1MHz. The high-resolution timer need only guarantee that it
* not wrap more than once in the 50ms period for absolute time to
* be consistently maintained.
*
* The minimum deadline must be such that the time taken between
* reading a time and writing a deadline to the timer cannot
* result in missing the deadline.
*/
#define HRT_INTERVAL_MIN 50
#define HRT_INTERVAL_MAX 50000
/*
* Period of the free-running counter, in microseconds.
*/
#define HRT_COUNTER_PERIOD 18446744073709551615
/*
* Scaling factor(s) for the free-running counter; convert an input
* in counts to a time in microseconds.
*/
#define HRT_COUNTER_SCALE(_c) (_c)
/*
* Queue of callout entries.
*/
static struct sq_queue_s callout_queue;
/* latency baseline (last compare value applied) */
static uint64_t latency_baseline;
/* timer count at interrupt (for latency purposes) */
static uint64_t latency_actual;
/* latency histogram */
const uint16_t latency_bucket_count = LATENCY_BUCKET_COUNT;
const uint16_t latency_buckets[LATENCY_BUCKET_COUNT] = { 1, 2, 5, 10, 20, 50, 100, 1000 };
__EXPORT uint32_t latency_counters[LATENCY_BUCKET_COUNT + 1];
/* timer-specific functions */
static void hrt_tim_init(void);
static int hrt_tim_isr(int irq, void *context, void *arg);
static void hrt_latency_update(void);
static void esp32_tim_modifyreg32(uint32_t base, uint32_t offset, uint32_t clearbits, uint32_t setbits);
static void esp32_tim_putreg(uint32_t base, uint32_t offset, uint32_t value);
static uint32_t esp32_tim_getreg(uint32_t base, uint32_t offset);
/* callout list manipulation */
static void hrt_call_internal(struct hrt_call *entry,
hrt_abstime deadline,
hrt_abstime interval,
hrt_callout callout,
void *arg);
static void hrt_call_enter(struct hrt_call *entry);
static void hrt_call_reschedule(void);
static void hrt_call_invoke(void);
int hrt_ioctl(unsigned int cmd, unsigned long arg);
static void esp32_tim_modifyreg32(uint32_t base, uint32_t offset, uint32_t clearbits, uint32_t setbits)
{
modifyreg32(base + offset, clearbits, setbits);
}
static void esp32_tim_putreg(uint32_t base, uint32_t offset, uint32_t value)
{
putreg32(value, base + offset);
}
static uint32_t esp32_tim_getreg(uint32_t base, uint32_t offset)
{
return getreg32(base + offset);
}
/**
* Initialise the timer we are going to use.
*
* We expect that we'll own one of the reduced-function STM32 general
* timers, and that we can use channel 1 in compare mode.
*/
static void
hrt_tim_init(void)
{
// ESP32_TIM_SETPRE(tim, ESP32_HRT_TIMER_PRESCALER);
uint32_t mask = ((uint32_t)(HRT_TIMER_CLOCK / 1000000) - 1) << HRT_DIVIDER_S;
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, HRT_DIVIDER_M, mask);
// ESP32_TIM_SETMODE(tim, ESP32_TIM_MODE_UP);
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, 0, HRT_INCREASE);
// ESP32_TIM_CLEAR(tim);
esp32_tim_putreg(HRT_TIM_BASE, HRT_LOAD_LO_OFFSET, 0);
esp32_tim_putreg(HRT_TIM_BASE, HRT_LOAD_HI_OFFSET, 0);
esp32_tim_putreg(HRT_TIM_BASE, HRT_LOAD_OFFSET, 1 << 0); //reload
// ESP32_TIM_SETCTR(tim, 0); //set counter value
esp32_tim_putreg(HRT_TIM_BASE, HRT_LOAD_LO_OFFSET, 0);
esp32_tim_putreg(HRT_TIM_BASE, HRT_LOAD_HI_OFFSET, 0);
// ESP32_TIM_RLD_NOW(tim); //reload value now
esp32_tim_putreg(HRT_TIM_BASE, HRT_LOAD_OFFSET, 1 << 0); //reload
// ESP32_TIM_SETALRVL(tim, 1000); //alarm value
uint64_t val = 1000;
uint64_t low_64 = val & 0xffffffff;
uint64_t high_64 = (val >> 32) & 0xffffffff;
esp32_tim_putreg(HRT_TIM_BASE, HRT_ALARM_LO_OFFSET, (uint32_t)low_64);
esp32_tim_putreg(HRT_TIM_BASE, HRT_ALARM_HI_OFFSET, (uint32_t)high_64);
// ESP32_TIM_SETALRM(tim, true); //enable alarm
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, 0, HRT_ALARM_EN);
// ESP32_TIM_SETARLD(tim, false); //auto reload
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, HRT_AUTORELOAD, 0);
// ESP32_TIM_SETISR(tim, hrt_tim_isr, NULL);
esp32_setup_irq(0, HRT_TIMER_PERIPH, HRT_TIMER_PRIO, ESP32_CPUINT_LEVEL);
irq_attach(HRT_TIMER_VECTOR, hrt_tim_isr, NULL);
up_enable_irq(HRT_TIMER_VECTOR);
// ESP32_TIM_ENABLEINT(tim);
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, 0, HRT_TIMER_LEVEL_INT_EN);
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_TIMER_INT_ENA_OFFSET, 0, HRT_TIMER_INT_ENA);
// ESP32_TIM_START(tim);
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, 0, HRT_TIMER_EN);
}
/**
* Handle the compare interrupt by calling the callout dispatcher
* and then re-scheduling the next deadline.
*/
static int IRAM_ATTR
hrt_tim_isr(int irq, void *context, void *arg)
{
// uint32_t status = REG_READ(DPORT_APP_INTR_STATUS_1_REG);
/* grab the timer for latency tracking purposes */
uint32_t value_32;
latency_actual = 0;
/* Dummy value to latch the counter value to read it */
esp32_tim_putreg(HRT_TIM_BASE, HRT_UPDATE_OFFSET, 1 << 0);
/* Read value */
value_32 = esp32_tim_getreg(HRT_TIM_BASE, HRT_HI_OFFSET); /* High 32 bits */
latency_actual |= (uint64_t)value_32;
latency_actual <<= 32;
value_32 = esp32_tim_getreg(HRT_TIM_BASE, HRT_LO_OFFSET); /* Low 32 bits */
latency_actual |= (uint64_t)value_32;
/* do latency calculations */
hrt_latency_update();
/* run any callouts that have met their deadline */
hrt_call_invoke();
/* and schedule the next interrupt */
hrt_call_reschedule();
// acknowledge the interrupt
esp32_tim_putreg(HRT_TIM_BASE, HRT_TIMER_CLR_OFFSET, HRT_TIMER_INT_CLR);
esp32_tim_modifyreg32(HRT_TIM_BASE, HRT_CONFIG_OFFSET, 0, HRT_ALARM_EN);
return OK;
}
/**
* Fetch a never-wrapping absolute time value in microseconds from
* some arbitrary epoch shortly after system start.
*/
hrt_abstime IRAM_ATTR
hrt_absolute_time(void)
{
hrt_abstime abstime;
// uint64_t count;
irqstate_t flags;
/*
* Counter state. Marked volatile as they may change
* inside this routine but outside the irqsave/restore
* pair. Discourage the compiler from moving loads/stores
* to these outside of the protected range.
*/
// static volatile uint64_t last_count;
/* prevent re-entry */
flags = px4_enter_critical_section();
rUPDATE = 1;
abstime = (hrt_abstime)(((uint64_t)rHI << 32) | (uint64_t)rLO);
px4_leave_critical_section(flags);
return abstime;
}
/**
* Store the absolute time in an interrupt-safe fashion
*/
void
hrt_store_absolute_time(volatile hrt_abstime *t)
{
irqstate_t flags = px4_enter_critical_section();
*t = hrt_absolute_time();
px4_leave_critical_section(flags);
}
/**
* Initialise the high-resolution timing module.
*/
void
hrt_init(void)
{
sq_init(&callout_queue);
hrt_tim_init();
}
/**
* Call callout(arg) after interval has elapsed.
*/
void __attribute__((section(".iram1")))
hrt_call_after(struct hrt_call *entry, hrt_abstime delay, hrt_callout callout, void *arg)
{
hrt_call_internal(entry,
hrt_absolute_time() + delay,
0,
callout,
arg);
}
/**
* Call callout(arg) at calltime.
*/
void __attribute__((section(".iram1")))
hrt_call_at(struct hrt_call *entry, hrt_abstime calltime, hrt_callout callout, void *arg)
{
hrt_call_internal(entry, calltime, 0, callout, arg);
}
/**
* Call callout(arg) every period.
*/
void __attribute__((section(".iram1")))
hrt_call_every(struct hrt_call *entry, hrt_abstime delay, hrt_abstime interval, hrt_callout callout, void *arg)
{
hrt_call_internal(entry,
hrt_absolute_time() + delay,
interval,
callout,
arg);
}
static void __attribute__((section(".iram1")))
hrt_call_internal(struct hrt_call *entry, hrt_abstime deadline, hrt_abstime interval, hrt_callout callout, void *arg)
{
irqstate_t flags = px4_enter_critical_section();
/* if the entry is currently queued, remove it */
/* note that we are using a potentially uninitialised
entry->link here, but it is safe as sq_rem() doesn't
dereference the passed node unless it is found in the
list. So we potentially waste a bit of time searching the
queue for the uninitialised entry->link but we don't do
anything actually unsafe.
*/
if (entry->deadline != 0) {
sq_rem(&entry->link, &callout_queue);
}
entry->deadline = deadline;
entry->period = interval;
entry->callout = callout;
entry->arg = arg;
hrt_call_enter(entry);
px4_leave_critical_section(flags);
}
/**
* If this returns true, the call has been invoked and removed from the callout list.
*
* Always returns false for repeating callouts.
*/
bool __attribute__((section(".iram1")))
hrt_called(struct hrt_call *entry)
{
return (entry->deadline == 0);
}
/**
* Remove the entry from the callout list.
*/
void __attribute__((section(".iram1")))
hrt_cancel(struct hrt_call *entry)
{
irqstate_t flags = px4_enter_critical_section();
sq_rem(&entry->link, &callout_queue);
entry->deadline = 0;
/* if this is a periodic call being removed by the callout, prevent it from
* being re-entered when the callout returns.
*/
entry->period = 0;
px4_leave_critical_section(flags);
}
static void __attribute__((section(".iram1")))
hrt_call_enter(struct hrt_call *entry)
{
struct hrt_call *call, *next;
call = (struct hrt_call *)sq_peek(&callout_queue);
if ((call == NULL) || (entry->deadline < call->deadline)) {
sq_addfirst(&entry->link, &callout_queue);
hrtinfo("call enter at head, reschedule\n");
/* we changed the next deadline, reschedule the timer event */
hrt_call_reschedule();
} else {
do {
next = (struct hrt_call *)sq_next(&call->link);
if ((next == NULL) || (entry->deadline < next->deadline)) {
hrtinfo("call enter after head\n");
sq_addafter(&call->link, &entry->link, &callout_queue);
break;
}
} while ((call = next) != NULL);
}
hrtinfo("scheduled\n");
}
static void __attribute__((section(".iram1")))
hrt_call_invoke(void)
{
struct hrt_call *call;
hrt_abstime deadline;
while (true) {
/* get the current time */
hrt_abstime now = hrt_absolute_time();
call = (struct hrt_call *)sq_peek(&callout_queue);
if (call == NULL) {
break;
}
if (call->deadline > now) {
break;
}
sq_rem(&call->link, &callout_queue);
hrtinfo("call pop\n");
/* save the intended deadline for periodic calls */
deadline = call->deadline;
/* zero the deadline, as the call has occurred */
call->deadline = 0;
/* invoke the callout (if there is one) */
if (call->callout) {
hrtinfo("call %p: %p(%p)\n", call, call->callout, call->arg);
call->callout(call->arg);
}
/* if the callout has a non-zero period, it has to be re-entered */
if (call->period != 0) {
// re-check call->deadline to allow for
// callouts to re-schedule themselves
// using hrt_call_delay()
if (call->deadline <= now) {
call->deadline = deadline + call->period;
}
hrt_call_enter(call);
}
}
}
/**
* Reschedule the next timer interrupt.
*
* This routine must be called with interrupts disabled.
*/
static void __attribute__((section(".iram1")))
hrt_call_reschedule()
{
hrt_abstime now = hrt_absolute_time();
struct hrt_call *next = (struct hrt_call *)sq_peek(&callout_queue);
hrt_abstime deadline = now + HRT_INTERVAL_MAX;
/*
* Determine what the next deadline will be.
*
* Note that we ensure that this will be within the counter
* period, so that when we truncate all but the low 16 bits
* the next time the compare matches it will be the deadline
* we want.
*
* It is important for accurate timekeeping that the compare
* interrupt fires sufficiently often that the base_time update in
* hrt_absolute_time runs at least once per timer period.
*/
if (next != NULL) {
hrtinfo("entry in queue\n");
if (next->deadline <= (now + HRT_INTERVAL_MIN)) {
hrtinfo("pre-expired\n");
/* set a minimal deadline so that we call ASAP */
deadline = now + HRT_INTERVAL_MIN;
} else if (next->deadline < deadline) {
hrtinfo("due soon\n");
deadline = next->deadline;
}
}
hrtinfo("schedule for %u at %u\n", (unsigned)(deadline & 0xffffffff), (unsigned)(now & 0xffffffff));
/* set the new compare value and remember it for latency tracking */
latency_baseline = deadline & 0xffff;
rALARMLO = (uint32_t)(deadline & 0xffffffff);
rALARMHI = (uint32_t)((deadline >> 32) & 0xffffffff);
}
static void
hrt_latency_update(void)
{
uint16_t latency = latency_actual - latency_baseline;
unsigned index;
/* bounded buckets */
for (index = 0; index < LATENCY_BUCKET_COUNT; index++) {
if (latency <= latency_buckets[index]) {
latency_counters[index]++;
return;
}
}
/* catch-all at the end */
latency_counters[index]++;
}
void __attribute__((section(".iram1")))
hrt_call_init(struct hrt_call *entry)
{
memset(entry, 0, sizeof(*entry));
}
void __attribute__((section(".iram1")))
hrt_call_delay(struct hrt_call *entry, hrt_abstime delay)
{
entry->deadline = hrt_absolute_time() + delay;
}
#endif /* HRT_TIMER */
@@ -0,0 +1,39 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <board_config.h>
#define SYSTEM_ADC_BASE 0 // not used on kinetis
#include <px4_platform/adc.h>
@@ -0,0 +1,245 @@
/****************************************************************************
*
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <stdint.h>
#include "hardware/esp32_tim.h"
#include "hardware/esp32_gpio.h"
#include "hardware/esp32_soc.h"
#include <px4_platform_common/constexpr_util.h>
/*
* Timers
*/
namespace Timer
{
enum Timer {
Timer0 = 0,
Timer1,
Timer2,
Timer3,
};
// These are actually the Operators
enum Channel {
Channel0 = 0,
Channel1,
Channel2,
Channel3,
Channel4,
Channel5,
Channel6,
Channel7
};
struct TimerChannel {
Timer timer;
Channel channel;
};
}
static inline constexpr uint32_t timerBaseRegister(Timer::Timer timer)
{
switch (timer) {
case Timer::Timer0: return DR_REG_PWM_BASE + 0x04;
case Timer::Timer1: return DR_REG_PWM1_BASE + 0x04;
case Timer::Timer2: return DR_REG_PWM1_BASE + 0x04;
case Timer::Timer3: return DR_REG_PWM1_BASE + 0x04;
}
return 0;
}
/*
* GPIO
*/
namespace GPIO
{
enum Pin {
Pin0 = 0,
Pin1,
Pin2,
Pin3,
Pin4,
Pin5,
Pin6,
Pin7,
Pin8,
Pin9,
Pin10,
Pin11,
Pin12,
Pin13,
Pin14,
Pin15,
Pin16,
Pin17,
Pin18,
Pin19,
Pin20,
Pin21,
Pin22,
Pin23,
Pin24,
Pin25,
Pin26,
Pin27,
Pin28,
Pin29,
Pin30,
Pin31,
Pin32,
Pin33,
Pin34,
Pin35,
Pin36,
Pin37,
Pin38,
};
struct GPIOPin {
Pin pin;
};
}
static inline constexpr uint32_t getGPIOPin(GPIO::Pin pin)
{
switch (pin) {
case GPIO::Pin0: return 0;
case GPIO::Pin1: return 1;
case GPIO::Pin2: return 2;
case GPIO::Pin3: return 3;
case GPIO::Pin4: return 4;
case GPIO::Pin5: return 5;
case GPIO::Pin6: return 6;
case GPIO::Pin7: return 7;
case GPIO::Pin8: return 8;
case GPIO::Pin9: return 9;
case GPIO::Pin10: return 10;
case GPIO::Pin11: return 11;
case GPIO::Pin12: return 12;
case GPIO::Pin13: return 13;
case GPIO::Pin14: return 14;
case GPIO::Pin15: return 15;
case GPIO::Pin16: return 16;
case GPIO::Pin17: return 17;
case GPIO::Pin18: return 18;
case GPIO::Pin19: return 19;
case GPIO::Pin20: return 20;
case GPIO::Pin21: return 21;
case GPIO::Pin22: return 22;
case GPIO::Pin23: return 23;
case GPIO::Pin24: return 24;
case GPIO::Pin25: return 25;
case GPIO::Pin26: return 26;
case GPIO::Pin27: return 27;
case GPIO::Pin28: return 28;
case GPIO::Pin29: return 29;
case GPIO::Pin30: return 30;
case GPIO::Pin31: return 31;
case GPIO::Pin32: return 32;
case GPIO::Pin33: return 33;
case GPIO::Pin34: return 34;
case GPIO::Pin35: return 35;
case GPIO::Pin36: return 36;
case GPIO::Pin37: return 37;
case GPIO::Pin38: return 38;
}
return 0;
}
namespace SPI
{
enum class Bus {
SPI1 = 1,
SPI2,
SPI3,
};
using CS = GPIO::GPIOPin; ///< chip-select pin
using DRDY = GPIO::GPIOPin; ///< data ready pin
struct bus_device_external_cfg_t {
CS cs_gpio;
DRDY drdy_gpio;
};
} // namespace SPI
@@ -0,0 +1,56 @@
/****************************************************************************
*
* Copyright (C) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <px4_arch/hw_description.h>
#include <px4_platform_common/i2c.h>
#if defined(CONFIG_I2C)
static inline constexpr px4_i2c_bus_t initI2CBusInternal(int bus)
{
px4_i2c_bus_t ret{};
ret.bus = bus;
ret.is_external = false;
return ret;
}
static inline constexpr px4_i2c_bus_t initI2CBusExternal(int bus)
{
px4_i2c_bus_t ret{};
ret.bus = bus;
ret.is_external = true;
return ret;
}
#endif // CONFIG_I2C
@@ -0,0 +1,176 @@
/****************************************************************************
*
* Copyright (C) 2012, 2017 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file io_timer.h
*/
#include <px4_platform_common/px4_config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <drivers/drv_hrt.h>
#pragma once
__BEGIN_DECLS
/* configuration limits */
#ifdef BOARD_NUM_IO_TIMERS
#define MAX_IO_TIMERS BOARD_NUM_IO_TIMERS
#else
#define MAX_IO_TIMERS 1
#endif
#if DIRECT_PWM_OUTPUT_CHANNELS > 8
#define MAX_TIMER_IO_CHANNELS DIRECT_PWM_OUTPUT_CHANNELS
#else
#define MAX_TIMER_IO_CHANNELS 8
#endif
#define MAX_LED_TIMERS 2
#define MAX_TIMER_LED_CHANNELS 6
#define MAX_SPIX_SYNC_TIMERS 2
#define MAX_TIMER_SPIX_SYNC_CHANNELS 2
#define IO_TIMER_ALL_MODES_CHANNELS 0
typedef enum io_timer_channel_mode_t {
IOTimerChanMode_NotUsed = 0,
IOTimerChanMode_PWMOut = 1,
IOTimerChanMode_PWMIn = 2,
IOTimerChanMode_Capture = 3,
IOTimerChanMode_OneShot = 4,
IOTimerChanMode_Trigger = 5,
IOTimerChanMode_Dshot = 6,
IOTimerChanMode_LED = 7,
IOTimerChanMode_PPS = 8,
IOTimerChanMode_Other = 9,
IOTimerChanModeSize
} io_timer_channel_mode_t;
typedef uint16_t io_timer_channel_allocation_t; /* big enough to hold MAX_TIMER_IO_CHANNELS */
/* array of timers dedicated to PWM in and out and capture use
*** Note that the clock_freq is set to the source in the clock tree that
*** feeds this specific timer. This can differs by Timer!
*** In PWM mode the timer's prescaler is set to achieve a counter frequency of 1MHz
*** In OneShot mode the timer's prescaler is set to achieve a counter frequency of 8MHz
*** Other prescaler rates can be achieved by fore instance by setting the clock_freq = 1Mhz
*** the resulting PSC will be one and the timer will count at it's clock frequency.
*/
typedef struct io_timers_t {
uint32_t base;
uint32_t clock_register;
uint32_t clock_bit;
uint32_t clock_freq;
uint32_t vectorno;
} io_timers_t;
typedef struct io_timers_channel_mapping_element_t {
uint32_t first_channel_index;
uint32_t channel_count;
uint32_t lowest_timer_channel;
uint32_t channel_count_including_gaps;
} io_timers_channel_mapping_element_t;
/* mapping for each io_timers to timer_io_channels */
typedef struct io_timers_channel_mapping_t {
io_timers_channel_mapping_element_t element[MAX_IO_TIMERS];
} io_timers_channel_mapping_t;
/* array of channels in logical order */
typedef struct timer_io_channels_t {
uint32_t gpio_out;
uint32_t gpio_in;
uint8_t timer_index;
uint8_t timer_channel;
uint16_t masks;
uint8_t ccr_offset;
} timer_io_channels_t;
typedef void (*channel_handler_t)(void *context, const io_timers_t *timer, uint32_t chan_index,
const timer_io_channels_t *chan,
hrt_abstime isrs_time, uint16_t isrs_rcnt);
/* supplied by board-specific code */
__EXPORT extern const io_timers_t io_timers[MAX_IO_TIMERS];
__EXPORT extern const io_timers_channel_mapping_t io_timers_channel_mapping;
__EXPORT extern const timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS];
__EXPORT extern const io_timers_t led_pwm_timers[MAX_LED_TIMERS];
__EXPORT extern const timer_io_channels_t led_pwm_channels[MAX_TIMER_LED_CHANNELS];
__EXPORT extern const io_timers_t spix_sync_timers[MAX_SPIX_SYNC_TIMERS];
__EXPORT extern const io_timers_channel_mapping_t spix_sync_channel_mapping;
__EXPORT extern const timer_io_channels_t spix_sync_channels[MAX_TIMER_SPIX_SYNC_CHANNELS];
__EXPORT int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode,
channel_handler_t channel_handler, void *context);
__EXPORT int io_timer_init_timer(unsigned timer, io_timer_channel_mode_t mode);
__EXPORT int io_timer_set_pwm_rate(unsigned timer, unsigned rate);
__EXPORT int io_timer_set_enable(bool state, io_timer_channel_mode_t mode,
io_timer_channel_allocation_t masks);
__EXPORT uint16_t io_channel_get_ccr(unsigned channel);
__EXPORT int io_timer_set_ccr(unsigned channel, uint16_t value);
__EXPORT uint32_t io_timer_get_group(unsigned timer);
__EXPORT int io_timer_validate_channel_index(unsigned channel);
__EXPORT int io_timer_allocate_channel(unsigned channel, io_timer_channel_mode_t mode);
__EXPORT int io_timer_unallocate_channel(unsigned channel);
__EXPORT int io_timer_get_channel_mode(unsigned channel);
__EXPORT int io_timer_get_mode_channels(io_timer_channel_mode_t mode);
__EXPORT extern void io_timer_trigger(unsigned channels_mask);
__EXPORT void io_timer_update_dma_req(uint8_t timer, bool enable);
/**
* Reserve a timer
* @return 0 on success (if not used yet, or already set to the mode)
*/
__EXPORT int io_timer_allocate_timer(unsigned timer, io_timer_channel_mode_t mode);
__EXPORT int io_timer_unallocate_timer(unsigned timer);
__EXPORT extern int io_timer_set_dshot_mode(uint8_t timer, unsigned dshot_pwm_rate, uint8_t dma_burst_length);
/**
* Returns the pin configuration for a specific channel, to be used as GPIO output.
* 0 is returned if the channel is not valid.
*/
__EXPORT uint32_t io_timer_channel_get_gpio_output(unsigned channel);
/**
* Returns the pin configuration for a specific channel, to be used as PWM input.
* 0 is returned if the channel is not valid.
*/
__EXPORT uint32_t io_timer_channel_get_as_pwm_input(unsigned channel);
__END_DECLS
@@ -0,0 +1,170 @@
/****************************************************************************
*
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <px4_arch/io_timer.h>
#include <px4_arch/hw_description.h>
#include <px4_platform_common/constexpr_util.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform/io_timer_init.h>
#include <esp32_tim.h>
#include <esp32_gpio.h>
// static inline constexpr timer_io_channels_t initIOTimerGPIOInOut(Timer::TimerChannel timer, GPIO::GPIOPin pin);
#define initIOTimerChannelCapture initIOTimerChannel // alias, used for param metadata generation
static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t io_timers_conf[MAX_IO_TIMERS],
Timer::TimerChannel timer, GPIO::GPIOPin pin)
{
timer_io_channels_t ret = {};
ret.gpio_out = getGPIOPin(pin.pin);
ret.timer_channel = timer.channel;
ret.timer_index = timer.timer;
bool nuttx_incorrect_mapping = false;
bool multiple_timers_configure = false;
bool timer_configured = false;
#if defined(CONFIG_ESP32_LEDC_TIM0_CHANNELS)
multiple_timers_configure = timer_configured;
timer_configured = true;
#endif
#if defined(CONFIG_ESP32_LEDC_TIM1_CHANNELS)
multiple_timers_configure = timer_configured;
timer_configured = true;
#endif
#if defined(CONFIG_ESP32_LEDC_TIM2_CHANNELS)
multiple_timers_configure = timer_configured;
timer_configured = true;
#endif
#if defined(CONFIG_ESP32_LEDC_TIM3_CHANNELS)
multiple_timers_configure = timer_configured;
timer_configured = true;
#endif
int channel = timer.channel;
switch (channel) {
case 0:
#if defined(CONFIG_ESP32_LEDC_CHANNEL0_PIN)
nuttx_incorrect_mapping = pin.pin == CONFIG_ESP32_LEDC_CHANNEL0_PIN;
#endif
break;
case 1:
#if defined(CONFIG_ESP32_LEDC_CHANNEL1_PIN)
nuttx_incorrect_mapping = pin.pin == CONFIG_ESP32_LEDC_CHANNEL1_PIN;
#endif
break;
case 2:
#if defined(CONFIG_ESP32_LEDC_CHANNEL2_PIN)
nuttx_incorrect_mapping = pin.pin == CONFIG_ESP32_LEDC_CHANNEL2_PIN;
#endif
break;
case 3:
#if defined(CONFIG_ESP32_LEDC_CHANNEL3_PIN)
nuttx_incorrect_mapping = pin.pin == CONFIG_ESP32_LEDC_CHANNEL3_PIN;
#endif
break;
default:
break;
}
constexpr_assert(nuttx_incorrect_mapping, "PX4 ChannelTimer Mapping different from Nuttx)");
constexpr_assert(!multiple_timers_configure, "Only a single timer can be configured in Nuttx");
return ret;
}
static inline constexpr timer_io_channels_t initIOTimerChannelOutputClear(const io_timers_t
io_timers_conf[MAX_IO_TIMERS], Timer::TimerChannel timer, GPIO::GPIOPin pin)
{
timer_io_channels_t ret = initIOTimerChannel(io_timers_conf, timer, pin);
ret.gpio_out |= 0;
return ret;
}
static inline constexpr io_timers_t initIOTimer(Timer::Timer timer)
{
bool nuttx_config_timer_enabled = false;
io_timers_t ret{};
switch (timer) {
case Timer::Timer0: // refers to MCPWM peripheral 1
ret.base = 0;
#if defined(CONFIG_ESP32_LEDC_TIM0)
nuttx_config_timer_enabled = true;
#endif
break;
case Timer::Timer1: // refers to MCPWM peripheral 2
ret.base = 1;
#if defined(CONFIG_ESP32_LEDC_TIM1)
nuttx_config_timer_enabled = true;
#endif
break;
case Timer::Timer2: // refers to MCPWM peripheral 2
ret.base = 2;
#if defined(CONFIG_ESP32_LEDC_TIM2)
nuttx_config_timer_enabled = true;
#endif
break;
case Timer::Timer3: // refers to MCPWM peripheral 2
ret.base = 4;
#if defined(CONFIG_ESP32_LEDC_TIM3)
nuttx_config_timer_enabled = true;
#endif
break;
default: break;
}
constexpr_assert(nuttx_config_timer_enabled,
"IO Timer requires NuttX timer config to be Enabled (CONFIG_ESP32_LEDC_TIMx)");
return ret;
}
@@ -0,0 +1,130 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <px4_platform/micro_hal.h>
__BEGIN_DECLS
#include <esp32_tim.h>
#include <esp32_spi.h>
#include <esp32_i2c.h>
#include <nuttx/mtd/mtd.h>
#include <esp32_spiflash.h>
#include <esp32_gpio.h>
# define PX4_CPU_UUID_WORD32_UNIQUE_H 1 /* Most significant digits change the least */
# define PX4_CPU_UUID_WORD32_UNIQUE_M 1 /* Middle significant digits */
# define PX4_CPU_UUID_WORD32_UNIQUE_L 0 /* Least significant digits change the most */
#define PX4_CPU_UUID_BYTE_LENGTH 8
#define PX4_CPU_UUID_WORD32_LENGTH (PX4_CPU_UUID_BYTE_LENGTH/sizeof(uint32_t))
#define PX4_CPU_MFGUID_BYTE_LENGTH PX4_CPU_UUID_BYTE_LENGTH
#define px4_enter_critical_section() enter_critical_section()
#define px4_leave_critical_section(flags) leave_critical_section(flags)
#define px4_udelay(usec) up_udelay(usec)
#define px4_mdelay(msec) up_mdelay(msec)
#define px4_cache_aligned_data()
#define px4_cache_aligned_alloc malloc
// bits Function
// 0-5 GPIO number. 0-40 is valid.
// 6 input
// 7 output
// 8 fun
// 9 pull up
// 10 pull down
// 11 open drain
// 12-14 GPIO function select
// 15-31 Unused
#define GPIO_SET_SHIFT 6
#define GPIO_INPUT (1 << 6)
#define GPIO_OUTPUT (1 << 7)
#define GPIO_FUNCTION (1 << 8)
#define GPIO_PULLUP (1 << 9)
#define GPIO_PULLDOWN (1 << 10)
#define GPIO_OPEN_DRAIN (1 << 11)
#define FUNCTION_SHIFT 6
#define FUNCTION_1 (1 << FUNCTION_SHIFT)
#define FUNCTION_2 (2 << FUNCTION_SHIFT)
#define FUNCTION_3 (3 << FUNCTION_SHIFT)
#define FUNCTION_4 (4 << FUNCTION_SHIFT)
#define FUNCTION_5 (5 << FUNCTION_SHIFT)
#define FUNCTION_6 (6 << FUNCTION_SHIFT)
#define GPIO_FUN(func) (func << 12) // Function select
#define GPIO_NUM_MASK 0x3f
#define GPIO_INPUT_MASK 0x40
#define GPIO_OUTPUT_MASK 0x80
#define GPIO_FUNCTION_MASK 0x100
#define GPIO_PULLUP_MASK 0x200
#define GPIO_PULLDOWN_MASK 0x400
#define GPIO_OPEN_DRAIN_MASK 0x800
#define GPIO_FUN_SELECT_MASK 0x7000
int px4_esp32_configgpio(uint32_t pinset);
int px4_esp32_unconfiggpio(uint32_t pinset);
int esp32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, bool event, xcpt_t func, void *arg);
#define PX4_BUS_OFFSET 1
#define px4_arch_configgpio(pinset) px4_esp32_configgpio(pinset)
#define px4_arch_unconfiggpio(pinset) px4_esp32_unconfiggpio(pinset)
#define px4_arch_gpioread(pinset) esp32_gpioread(pinset & GPIO_NUM_MASK)
#define px4_arch_gpiowrite(pinset, value) esp32_gpiowrite(pinset & GPIO_NUM_MASK, value)
#define px4_arch_gpiosetevent(pinset,r,f,e,fp,a) esp32_gpiosetevent(pinset,r,f,e,fp,a)
#define px4_arch_mtd_dev() esp32_spiflash_get_mtd()
#define px4_spibus_initialize(bus_num_1based) esp32_spibus_initialize(bus_num_1based)
#define px4_i2cbus_initialize(bus_num_1based) esp32_i2cbus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based))
#define px4_i2cbus_uninitialize(pdev) esp32_i2cbus_uninitialize(pdev)
#define PX4_SOC_ARCH_ID PX4_SOC_ARCH_ID_UNUSED
#define PX4_FLASH_BASE ESP32_FLASH_BASE
#define PX4_NUMBER_I2C_BUSES 2
#define PX4_ADC_INTERNAL_TEMP_SENSOR_CHANNEL 0
#undef DISABLED
__END_DECLS
@@ -0,0 +1,220 @@
/****************************************************************************
*
* Copyright (C) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <px4_arch/hw_description.h>
#include <px4_platform_common/spi.h>
#include <px4_arch/micro_hal.h>
#if defined(CONFIG_ESP32_SPI)
#include <esp32_gpio.h>
static inline constexpr px4_spi_bus_device_t initSPIDevice(uint32_t devid, SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {})
{
px4_spi_bus_device_t ret{};
if (cs_gpio.pin == -1) {
ret.cs_gpio = 0;
} else {
ret.cs_gpio = (cs_gpio.pin | GPIO_PULLUP | GPIO_OUTPUT);
}
if (drdy_gpio.pin == -1) {
ret.drdy_gpio = 0;
} else {
ret.drdy_gpio = (drdy_gpio.pin | GPIO_INPUT);
}
if (PX4_SPIDEVID_TYPE(devid) == 0) { // it's a PX4 device (internal or external)
ret.devid = PX4_SPIDEV_ID(PX4_SPI_DEVICE_ID, devid);
} else { // it's a NuttX device (e.g. SPIDEV_FLASH(0))
ret.devid = devid;
}
ret.devtype_driver = PX4_SPI_DEV_ID(devid);
return ret;
}
static inline constexpr px4_spi_bus_t initSPIBus(SPI::Bus bus, const px4_spi_bus_devices_t &devices,
GPIO::GPIOPin power_enable = {})
{
px4_spi_bus_t ret{};
ret.requires_locking = false;
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) {
ret.devices[i] = devices.devices[i];
if (ret.devices[i].cs_gpio != 0) {
if (PX4_SPI_DEVICE_ID == PX4_SPIDEVID_TYPE(ret.devices[i].devid)) {
int same_devices_count = 0;
for (int j = 0; j < i; ++j) {
if (ret.devices[j].cs_gpio != 0) {
same_devices_count += (ret.devices[i].devid & 0xff) == (ret.devices[j].devid & 0xff);
}
}
// increment the 2. LSB byte to allow multiple devices of the same type
ret.devices[i].devid |= same_devices_count << 8;
} else {
// A bus potentially requires locking if it is accessed by non-PX4 devices (i.e. NuttX drivers)
ret.requires_locking = true;
}
}
}
ret.bus = (int)bus;
ret.is_external = false;
if (power_enable.pin == -1) {
ret.power_enable_gpio = 0;
} else {
ret.power_enable_gpio = (power_enable.pin | GPIO_OUTPUT | GPIO_PULLUP);
}
return ret;
}
// just a wrapper since we cannot pass brace-enclosed initialized arrays directly as arguments
struct bus_device_external_cfg_array_t {
SPI::bus_device_external_cfg_t devices[SPI_BUS_MAX_DEVICES];
};
static inline constexpr px4_spi_bus_t initSPIBusExternal(SPI::Bus bus, const bus_device_external_cfg_array_t &devices)
{
px4_spi_bus_t ret{};
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) {
if (devices.devices[i].cs_gpio.pin == -1) {
break;
}
ret.devices[i] = initSPIDevice(i, devices.devices[i].cs_gpio, devices.devices[i].drdy_gpio);
}
ret.bus = (int)bus;
ret.is_external = true;
ret.requires_locking = false; // external buses are never accessed by NuttX drivers
return ret;
}
static inline constexpr SPI::bus_device_external_cfg_t initSPIConfigExternal(SPI::CS cs_gpio, SPI::DRDY drdy_gpio = {})
{
SPI::bus_device_external_cfg_t ret{};
ret.cs_gpio = cs_gpio;
ret.drdy_gpio = drdy_gpio;
return ret;
}
struct px4_spi_bus_array_t {
px4_spi_bus_t item[SPI_BUS_MAX_BUS_ITEMS];
};
static inline constexpr px4_spi_bus_all_hw_t initSPIHWVersion(int hw_version_revision,
const px4_spi_bus_array_t &bus_items)
{
px4_spi_bus_all_hw_t ret{};
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) {
ret.buses[i] = bus_items.item[i];
}
ret.board_hw_version_revision = hw_version_revision;
return ret;
}
static constexpr bool validateSPIConfig(const px4_spi_bus_t spi_buses_conf[SPI_BUS_MAX_BUS_ITEMS]);
static constexpr bool validateSPIConfig(const px4_spi_bus_all_hw_t spi_buses_conf[BOARD_NUM_SPI_CFG_HW_VERSIONS])
{
for (int ver = 0; ver < BOARD_NUM_SPI_CFG_HW_VERSIONS; ++ver) {
validateSPIConfig(spi_buses_conf[ver].buses);
}
for (int ver = 1; ver < BOARD_NUM_SPI_CFG_HW_VERSIONS; ++ver) {
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) {
const bool equal_power_enable_gpio = spi_buses_conf[ver].buses[i].power_enable_gpio == spi_buses_conf[ver -
1].buses[i].power_enable_gpio;
// currently board_control_spi_sensors_power_configgpio() depends on that - this restriction can be removed
// by ensuring board_control_spi_sensors_power_configgpio() is called after the hw version is determined
// and SPI config is initialized.
constexpr_assert(equal_power_enable_gpio, "All HW versions must define the same power enable GPIO");
}
}
return false;
}
constexpr bool validateSPIConfig(const px4_spi_bus_t spi_busses_conf[SPI_BUS_MAX_BUS_ITEMS])
{
const bool nuttx_enabled_spi_buses[] = {
false,
#ifdef CONFIG_ESP32_SPI2
true,
#else
false,
#endif
#ifdef CONFIG_ESP32_SPI3
true,
#else
false,
#endif
false,
false,
false,
};
for (unsigned i = 0; i < sizeof(nuttx_enabled_spi_buses) / sizeof(nuttx_enabled_spi_buses[0]); ++i) {
bool found_bus = false;
for (int j = 0; j < SPI_BUS_MAX_BUS_ITEMS; ++j) {
if (spi_busses_conf[j].bus == (int)i + 1) {
found_bus = true;
}
}
// Either the bus is enabled in NuttX and configured in spi_busses_conf, or disabled and not configured
constexpr_assert(found_bus == nuttx_enabled_spi_buses[i], "SPI bus config mismatch (CONFIG_ESP32_SPIx)");
}
return false;
}
#endif // CONFIG_SPI
@@ -0,0 +1,44 @@
############################################################################
#
# Copyright (c) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(arch_io_pins
io_timer.c
esp32_pinset.c
pwm_servo.c
# pwm_trigger.c
# input_capture.c
)
target_compile_options(arch_io_pins PRIVATE ${MAX_CUSTOM_OPT_LEVEL})
target_link_libraries(arch_io_pins PRIVATE drivers_board)
@@ -0,0 +1,74 @@
#include <px4_platform_common/px4_config.h>
#include <systemlib/px4_macros.h>
#include <arch/board/board.h>
#include <px4_arch/micro_hal.h>
#include <errno.h>
#include <stdio.h>
#include <syslog.h>
int px4_esp32_configgpio(uint32_t pinset)
{
if ((pinset & GPIO_NUM_MASK) >= ESP32_NGPIOS) {
return -EINVAL;
}
return esp32_configgpio((int)(pinset & GPIO_NUM_MASK), (uint16_t)(pinset >> GPIO_SET_SHIFT));
}
int px4_esp32_unconfiggpio(uint32_t pinset)
{
return px4_esp32_configgpio((pinset & GPIO_NUM_MASK) | GPIO_INPUT | GPIO_OPEN_DRAIN);
}
/****************************************************************************
* Name: esp32_gpiosetevent
*
* Description:
* Sets/clears GPIO based event and interrupt triggers.
*
* Input Parameters:
* - pinset: GPIO pin configuration
* - risingedge: Enables interrupt on rising edges
* - fallingedge: Enables interrupt on falling edges
* - event: Generate event when set
* - func: When non-NULL, generate interrupt
* - arg: Argument passed to the interrupt callback
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure indicating the
* nature of the failure.
*
****************************************************************************/
int esp32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
bool event, xcpt_t func, void *arg)
{
uint32_t pin = pinset & GPIO_NUM_MASK;
int irq = ESP32_PIN2IRQ(pin);
if (event == true) {
int ret = irq_attach(irq, func, arg);
if (ret < 0) {
syslog(LOG_ERR, "ERROR: irq_attach() failed: %d\n", ret);
return ret;
}
if (risingedge == true && fallingedge == true) {
esp32_gpioirqenable(irq, CHANGE);
} else if (risingedge == true && fallingedge == false) {
esp32_gpioirqenable(irq, RISING);
} else if (risingedge == false && fallingedge == true) {
esp32_gpioirqenable(irq, FALLING);
}
} else {
esp32_gpioirqdisable(irq);
}
//syslog(LOG_INFO, "esp32_gpiosetevent: %d\n", ret);
return OK;
}
@@ -0,0 +1,98 @@
/****************************************************************************
*
* Copyright (C) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file io_timer.c
*
* Servo driver supporting PWM servos connected to RP2040 PWM blocks.
*/
#include <px4_platform_common/px4_config.h>
#include <systemlib/px4_macros.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <sys/types.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include <time.h>
#include <queue.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <arch/board/board.h>
#include <drivers/drv_pwm_output.h>
#include <px4_arch/io_timer.h>
uint32_t io_timer_get_group(unsigned timer)
{
if (timer == 0) {
#if defined(CONFIG_ESP32_LEDC_TIM0_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM0_CHANNELS) - 1;
#endif
return -1;
} else if (timer == 1) {
#if defined(CONFIG_ESP32_LEDC_TIM1_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM1_CHANNELS) - 1;
#endif
return -1;
} else if (timer == 2) {
#if defined(CONFIG_ESP32_LEDC_TIM2_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM2_CHANNELS) - 1;
#endif
return -1;
} else if (timer == 3) {
#if defined(CONFIG_ESP32_LEDC_TIM3_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM3_CHANNELS) - 1;
#endif
return -1;
}
return -1;
}
uint32_t io_timer_channel_get_gpio_output(unsigned channel)
{
return timer_io_channels[channel].gpio_out | GPIO_OUTPUT | GPIO_PULLUP;
}
@@ -0,0 +1,321 @@
/****************************************************************************
*
* Copyright (C) 2012, 2017 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/*
* @file drv_pwm_servo.c
*
* Servo driver supporting PWM servos connected to STM32 timer blocks.
*
* Works with any of the 'generic' or 'advanced' STM32 timers that
* have output pins, does not require an interrupt.
*/
#include <px4_platform_common/px4_config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <sys/types.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include <time.h>
#include <queue.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <arch/board/board.h>
#include <drivers/drv_pwm_output.h>
#include <px4_arch/io_timer.h>
// #include <esp32_ledc.h>
#include "xtensa.h"
#define DR_REG_DPORT_BASE 0x3ff00000
#define DPORT_PERIP_CLK_EN_REG (DR_REG_DPORT_BASE + 0x0C0)
#define DPORT_PERIP_RST_EN_REG (DR_REG_DPORT_BASE + 0x0C4)
#define DR_REG_LEDC_BASE 0x3ff59000
#define LEDC_LSTIMER0_CONF_REG (DR_REG_LEDC_BASE + 0x0160)
#define LEDC_LSTIMER1_CONF_REG (DR_REG_LEDC_BASE + 0x0168)
#define LEDC_LSCH1_CONF0_REG (DR_REG_LEDC_BASE + 0x00B4)
#define LEDC_LSCH0_CONF0_REG (DR_REG_LEDC_BASE + 0x00A0)
#define LEDC_LSCH0_CONF1_REG (DR_REG_LEDC_BASE + 0x00AC)
#define LEDC_LSCH0_HPOINT_REG (DR_REG_LEDC_BASE + 0x00A4)
#define LEDC_LSCH0_DUTY_REG (DR_REG_LEDC_BASE + 0x00A8)
#define LEDC_CONF_REG (DR_REG_LEDC_BASE + 0x0190)
#define LEDC_SIG_OUT_EN_LSCH0 1 << 2
#define LEDC_PARA_UP_LSCH0 1 << 4
#define DPORT_LEDC_CLK_EN 1 << 11
#define DPORT_LEDC_RST 1 << 11
#define LEDC_LSTIMER0_PAUSE 1 << 23
#define LEDC_LSTIMER0_RST 1 << 24
#define LEDC_TICK_SEL_LSTIMER0 1 << 25
#define LEDC_LSTIMER0_PARA_UP 1 << 26
#define LEDC_DUTY_START_LSCH0 1 << 31
#define LEDC_DIV_NUM_LSTIMER0_S 5
#define LEDC_LSTIMER0_DUTY_RES_S 0
#define b16HALF 0x00008000 /* 0.5 */
#define b16toi(a) ((a) >> 16) /* Conversion to integer */
/* LEDC clock resource */
#define LEDC_CLK_RES (1) /* APB clock */
/* LEDC timer max reload */
#define LEDC_RELOAD_MAX (1048576) /* 2^20 */
/* LEDC timer max clock divider parameter */
#define LEDC_CLKDIV_MAX (1024) /* 2^10 */
/* LEDC timer registers mapping */
#define LEDC_TIMER_REG(r, n) ((r) + (n) * (LEDC_LSTIMER1_CONF_REG - LEDC_LSTIMER0_CONF_REG))
/* LEDC timer channel registers mapping */
#define setbits(bs, a) modifyreg32(a, 0, bs)
#define resetbits(bs, a) modifyreg32(a, bs, 0)
#define LEDC_CHAN_REG(r, n) ((r) + (n) * (LEDC_LSCH1_CONF0_REG - LEDC_LSCH0_CONF0_REG))
#define SET_TIMER_BITS(t, r, b) setbits(b, LEDC_TIMER_REG(r, t));
#define SET_TIMER_REG(t, r, v) putreg32(v, LEDC_TIMER_REG(r, t));
#define SET_CHAN_BITS(c, r, b) setbits(b, LEDC_CHAN_REG(r, c));
#define SET_CHAN_REG(c, r, v) putreg32(v, LEDC_CHAN_REG(r, c));
uint32_t reload = 0;
uint32_t prescaler = 0;
uint32_t shift = 0;
uint32_t timer_rate = 0;
void get_optimal_timer_setup(uint32_t desired_freq)
{
uint32_t shifted = 1;
timer_rate = desired_freq;
reload = (20480000000 / desired_freq + LEDC_CLKDIV_MAX) / LEDC_CLKDIV_MAX;
if (reload == 0) {
reload = 1;
} else if (reload > LEDC_RELOAD_MAX) {
reload = LEDC_RELOAD_MAX;
}
for (uint32_t c = 2; c <= LEDC_RELOAD_MAX; c *= 2) {
if (c * 2 > reload) {
reload = c;
break;
}
shifted++;
}
shift = shifted;
prescaler = (20480000000 / reload) / desired_freq;
}
int up_pwm_servo_set(unsigned channel, uint16_t value)
{
uint32_t duty = (value * timer_rate) * 0.065535;
uint32_t regval = b16toi(duty * reload + b16HALF);
irqstate_t flags;
flags = px4_enter_critical_section();
SET_CHAN_REG(channel, LEDC_LSCH0_DUTY_REG, regval << 4);
SET_CHAN_BITS(channel, LEDC_LSCH0_CONF0_REG, LEDC_PARA_UP_LSCH0);
px4_leave_critical_section(flags);
return OK;
}
uint16_t up_pwm_servo_get(unsigned channel)
{
return 0;
}
int up_pwm_servo_init(uint32_t channel_mask)
{
// pause the timer
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_LSTIMER0_PAUSE);
// reset the timer
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_LSTIMER0_RST);
// We are going to use REF_Tick as our source, which is set at 1Mhz.
// our prescaler is thus 0
irqstate_t flags;
prescaler = 0;
shift = 0;
get_optimal_timer_setup(400);
flags = px4_enter_critical_section();
setbits(DPORT_LEDC_CLK_EN, DPORT_PERIP_CLK_EN_REG);
resetbits(DPORT_LEDC_RST, DPORT_PERIP_RST_EN_REG);
putreg32(LEDC_CLK_RES, LEDC_CONF_REG);
uint32_t regval = (shift << LEDC_LSTIMER0_DUTY_RES_S) | (prescaler << LEDC_DIV_NUM_LSTIMER0_S);
SET_TIMER_REG(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, regval);
/* Setup to timer to use APB clock (80MHz) */
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_TICK_SEL_LSTIMER0);
/* Update clock divide and reload to hardware */
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_LSTIMER0_PARA_UP);
px4_leave_critical_section(flags);
return channel_mask;
}
void up_pwm_servo_deinit(uint32_t channel_mask)
{
/* disable the timers */
up_pwm_servo_arm(false, channel_mask);
}
int up_pwm_servo_set_rate_group_update(unsigned group, unsigned rate)
{
if (group == 0 || group == 1 || group == 2 || group == 3) {
irqstate_t flags;
shift = 0;
prescaler = 0;
get_optimal_timer_setup(rate);
flags = px4_enter_critical_section();
uint32_t regval = (shift << LEDC_LSTIMER0_DUTY_RES_S) | (prescaler << LEDC_DIV_NUM_LSTIMER0_S);
SET_TIMER_REG(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, regval);
/* Setup to timer to use APB clock (80MHz) */
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_TICK_SEL_LSTIMER0);
/* Update clock divide and reload to hardware */
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_LSTIMER0_PARA_UP);
px4_leave_critical_section(flags);
return OK;
}
return ERROR;
}
void up_pwm_update(unsigned channels_mask)
{
//syslog(LOG_INFO, "up_pwm_update channels_mask: %d\n", channels_mask);
// pwm->ops->start(pwm,&pwm_info);
}
uint32_t up_pwm_servo_get_rate_group(unsigned group)
{
if (group == 0) {
#if defined(CONFIG_ESP32_LEDC_TIM0_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM0_CHANNELS) - 1;
#endif
return -1;
} else if (group == 1) {
#if defined(CONFIG_ESP32_LEDC_TIM1_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM1_CHANNELS) - 1;
#endif
return -1;
} else if (group == 2) {
#if defined(CONFIG_ESP32_LEDC_TIM2_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM2_CHANNELS) - -1;
#endif
return -1;
} else if (group == 3) {
#if defined(CONFIG_ESP32_LEDC_TIM3_CHANNELS)
return (1 << CONFIG_ESP32_LEDC_TIM3_CHANNELS) - 1;
#endif
return -1;
}
return -1;
}
void
up_pwm_servo_arm(bool armed, uint32_t channel_mask)
{
if (armed) {
for (uint8_t chan = 0; chan < 4; chan++) {
irqstate_t flags;
flags = px4_enter_critical_section();
/* Reset config 0 & 1 registers */
SET_CHAN_REG(chan, LEDC_LSCH0_CONF0_REG, 0);
SET_CHAN_REG(chan, LEDC_LSCH0_CONF1_REG, 0);
/* Set pulse phase 0 */
SET_CHAN_REG(chan, LEDC_LSCH0_HPOINT_REG, 0);
/* Start GPIO output */
SET_CHAN_BITS(chan, LEDC_LSCH0_CONF0_REG, LEDC_SIG_OUT_EN_LSCH0);
/* Start Duty counter */
SET_CHAN_BITS(chan, LEDC_LSCH0_CONF1_REG, LEDC_DUTY_START_LSCH0);
/* Update duty and phase to hardware */
SET_CHAN_BITS(chan, LEDC_LSCH0_CONF0_REG, LEDC_PARA_UP_LSCH0);
px4_leave_critical_section(flags);
}
} else {
irqstate_t flags;
flags = px4_enter_critical_section();
/* Stop timer */
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_LSTIMER0_PAUSE);
/* Reset timer */
SET_TIMER_BITS(io_timers[0].base, LEDC_LSTIMER0_CONF_REG, LEDC_LSTIMER0_RST);
px4_leave_critical_section(flags);
}
}
@@ -0,0 +1,39 @@
############################################################################
#
# Copyright (c) 2020 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(arch_spi
spi.cpp
)
target_compile_options(arch_spi PRIVATE ${MAX_CUSTOM_OPT_LEVEL})
target_link_libraries (arch_spi PRIVATE drivers_board) # px4_spi_buses
@@ -0,0 +1,322 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <board_config.h>
#include <systemlib/px4_macros.h>
#include <px4_platform_common/spi.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <unistd.h>
#include <nuttx/spi/spi.h>
#include <arch/board/board.h>
static const px4_spi_bus_t *_spi_bus2;
static const px4_spi_bus_t *_spi_bus3;
static void spi_bus_configgpio_cs(const px4_spi_bus_t *bus)
{
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) {
if (bus->devices[i].cs_gpio != 0) {
px4_arch_configgpio(bus->devices[i].cs_gpio);
}
}
}
__EXPORT void esp32_spiinitialize()
{
px4_set_spi_buses_from_hw_version();
board_control_spi_sensors_power_configgpio();
board_control_spi_sensors_power(true, 0xffff);
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) {
switch (px4_spi_buses[i].bus) {
case 2: _spi_bus2 = &px4_spi_buses[i]; break;
case 3: _spi_bus3 = &px4_spi_buses[i]; break;
}
}
#if defined(CONFIG_ESP32_SPI2)
ASSERT(_spi_bus2);
if (board_has_bus(BOARD_SPI_BUS, 2)) {
//syslog(LOG_DEBUG, "spi bus configgpio cs %i\n", _spi_bus2->bus);
spi_bus_configgpio_cs(_spi_bus2);
}
#endif // CONFIG_ESP32_SPI2
#ifdef CONFIG_ESP32_SPI3
ASSERT(_spi_bus3);
if (board_has_bus(BOARD_SPI_BUS, 3)) {
//syslog(LOG_DEBUG, "spi bus configgpio cs %i\n", _spi_bus3->bus);
spi_bus_configgpio_cs(_spi_bus3);
}
#endif // CONFIG_ESP32_SPI3
}
static inline void esp32_spixselect(const px4_spi_bus_t *bus, struct spi_dev_s *dev, uint32_t devid, bool selected)
{
//syslog(LOG_DEBUG, "esp32 spixselect %i\n", bus->bus);
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) {
if (bus->devices[i].cs_gpio == 0) {
break;
}
if (devid == bus->devices[i].devid) {
// SPI select is active low, so write !selected to select the device
//syslog(LOG_DEBUG, "esp32_gpiowrite %i\n", bus->bus);
px4_arch_gpiowrite(bus->devices[i].cs_gpio, !selected);
}
}
}
/************************************************************************************
* Name: ESP32_spi2select and ESP32_spi2status
*
* Description:
* Called by ESP32 spi driver on bus 2.
*
************************************************************************************/
#if defined(CONFIG_ESP32_SPI2)
__EXPORT void esp32_spi2_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
{
esp32_spixselect(_spi_bus2, dev, devid, selected);
}
__EXPORT uint8_t esp32_spi2_status(FAR struct spi_dev_s *dev, uint32_t devid)
{
return SPI_STATUS_PRESENT;
}
#endif // CONFIG_ESP32_SPI2
/************************************************************************************
* Name: esp32_spi3select and esp32_spi3status
*
* Description:
* Called by ESP32 spi driver on bus 3.
*
************************************************************************************/
#if defined(CONFIG_ESP32_SPI3)
__EXPORT void esp32_spi3_select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
{
esp32_spixselect(_spi_bus3, dev, devid, selected);
}
__EXPORT uint8_t esp32_spi3_status(FAR struct spi_dev_s *dev, uint32_t devid)
{
return SPI_STATUS_PRESENT;
}
#endif // CONFIG_ESP32_SPI3
void board_control_spi_sensors_power(bool enable_power, int bus_mask)
{
const px4_spi_bus_t *buses = px4_spi_buses;
// this might be called very early on boot where we have not yet determined the hw version
// (we expect all versions to have the same power GPIO)
#if BOARD_NUM_SPI_CFG_HW_VERSIONS > 1
if (!buses) {
buses = &px4_spi_buses_all_hw[0].buses[0];
}
#endif
for (int bus = 0; bus < SPI_BUS_MAX_BUS_ITEMS; ++bus) {
if (buses[bus].bus == -1) {
break;
}
const bool bus_matches = bus_mask & (1 << (buses[bus].bus - 1));
if (buses[bus].power_enable_gpio == 0 ||
!board_has_bus(BOARD_SPI_BUS, buses[bus].bus) ||
!bus_matches) {
continue;
}
px4_arch_gpiowrite(buses[bus].power_enable_gpio, enable_power ? 1 : 0);
}
}
void board_control_spi_sensors_power_configgpio()
{
const px4_spi_bus_t *buses = px4_spi_buses;
// this might be called very early on boot where we have yet not determined the hw version
// (we expect all versions to have the same power GPIO)
#if BOARD_NUM_SPI_CFG_HW_VERSIONS > 1
if (!buses) {
buses = &px4_spi_buses_all_hw[0].buses[0];
}
#endif
for (int bus = 0; bus < SPI_BUS_MAX_BUS_ITEMS; ++bus) {
if (buses[bus].bus == -1) {
break;
}
if (buses[bus].power_enable_gpio == 0 ||
!board_has_bus(BOARD_SPI_BUS, buses[bus].bus)) {
continue;
}
px4_arch_configgpio(buses[bus].power_enable_gpio);
}
}
#define _PIN_OFF(def) (((def) & GPIO_NUM_MASK) | (GPIO_INPUT | GPIO_PULLDOWN))
__EXPORT void board_spi_reset(int ms, int bus_mask)
{
bool has_power_enable = false;
// disable SPI bus
for (int bus = 0; bus < SPI_BUS_MAX_BUS_ITEMS; ++bus) {
if (px4_spi_buses[bus].bus == -1) {
break;
}
const bool bus_requested = bus_mask & (1 << (px4_spi_buses[bus].bus - 1));
if (px4_spi_buses[bus].power_enable_gpio == 0 ||
!board_has_bus(BOARD_SPI_BUS, px4_spi_buses[bus].bus) ||
!bus_requested) {
continue;
}
has_power_enable = true;
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) {
if (px4_spi_buses[bus].devices[i].cs_gpio != 0) {
px4_arch_configgpio(_PIN_OFF(px4_spi_buses[bus].devices[i].cs_gpio));
}
if (px4_spi_buses[bus].devices[i].drdy_gpio != 0) {
px4_arch_configgpio(_PIN_OFF(px4_spi_buses[bus].devices[i].drdy_gpio));
}
}
#if defined(CONFIG_ESP32_SPI2)
if (px4_spi_buses[bus].bus == 2) {
px4_arch_configgpio(_PIN_OFF(CONFIG_ESP32_SPI2_CLKPIN));
px4_arch_configgpio(_PIN_OFF(CONFIG_ESP32_SPI2_MOSIPIN));
px4_arch_configgpio(_PIN_OFF(CONFIG_ESP32_SPI2_MISOPIN));
}
#endif
#if defined(CONFIG_ESP32_SPI3)
if (px4_spi_buses[bus].bus == 3) {
px4_arch_configgpio(_PIN_OFF(CONFIG_ESP32_SPI3_CLKPIN));
px4_arch_configgpio(_PIN_OFF(CONFIG_ESP32_SPI3_MOSIPIN));
px4_arch_configgpio(_PIN_OFF(CONFIG_ESP32_SPI3_MISOPIN));
}
#endif
}
if (!has_power_enable) {
// board does not have power control over any of the sensor buses
return;
}
// set the sensor rail(s) off
board_control_spi_sensors_power(false, bus_mask);
// wait for the sensor rail to reach GND
usleep(ms * 1000);
syslog(LOG_DEBUG, "reset done, %d ms\n", ms);
/* re-enable power */
// switch the sensor rail back on
board_control_spi_sensors_power(true, bus_mask);
/* wait a bit before starting SPI, different times didn't influence results */
usleep(100);
/* reconfigure the SPI pins */
for (int bus = 0; bus < SPI_BUS_MAX_BUS_ITEMS; ++bus) {
if (px4_spi_buses[bus].bus == -1) {
break;
}
const bool bus_requested = bus_mask & (1 << (px4_spi_buses[bus].bus - 1));
if (px4_spi_buses[bus].power_enable_gpio == 0 ||
!board_has_bus(BOARD_SPI_BUS, px4_spi_buses[bus].bus) ||
!bus_requested) {
continue;
}
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) {
if (px4_spi_buses[bus].devices[i].cs_gpio != 0) {
px4_arch_configgpio(px4_spi_buses[bus].devices[i].cs_gpio | GPIO_OUTPUT);
}
if (px4_spi_buses[bus].devices[i].drdy_gpio != 0) {
px4_arch_configgpio(px4_spi_buses[bus].devices[i].drdy_gpio | GPIO_INPUT);
}
}
#if defined(CONFIG_ESP32_SPI2)
if (px4_spi_buses[bus].bus == 2) {
px4_arch_configgpio(CONFIG_ESP32_SPI2_CLKPIN | (GPIO_OUTPUT | FUNCTION_2));
px4_arch_configgpio(CONFIG_ESP32_SPI2_MOSIPIN | (GPIO_OUTPUT | FUNCTION_2));
px4_arch_configgpio(CONFIG_ESP32_SPI2_MISOPIN | (GPIO_INPUT | PULLUP | FUNCTION_2);
}
#endif
#if defined(CONFIG_ESP32_SPI3)
if (px4_spi_buses[bus].bus == 3) {
px4_arch_configgpio(CONFIG_ESP32_SPI3_CLKPIN | (GPIO_OUTPUT | FUNCTION_3));
px4_arch_configgpio(CONFIG_ESP32_SPI3_MOSIPIN | (GPIO_OUTPUT | FUNCTION_3));
px4_arch_configgpio(CONFIG_ESP32_SPI3_MISOPIN | (GPIO_INPUT | PULLUP | FUNCTION_3));
}
#endif
}
}
@@ -0,0 +1,37 @@
############################################################################
#
# Copyright (c) 2021 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(arch_version
board_identity.c
board_mcu_version.c
)
@@ -0,0 +1,160 @@
/**
* @file board_identity.c
* Implementation of RP2040 based Board identity API
*/
#include <px4_platform_common/px4_config.h>
#include <stdio.h>
#include <string.h>
// ESP32 doesn't really have a cpu register with unique id.
// but we can make use of its unique mac address
#define MAC_ADDR0_LOWER (0x3ff5a004)
#define MAC_ADDR1_HIGHER (0x3ff5a008)
#define REG_READ(_r) (*(volatile uint32_t *)(_r))
#define CPU_UUID_BYTE_FORMAT_ORDER {5,4,3,2,1,0}
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | ((x) << 24))
static const uint16_t soc_arch_id = PX4_SOC_ARCH_ID;
/* A type suitable for holding the reordering array for the byte format of the UUID
*/
typedef const uint8_t uuid_uint8_reorder_t[PX4_CPU_UUID_BYTE_LENGTH];
static int emac_read_mac(uint32_t *mac)
{
/* The MAC address in register is from high byte to low byte */
mac[0] = REG_READ(MAC_ADDR0_LOWER);
mac[1] = REG_READ(MAC_ADDR1_HIGHER) & 0xffff;
return 0;
}
void board_get_uuid(uuid_byte_t uuid_bytes)
{
uuid_uint8_reorder_t reorder = CPU_UUID_BYTE_FORMAT_ORDER;
union {
uuid_byte_t b;
uuid_uint32_t w;
} id;
/* Copy the serial from the chips non-write memory */
board_get_uuid32(id.w);
/* swap endianess */
for (int i = 0; i < PX4_CPU_UUID_BYTE_LENGTH; i++) {
uuid_bytes[i] = id.b[reorder[i]];
}
}
__EXPORT void board_get_uuid32(uuid_uint32_t uuid_words)
{
uint32_t mac[2];
emac_read_mac(mac);
uint32_t *chip_uuid = mac;
// memcpy(&chip_uuid, mac, sizeof(chip_uuid));
for (unsigned i = 0; i < PX4_CPU_UUID_WORD32_LENGTH; i++) {
uuid_words[i] = chip_uuid[i];
}
}
int board_get_uuid32_formated(char *format_buffer, int size,
const char *format,
const char *seperator)
{
uuid_uint32_t uuid;
board_get_uuid32(uuid);
int offset = 0;
int sep_size = seperator ? strlen(seperator) : 0;
for (unsigned i = 0; (offset < size - 1) && (i < PX4_CPU_UUID_WORD32_LENGTH); i++) {
offset += snprintf(&format_buffer[offset], size - offset, format, uuid[i]);
if (sep_size && (offset < size - sep_size - 1) && (i < PX4_CPU_UUID_WORD32_LENGTH - 1)) {
strncat(&format_buffer[offset], seperator, size - offset);
offset += sep_size;
}
}
return 0;
}
int board_get_mfguid(mfguid_t mfgid)
{
uint32_t mac[2];
emac_read_mac(mac);
uint32_t *chip_uuid = mac;
uint8_t *rv = &mfgid[0];
for (unsigned i = 0; i < PX4_CPU_UUID_WORD32_LENGTH; i++) {
uint32_t uuid_bytes = SWAP_UINT32(chip_uuid[(PX4_CPU_UUID_WORD32_LENGTH - 1) - i]);
memcpy(rv, &uuid_bytes, sizeof(uint32_t));
rv += sizeof(uint32_t);
}
return PX4_CPU_MFGUID_BYTE_LENGTH;
}
int board_get_mfguid_formated(char *format_buffer, int size)
{
mfguid_t mfguid;
board_get_mfguid(mfguid);
int offset = 0;
for (unsigned i = 0; offset < size && i < PX4_CPU_MFGUID_BYTE_LENGTH; i++) {
offset += snprintf(&format_buffer[offset], size - offset, "%02x", mfguid[i]);
}
return offset;
}
int board_get_px4_guid(px4_guid_t px4_guid)
{
uint8_t *pb = (uint8_t *) &px4_guid[0];
*pb++ = (soc_arch_id >> 8) & 0xff;
*pb++ = (soc_arch_id & 0xff);
for (unsigned i = 0; i < PX4_GUID_BYTE_LENGTH - (sizeof(soc_arch_id) + PX4_CPU_UUID_BYTE_LENGTH); i++) {
*pb++ = 0;
}
uint32_t mac[2];
emac_read_mac(mac);
uint32_t *chip_uuid = mac;
for (unsigned i = 0; i < PX4_CPU_UUID_WORD32_LENGTH; i++) {
uint32_t uuid_bytes = SWAP_UINT32(chip_uuid[(PX4_CPU_UUID_WORD32_LENGTH - 1) - i]);
memcpy(pb, &uuid_bytes, sizeof(uint32_t));
pb += sizeof(uint32_t);
}
return PX4_GUID_BYTE_LENGTH;
}
int board_get_px4_guid_formated(char *format_buffer, int size)
{
px4_guid_t px4_guid;
board_get_px4_guid(px4_guid);
int offset = 0;
/* size should be 2 per byte + 1 for termination
* So it needs to be odd
*/
size = size & 1 ? size : size - 1;
/* Discard from MSD */
for (unsigned i = PX4_GUID_BYTE_LENGTH - size / 2; offset < size && i < PX4_GUID_BYTE_LENGTH; i++) {
offset += snprintf(&format_buffer[offset], size - offset, "%02x", px4_guid[i]);
}
return offset;
}
@@ -0,0 +1,103 @@
/****************************************************************************
*
* Copyright (C) 2021 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file board_mcu_version.c
* Implementation of ESP32 based SoC version API
*/
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/defines.h>
/* Define any issues with the Silicon as lines separated by \n
* omitting the last \n
*/
#define ESP32_ERRATA "No unique CPU ID, using MAC address."
#define DR_REG_EFUSE_BASE 0x3ff5a000
#define DR_REG_SYSCON_BASE 0x60026000
#define EFUSE_BLK0_RDATA3_REG (DR_REG_EFUSE_BASE + 0x00c)
#define EFUSE_BLK0_RDATA5_REG (DR_REG_EFUSE_BASE + 0x014)
#define SYSCON_DATE_REG (DR_REG_SYSCON_BASE + 0x3FC)
#define REG_READ(_r) (*(volatile uint32_t *)(_r))
int board_mcu_version(char *rev, const char **revstr, const char **errata)
{
/*
comes from esp-idf in efuse_hal_get_major_chip_version
and efuse_hal_get_minor_chip_version
*/
uint8_t eco_bit0 = (REG_READ(EFUSE_BLK0_RDATA3_REG) >> 15) & 0x1;
uint8_t eco_bit1 = (REG_READ(EFUSE_BLK0_RDATA5_REG) >> 20) & 0x1;
uint8_t eco_bit2 = (REG_READ(SYSCON_DATE_REG) & 0x80000000) >> 31;
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
uint8_t minor_revision = (REG_READ(EFUSE_BLK0_RDATA5_REG) >> 24) & 0x3;
int revid;
switch (combine_value) {
case 0:
*revstr = "ESP32 v0";
*rev = minor_revision + 48;
revid = minor_revision;
break;
case 1:
*revstr = "ESP32 v1";
*rev = minor_revision + 48;
revid = minor_revision;
break;
case 3:
*revstr = "ESP32 v2";
*rev = minor_revision + 48;
revid = minor_revision;
break;
case 7:
*revstr = "ESP32 v3";
*rev = minor_revision + 48;
revid = minor_revision;
break;
default:
*revstr = "ESP32 v?";
*rev = '?';
revid = 0;
break;
}
return revid;
}