mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-11-13 12:21:36 +08:00
Intial Commit NXP FMURT1170
nxp/rt117x:Fix Pin IRQ
nxp/rt117x:Support 4 i2c busses
nxp/rt117x:Add px4io_serial support
nxp/imxrt:Expand ToneAlarmInterface to GPT 3 & 4
nxp_fmurt1170-v1:Using imxrt_flexspi_nor_octal
nxp_fmurt1170-v1:Entry is start
nxp_fmurt1170-v1:Add Proper MTD
nxp_fmurt1170-v1:Set I2C Buses
nxp_fmurt1170-v1:Proper SPI usage
nxpfmurt1170-v1:Adjust memory Map to use the 2 MB
nxp_fmurt1170:Bring in ROMAPI
nxp_fmurt1170-v1:Push FLASH to 200Mhz
nxp_fmurt1170-v1:Use BOARD_I2C_LATEINIT
nxp_fmurt1170-v1:Clock Config remove unused devices
nxp_fmurt1170-v1:Remove EVK SDRAM IO
nxp_fmurt1170-v1:Enable SE550 using HW_VER_REV_DRIVE
nxp_fmurt1170-v1:Use MTD to mount FRAM on Flex SPI
nxp_fmurt1170-v1:Manifest
nxpi_fmurt1170-v1:Restore board_peripheral_reset
nxp_fmurt1170-v1:Set I2C buss Interna/Externa and startup
nxp/rt117x:Set 6 I2C busses
nxp_fmurt1170-v1:Correct Clock Sources and Freqency Settings
nxp_fmurt1170-v1:Correct ADC Settings
Tune FlexSPI config and sync header with debug variant Linker prep for rodata ahb partitioning
FlexSPI prefetch partition split .text and .rodata
Current config
1KB Prefetch .rodata
3KB Prefetch .text
nxp_fmurt1170-v1:Run imxrt_flash_setup_prefetch_partition from ram with barriers
nxp_fmurt1170-v1:Use All OCTL setting from FLASH g_flash_config SANS lookupTable
Octal spi boot/debug problem bypass
nxp_fmurt1170-v1:Add PWM test
Fix clockconfig and USB vbus sense
fmurt1170-v1: Use TCM
nxp_fmurt1170-v1: Ethernet bringup
imxrt: use unique_id register for board_identity
fmurt7: update ITCM mapping, todo proper trap on pc hitting 0x0
fmurt7: correct rotation icm42688p onboard imu
rt117x: Add SSARC HP RAM driver for memory dumps
nxp_fmurt1170-v1: Enable hardfault_log
nxp_fmurt1170-v1: Enable DMA pool
fmurt1170-v1: fix uart mapping
nxp_fmurt1170-v1: enable SocketCAN & DroneCAN
nxp_fmurt1170-v1:Command line history TAB completion
nxp_fmurt1170-v1:Fix pinning duplication
nxp_fmurt1170-v1:Support conditional PHY address based on selected PHY
nxp_fmurt1170-v1:Add Pull Downs on CTS, use GPIO for RTS
nxp_fmurt1170-v1:Set TelemN TX Slew rate and Drive Strenth to max
nxp_fmurt1170-v:Set TELEM Buffers add HW HS
nxp_fmurt1170-v1:Turn off DMA poll
nxp_fmurt1170-v1:RC_SERIAL_PORT needed to be px4io to disable rc_input using TELEM2!
imxrt1170 bootloader (#22228)
* imxrt:Add bootloader support
* bootloader:imxrt clear BOOT_RTC_SIGNATURE
* nxp_fmurt1170-v1:Add bootloader
* nxp_fmurt1170-v1:bootloader removed ADC
* nxp_fmurt1170-v1:bootloader base bootloader script off of script.ld
* nxp_fmurt1170-v1:add _bootdelay_signature & change entry from 0x30000000 to 0x30040000
* fmurt1170-v1:hw_config Bootloader has to have 12 bytes
nxp_fmurt1170-v1:Default to use LAN8742A PHY
This commit is contained in:
@@ -266,6 +266,7 @@ else()
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
-Wl,--script=${NUTTX_CONFIG_DIR_CYG}/scripts/${SCRIPT_PREFIX}script.ld
|
||||
-L${NUTTX_CONFIG_DIR_CYG}/scripts/${SCRIPT_PREFIX}
|
||||
-Wl,-Map=${PX4_CONFIG}.map
|
||||
-Wl,--warn-common
|
||||
-Wl,--gc-sections
|
||||
@@ -383,6 +384,9 @@ if(NOT NUTTX_DIR MATCHES "external")
|
||||
if(CONFIG_ARCH_CHIP_MIMXRT1062DVL6A)
|
||||
set(DEBUG_DEVICE "MIMXRT1062XXX6A")
|
||||
set(DEBUG_SVD_FILE "MIMXRT1052.svd")
|
||||
elseif(CONFIG_ARCH_CHIP_MIMXRT1176DVMAA)
|
||||
set(DEBUG_DEVICE "MIMXRT1176DVMAA")
|
||||
set(DEBUG_SVD_FILE "MIMXRT1176_cm7.xml")
|
||||
elseif(CONFIG_ARCH_CHIP_MK66FN2M0VMD18)
|
||||
set(DEBUG_DEVICE "MK66FN2M0xxx18")
|
||||
set(DEBUG_SVD_FILE "MK66F18.svd")
|
||||
|
||||
@@ -294,13 +294,13 @@ void
|
||||
jump_to_app()
|
||||
{
|
||||
const uint32_t *app_base = (const uint32_t *)APP_LOAD_ADDRESS;
|
||||
const uint32_t *vec_base = (const uint32_t *)app_base;
|
||||
const uint32_t *vec_base = (const uint32_t *)app_base + APP_VECTOR_OFFSET;
|
||||
|
||||
/*
|
||||
* We refuse to program the first word of the app until the upload is marked
|
||||
* complete by the host. So if it's not 0xffffffff, we should try booting it.
|
||||
*/
|
||||
if (app_base[0] == 0xffffffff) {
|
||||
if (app_base[APP_VECTOR_OFFSET_WORDS] == 0xffffffff) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -382,11 +382,11 @@ jump_to_app()
|
||||
* The second word of the app is the entrypoint; it must point within the
|
||||
* flash area (or we have a bad flash).
|
||||
*/
|
||||
if (app_base[1] < APP_LOAD_ADDRESS) {
|
||||
if (app_base[APP_VECTOR_OFFSET_WORDS + 1] < APP_LOAD_ADDRESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (app_base[1] >= (APP_LOAD_ADDRESS + board_info.fw_size)) {
|
||||
if (app_base[APP_VECTOR_OFFSET_WORDS + 1] >= (APP_LOAD_ADDRESS + board_info.fw_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -816,15 +816,17 @@ bootloader(unsigned timeout)
|
||||
goto cmd_bad;
|
||||
}
|
||||
|
||||
if (address == 0) {
|
||||
#if APP_VECTOR_OFFSET == 0
|
||||
|
||||
#if defined(TARGET_HW_PX4_FMU_V4)
|
||||
if (address == APP_VECTOR_OFFSET) {
|
||||
|
||||
# if defined(TARGET_HW_PX4_FMU_V4)
|
||||
|
||||
if (check_silicon()) {
|
||||
goto bad_silicon;
|
||||
}
|
||||
|
||||
#endif
|
||||
# endif
|
||||
|
||||
// save the first word and don't program it until everything else is done
|
||||
first_word = flash_buffer.w[0];
|
||||
@@ -832,10 +834,20 @@ bootloader(unsigned timeout)
|
||||
flash_buffer.w[0] = 0xffffffff;
|
||||
}
|
||||
|
||||
#endif
|
||||
arg /= 4;
|
||||
|
||||
for (int i = 0; i < arg; i++) {
|
||||
#if APP_VECTOR_OFFSET != 0
|
||||
|
||||
if (address == APP_VECTOR_OFFSET) {
|
||||
// save the first word from vector table and don't program it until everything else is done
|
||||
first_word = flash_buffer.w[i];
|
||||
// replace first word with bits we can overwrite later
|
||||
flash_buffer.w[i] = 0xffffffff;
|
||||
}
|
||||
|
||||
#endif
|
||||
// program the word
|
||||
flash_func_write_word(address, flash_buffer.w[i]);
|
||||
|
||||
@@ -869,7 +881,7 @@ bootloader(unsigned timeout)
|
||||
for (unsigned p = 0; p < board_info.fw_size; p += 4) {
|
||||
uint32_t bytes;
|
||||
|
||||
if ((p == 0) && (first_word != 0xffffffff)) {
|
||||
if ((p == APP_VECTOR_OFFSET) && (first_word != 0xffffffff)) {
|
||||
bytes = first_word;
|
||||
|
||||
} else {
|
||||
@@ -1032,9 +1044,9 @@ bootloader(unsigned timeout)
|
||||
|
||||
// program the deferred first word
|
||||
if (first_word != 0xffffffff) {
|
||||
flash_func_write_word(0, first_word);
|
||||
flash_func_write_word(APP_VECTOR_OFFSET, first_word);
|
||||
|
||||
if (flash_func_read_word(0) != first_word) {
|
||||
if (flash_func_read_word(APP_VECTOR_OFFSET) != first_word) {
|
||||
goto cmd_fail;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,3 +129,8 @@ extern void cinit(void *config, uint8_t interface);
|
||||
extern void cfini(void);
|
||||
extern int cin(uint32_t devices);
|
||||
extern void cout(uint8_t *buf, unsigned len);
|
||||
|
||||
#if !defined(APP_VECTOR_OFFSET)
|
||||
# define APP_VECTOR_OFFSET 0
|
||||
#endif
|
||||
#define APP_VECTOR_OFFSET_WORDS (APP_VECTOR_OFFSET/sizeof(uint32_t))
|
||||
|
||||
@@ -32,10 +32,13 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "flash_cache.h"
|
||||
|
||||
#include "hw_config.h"
|
||||
|
||||
#include "bl.h"
|
||||
|
||||
#include <nuttx/progmem.h>
|
||||
|
||||
extern ssize_t arch_flash_write(uintptr_t address, const void *buffer, size_t buflen);
|
||||
@@ -54,7 +57,7 @@ inline void fc_reset(void)
|
||||
fcl_reset(&flash_cache[w]);
|
||||
}
|
||||
|
||||
flash_cache[0].start_address = APP_LOAD_ADDRESS;
|
||||
flash_cache[0].start_address = APP_LOAD_ADDRESS + APP_VECTOR_OFFSET;
|
||||
}
|
||||
|
||||
static inline flash_cache_line_t *fc_line_select(uintptr_t address)
|
||||
@@ -104,7 +107,7 @@ int fc_write(uintptr_t address, uint32_t word)
|
||||
|
||||
// Are we back writing the first word?
|
||||
|
||||
if (fc == &flash_cache[0] && index == 0 && fc->index == 7) {
|
||||
if (fc == &flash_cache[0] && index == 0 && fc->index == FC_LAST_WORD) {
|
||||
|
||||
if (fc_is_dirty(fc1)) {
|
||||
|
||||
|
||||
@@ -46,10 +46,15 @@
|
||||
* *writes to the first 8 words of flash at APP_LOAD_ADDRESS
|
||||
* are buffered until the "first word" is written with the real value (not 0xffffffff)
|
||||
*
|
||||
* On a imxrt the ROM API supports 256 byte writes.
|
||||
*/
|
||||
|
||||
#define FC_NUMBER_LINES 2 // Number of cache lines.
|
||||
#if defined(CONFIG_ARCH_CHIP_IMXRT)
|
||||
#define FC_NUMBER_WORDS 64 // Number of words per page
|
||||
#else
|
||||
#define FC_NUMBER_WORDS 8 // Number of words per cache line.
|
||||
#endif
|
||||
#define FC_NUMBER_LINES 2 // Number of cache lines.
|
||||
#define FC_LAST_WORD FC_NUMBER_WORDS-1 // The index of the last word in cache line.
|
||||
#define FC_ADDRESS_MASK ~(sizeof(flash_cache[0].words)-1) // Cache tag from address
|
||||
#define FC_ADDR2INDX(a) (((a) / sizeof(flash_cache[0].words[0])) % FC_NUMBER_WORDS) // index from address
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2023 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,43 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2023 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_bootloader
|
||||
main.c
|
||||
systick.c
|
||||
)
|
||||
|
||||
target_link_libraries(arch_bootloader
|
||||
PRIVATE
|
||||
bootloader_lib
|
||||
nuttx_arch
|
||||
)
|
||||
@@ -0,0 +1,795 @@
|
||||
/*
|
||||
* imxrt board support for the bootloader.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <px4_platform_common/px4_config.h>
|
||||
#include <px4_defines.h>
|
||||
|
||||
#include "hw_config.h"
|
||||
#include "imxrt_flexspi_nor_flash.h"
|
||||
#include "imxrt_romapi.h"
|
||||
#include <hardware/rt117x/imxrt117x_ocotp.h>
|
||||
#include <hardware/rt117x/imxrt117x_anadig.h>
|
||||
#include <hardware/rt117x/imxrt117x_snvs.h>
|
||||
#include <hardware/imxrt_usb_analog.h>
|
||||
#include "imxrt_clockconfig.h"
|
||||
|
||||
#include <nvic.h>
|
||||
#include <lib/systick.h>
|
||||
#include <lib/flash_cache.h>
|
||||
|
||||
#include "bl.h"
|
||||
#include "uart.h"
|
||||
#include "arm_internal.h"
|
||||
|
||||
#define MK_GPIO_INPUT(def) (((def) & (GPIO_PORT_MASK | GPIO_PIN_MASK | GPIO_MODE_MASK)) | (GPIO_INPUT))
|
||||
|
||||
#define BOOTLOADER_RESERVATION_SIZE (128 * 1024)
|
||||
|
||||
#define APP_SIZE_MAX (BOARD_FLASH_SIZE - (BOOTLOADER_RESERVATION_SIZE + APP_RESERVATION_SIZE))
|
||||
|
||||
#define CHIP_TAG "i.MX RT11?0,r??"
|
||||
#define CHIP_TAG_LEN sizeof(CHIP_TAG)-1
|
||||
|
||||
#define SI_REV(n) ((n & 0x7000000) >> 24)
|
||||
#define DIFPROG_TYPE(n) ((n & 0xF000) >> 12)
|
||||
#define DIFPROG_REV_MAJOR(n) ((n & 0xF0) >> 4)
|
||||
#define DIFPROG_REV_MINOR(n) ((n & 0xF))
|
||||
|
||||
|
||||
/* context passed to cinit */
|
||||
#if INTERFACE_USART
|
||||
# define BOARD_INTERFACE_CONFIG_USART INTERFACE_USART_CONFIG
|
||||
#endif
|
||||
#if INTERFACE_USB
|
||||
# define BOARD_INTERFACE_CONFIG_USB INTERFACE_USB_CONFIG
|
||||
#endif
|
||||
|
||||
/* board definition */
|
||||
struct boardinfo board_info = {
|
||||
.board_type = BOARD_TYPE,
|
||||
.board_rev = 0,
|
||||
.fw_size = 0,
|
||||
.systick_mhz = 480,
|
||||
};
|
||||
|
||||
static void board_init(void);
|
||||
|
||||
#define BOOT_RTC_SIGNATURE 0xb007b007
|
||||
#define PX4_IMXRT_RTC_REBOOT_REG IMXRT_SNVS_LPGPR3
|
||||
|
||||
/* State of an inserted USB cable */
|
||||
static bool usb_connected = false;
|
||||
|
||||
static uint32_t board_get_rtc_signature(void)
|
||||
{
|
||||
uint32_t result = getreg32(PX4_IMXRT_RTC_REBOOT_REG);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
board_set_rtc_signature(uint32_t sig)
|
||||
{
|
||||
modifyreg32(IMXRT_SNVS_LPCR, 0, SNVS_LPCR_GPR_Z_DIS);
|
||||
|
||||
putreg32(sig, PX4_IMXRT_RTC_REBOOT_REG);
|
||||
|
||||
}
|
||||
|
||||
static bool board_test_force_pin(void)
|
||||
{
|
||||
#if defined(BOARD_FORCE_BL_PIN_IN) && defined(BOARD_FORCE_BL_PIN_OUT)
|
||||
/* two pins strapped together */
|
||||
volatile unsigned samples = 0;
|
||||
volatile unsigned vote = 0;
|
||||
|
||||
for (volatile unsigned cycles = 0; cycles < 10; cycles++) {
|
||||
px4_arch_gpiowrite(BOARD_FORCE_BL_PIN_OUT, 1);
|
||||
|
||||
for (unsigned count = 0; count < 20; count++) {
|
||||
if (px4_arch_gpioread(BOARD_FORCE_BL_PIN_IN) != 0) {
|
||||
vote++;
|
||||
}
|
||||
|
||||
samples++;
|
||||
}
|
||||
|
||||
px4_arch_gpiowrite(BOARD_FORCE_BL_PIN_OUT, 0);
|
||||
|
||||
for (unsigned count = 0; count < 20; count++) {
|
||||
if (px4_arch_gpioread(BOARD_FORCE_BL_PIN_IN) == 0) {
|
||||
vote++;
|
||||
}
|
||||
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
|
||||
/* the idea here is to reject wire-to-wire coupling, so require > 90% agreement */
|
||||
if ((vote * 100) > (samples * 90)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(BOARD_FORCE_BL_PIN)
|
||||
/* single pin pulled up or down */
|
||||
volatile unsigned samples = 0;
|
||||
volatile unsigned vote = 0;
|
||||
|
||||
for (samples = 0; samples < 200; samples++) {
|
||||
if ((px4_arch_gpioread(BOARD_FORCE_BL_PIN) ? 1 : 0) == BOARD_FORCE_BL_STATE) {
|
||||
vote++;
|
||||
}
|
||||
}
|
||||
|
||||
/* reject a little noise */
|
||||
if ((vote * 100) > (samples * 90)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if INTERFACE_USART
|
||||
static bool board_test_usart_receiving_break(void)
|
||||
{
|
||||
#if !defined(SERIAL_BREAK_DETECT_DISABLED)
|
||||
/* (re)start the SysTick timer system */
|
||||
systick_interrupt_disable(); // Kill the interrupt if it is still active
|
||||
systick_counter_disable(); // Stop the timer
|
||||
systick_set_clocksource(CLKSOURCE_PROCESOR);
|
||||
|
||||
/* Set the timer period to be half the bit rate
|
||||
*
|
||||
* Baud rate = 115200, therefore bit period = 8.68us
|
||||
* Half the bit rate = 4.34us
|
||||
* Set period to 4.34 microseconds (timer_period = timer_tick / timer_reset_frequency = 168MHz / (1/4.34us) = 729.12 ~= 729)
|
||||
*/
|
||||
systick_set_reload(729); /* 4.3us tick, magic number */
|
||||
systick_counter_enable(); // Start the timer
|
||||
|
||||
uint8_t cnt_consecutive_low = 0;
|
||||
uint8_t cnt = 0;
|
||||
|
||||
/* Loop for 3 transmission byte cycles and count the low and high bits. Sampled at a rate to be able to count each bit twice.
|
||||
*
|
||||
* One transmission byte is 10 bits (8 bytes of data + 1 start bit + 1 stop bit)
|
||||
* We sample at every half bit time, therefore 20 samples per transmission byte,
|
||||
* therefore 60 samples for 3 transmission bytes
|
||||
*/
|
||||
while (cnt < 60) {
|
||||
// Only read pin when SysTick timer is true
|
||||
if (systick_get_countflag() == 1) {
|
||||
if (gpio_get(BOARD_PORT_USART_RX, BOARD_PIN_RX) == 0) {
|
||||
cnt_consecutive_low++; // Increment the consecutive low counter
|
||||
|
||||
} else {
|
||||
cnt_consecutive_low = 0; // Reset the consecutive low counter
|
||||
}
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
// If 9 consecutive low bits were received break out of the loop
|
||||
if (cnt_consecutive_low >= 18) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
systick_counter_disable(); // Stop the timer
|
||||
|
||||
/*
|
||||
* If a break is detected, return true, else false
|
||||
*
|
||||
* Break is detected if line was low for 9 consecutive bits.
|
||||
*/
|
||||
if (cnt_consecutive_low >= 18) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !defined(SERIAL_BREAK_DETECT_DISABLED)
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t
|
||||
board_get_devices(void)
|
||||
{
|
||||
uint32_t devices = BOOT_DEVICES_SELECTION;
|
||||
|
||||
if (usb_connected) {
|
||||
devices &= BOOT_DEVICES_FILTER_ONUSB;
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
static void
|
||||
board_init(void)
|
||||
{
|
||||
/* fix up the max firmware size, we have to read memory to get this */
|
||||
board_info.fw_size = APP_SIZE_MAX;
|
||||
|
||||
#if defined(BOARD_POWER_PIN_OUT)
|
||||
/* Configure the Power pins */
|
||||
px4_arch_configgpio(BOARD_POWER_PIN_OUT);
|
||||
px4_arch_gpiowrite(BOARD_POWER_PIN_OUT, BOARD_POWER_ON);
|
||||
#endif
|
||||
|
||||
#if INTERFACE_USB
|
||||
#endif
|
||||
|
||||
#if INTERFACE_USART
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_FORCE_BL_PIN_IN) && defined(BOARD_FORCE_BL_PIN_OUT)
|
||||
/* configure the force BL pins */
|
||||
px4_arch_configgpio(BOARD_FORCE_BL_PIN_IN);
|
||||
px4_arch_configgpio(BOARD_FORCE_BL_PIN_OUT);
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_FORCE_BL_PIN)
|
||||
/* configure the force BL pins */
|
||||
px4_arch_configgpio(BOARD_FORCE_BL_PIN);
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_PIN_LED_ACTIVITY)
|
||||
/* Initialize LEDs */
|
||||
px4_arch_configgpio(BOARD_PIN_LED_ACTIVITY);
|
||||
#endif
|
||||
#if defined(BOARD_PIN_LED_BOOTLOADER)
|
||||
/* Initialize LEDs */
|
||||
px4_arch_configgpio(BOARD_PIN_LED_BOOTLOADER);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
board_deinit(void)
|
||||
{
|
||||
|
||||
#if INTERFACE_USART
|
||||
#endif
|
||||
|
||||
#if INTERFACE_USB
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_FORCE_BL_PIN_IN) && defined(BOARD_FORCE_BL_PIN_OUT)
|
||||
/* deinitialise the force BL pins */
|
||||
px4_arch_configgpio(MK_GPIO_INPUT(BOARD_FORCE_BL_PIN_IN));
|
||||
px4_arch_configgpio(MK_GPIO_INPUT(BOARD_FORCE_BL_PIN_OUT));
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_FORCE_BL_PIN)
|
||||
/* deinitialise the force BL pin */
|
||||
px4_arch_configgpio(MK_GPIO_INPUT(BOARD_FORCE_BL_PIN));
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_POWER_PIN_OUT) && defined(BOARD_POWER_PIN_RELEASE)
|
||||
/* deinitialize the POWER pin - with the assumption the hold up time of
|
||||
* the voltage being bleed off by an inupt pin impedance will allow
|
||||
* enough time to boot the app
|
||||
*/
|
||||
px4_arch_configgpio(MK_GPIO_INPUT(BOARD_POWER_PIN_OUT));
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_PIN_LED_ACTIVITY)
|
||||
/* Initialize LEDs */
|
||||
px4_arch_configgpio(MK_GPIO_INPUT(BOARD_PIN_LED_ACTIVITY));
|
||||
#endif
|
||||
#if defined(BOARD_PIN_LED_BOOTLOADER)
|
||||
/* Initialize LEDs */
|
||||
px4_arch_configgpio(MK_GPIO_INPUT(BOARD_PIN_LED_BOOTLOADER));
|
||||
#endif
|
||||
|
||||
const uint32_t dnfw[] = {
|
||||
CCM_CR_M7,
|
||||
CCM_CR_BUS,
|
||||
CCM_CR_BUS_LPSR,
|
||||
CCM_CR_SEMC,
|
||||
CCM_CR_CSSYS,
|
||||
CCM_CR_CSTRACE,
|
||||
CCM_CR_FLEXSPI1,
|
||||
CCM_CR_FLEXSPI2
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i < IMXRT_CCM_CR_COUNT; i++) {
|
||||
bool ok = true;
|
||||
|
||||
for (unsigned int d = 0; ok && d < arraySize(dnfw); d++) {
|
||||
ok = dnfw[d] != i;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
putreg32(CCM_CR_CTRL_OFF, IMXRT_CCM_CR_CTRL(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void arch_systic_init(void)
|
||||
{
|
||||
// Done in NuttX
|
||||
}
|
||||
|
||||
inline void arch_systic_deinit(void)
|
||||
{
|
||||
/* kill the systick interrupt */
|
||||
irq_attach(IMXRT_IRQ_SYSTICK, NULL, NULL);
|
||||
modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_CLKSOURCE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the RCC clock configuration.
|
||||
*
|
||||
* @param clock_setup : The clock configuration to set
|
||||
*/
|
||||
static inline void
|
||||
clock_init(void)
|
||||
{
|
||||
// Done by Nuttx
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the RCC clock configuration to the default reset state.
|
||||
* @note The default reset state of the clock configuration is given below:
|
||||
* @note This function doesn't modify the configuration of the
|
||||
*/
|
||||
void
|
||||
clock_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
void arch_flash_lock(void)
|
||||
{
|
||||
}
|
||||
|
||||
void arch_flash_unlock(void)
|
||||
{
|
||||
fc_reset();
|
||||
}
|
||||
|
||||
ssize_t arch_flash_write(uintptr_t address, const void *buffer, size_t buflen)
|
||||
{
|
||||
struct flexspi_nor_config_s *pConfig = &g_bootConfig;
|
||||
irqstate_t flags = enter_critical_section();
|
||||
|
||||
static volatile int j = 0;
|
||||
j++;
|
||||
|
||||
if (j == 6) {
|
||||
j++;
|
||||
}
|
||||
|
||||
uintptr_t offset = ((uintptr_t) address) - IMXRT_FLEXSPI1_CIPHER_BASE;
|
||||
|
||||
volatile uint32_t status = ROM_FLEXSPI_NorFlash_ProgramPage(1, pConfig, offset, (const uint32_t *)buffer);
|
||||
up_invalidate_dcache((uintptr_t)address,
|
||||
(uintptr_t)address + buflen);
|
||||
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
if (status == 100) {
|
||||
return buflen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void arch_setvtor(const uint32_t *address)
|
||||
{
|
||||
putreg32((uint32_t)address, NVIC_VECTAB);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
flash_func_sector_size(unsigned sector)
|
||||
{
|
||||
if (sector <= BOARD_FLASH_SECTORS) {
|
||||
return 4 * 1024;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @name Configuration Option
|
||||
* @{
|
||||
*/
|
||||
/*! @brief Serial NOR Configuration Option. */
|
||||
|
||||
|
||||
/*@}
|
||||
* */
|
||||
locate_code(".ramfunc")
|
||||
void
|
||||
flash_func_erase_sector(unsigned sector)
|
||||
{
|
||||
|
||||
if (sector > BOARD_FLASH_SECTORS || (int)sector < BOARD_FIRST_FLASH_SECTOR_TO_ERASE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* blank-check the sector */
|
||||
const uint32_t bytes_per_sector = flash_func_sector_size(sector);
|
||||
uint32_t *address = (uint32_t *)(IMXRT_FLEXSPI1_CIPHER_BASE + (sector * bytes_per_sector));
|
||||
const uint32_t uint32_per_sector = bytes_per_sector / sizeof(*address);
|
||||
bool blank = true;
|
||||
|
||||
for (uint32_t i = 0; i < uint32_per_sector; i++) {
|
||||
if (address[i] != 0xffffffff) {
|
||||
blank = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct flexspi_nor_config_s *pConfig = &g_bootConfig;
|
||||
|
||||
/* erase the sector if it failed the blank check */
|
||||
if (!blank) {
|
||||
uintptr_t offset = ((uintptr_t) address) - IMXRT_FLEXSPI1_CIPHER_BASE;
|
||||
irqstate_t flags;
|
||||
flags = enter_critical_section();
|
||||
volatile uint32_t status = ROM_FLEXSPI_NorFlash_Erase(1, pConfig, (uintptr_t) offset, bytes_per_sector);
|
||||
leave_critical_section(flags);
|
||||
UNUSED(status);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
flash_func_write_word(uintptr_t address, uint32_t word)
|
||||
{
|
||||
address += APP_LOAD_ADDRESS;
|
||||
fc_write(address, word);
|
||||
}
|
||||
|
||||
uint32_t flash_func_read_word(uintptr_t address)
|
||||
{
|
||||
|
||||
if (address & 3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fc_read(address + APP_LOAD_ADDRESS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
flash_func_read_otp(uintptr_t address)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t get_mcu_id(void)
|
||||
{
|
||||
// ??? is DEBUGMCU get able
|
||||
return *(uint32_t *) IMXRT_ANADIG_MISC_MISC_DIFPROG;
|
||||
}
|
||||
|
||||
int get_mcu_desc(int max, uint8_t *revstr)
|
||||
{
|
||||
uint32_t info = getreg32(IMXRT_ANADIG_MISC_MISC_DIFPROG);
|
||||
// CHIP_TAG "i.MX RT11?0,r??"
|
||||
static uint8_t chip[sizeof(CHIP_TAG) + 1] = CHIP_TAG;
|
||||
chip[CHIP_TAG_LEN - 6] = '0' + DIFPROG_TYPE(info);
|
||||
chip[CHIP_TAG_LEN - 2] = 'A' + (DIFPROG_REV_MAJOR(info) - 10);
|
||||
chip[CHIP_TAG_LEN - 1] = '0' + DIFPROG_REV_MINOR(info);
|
||||
|
||||
uint8_t *endp = &revstr[max - 1];
|
||||
uint8_t *strp = revstr;
|
||||
uint8_t *des = chip;
|
||||
|
||||
while (strp < endp && *des) {
|
||||
*strp++ = *des++;
|
||||
}
|
||||
|
||||
return strp - revstr;
|
||||
}
|
||||
|
||||
|
||||
int check_silicon(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
flash_func_read_sn(uintptr_t address)
|
||||
{
|
||||
// Bootload has to uses 12 byte ID (3 Words)
|
||||
// but this IC has only 2 words
|
||||
// Address will be 0 4 8 - 3 words
|
||||
// so dummy up the last word....
|
||||
if (address > 4) {
|
||||
return 0x31313630;
|
||||
}
|
||||
|
||||
return *(uint32_t *)((address * 4) + IMXRT_OCOTP_UNIQUE_ID_MSB);
|
||||
}
|
||||
|
||||
void
|
||||
led_on(unsigned led)
|
||||
{
|
||||
switch (led) {
|
||||
case LED_ACTIVITY:
|
||||
#if defined(BOARD_PIN_LED_ACTIVITY)
|
||||
px4_arch_gpiowrite(BOARD_PIN_LED_ACTIVITY, BOARD_LED_ON);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case LED_BOOTLOADER:
|
||||
#if defined(BOARD_PIN_LED_BOOTLOADER)
|
||||
px4_arch_gpiowrite(BOARD_PIN_LED_BOOTLOADER, BOARD_LED_ON);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
led_off(unsigned led)
|
||||
{
|
||||
switch (led) {
|
||||
case LED_ACTIVITY:
|
||||
#if defined(BOARD_PIN_LED_ACTIVITY)
|
||||
px4_arch_gpiowrite(BOARD_PIN_LED_ACTIVITY, BOARD_LED_OFF);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case LED_BOOTLOADER:
|
||||
#if defined(BOARD_PIN_LED_BOOTLOADER)
|
||||
px4_arch_gpiowrite(BOARD_PIN_LED_BOOTLOADER, BOARD_LED_OFF);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
led_toggle(unsigned led)
|
||||
{
|
||||
switch (led) {
|
||||
case LED_ACTIVITY:
|
||||
#if defined(BOARD_PIN_LED_ACTIVITY)
|
||||
px4_arch_gpiowrite(BOARD_PIN_LED_ACTIVITY, px4_arch_gpioread(BOARD_PIN_LED_ACTIVITY) ^ 1);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case LED_BOOTLOADER:
|
||||
#if defined(BOARD_PIN_LED_BOOTLOADER)
|
||||
px4_arch_gpiowrite(BOARD_PIN_LED_BOOTLOADER, px4_arch_gpioread(BOARD_PIN_LED_BOOTLOADER) ^ 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* we should know this, but we don't */
|
||||
#ifndef SCB_CPACR
|
||||
# define SCB_CPACR (*((volatile uint32_t *) (((0xE000E000UL) + 0x0D00UL) + 0x088)))
|
||||
#endif
|
||||
|
||||
/* Make the actual jump to app */
|
||||
void
|
||||
arch_do_jump(const uint32_t *app_base)
|
||||
{
|
||||
|
||||
/* extract the stack and entrypoint from the app vector table and go */
|
||||
uint32_t stacktop = app_base[APP_VECTOR_OFFSET_WORDS];
|
||||
uint32_t entrypoint = app_base[APP_VECTOR_OFFSET_WORDS + 1];
|
||||
|
||||
asm volatile(
|
||||
"msr msp, %0 \n"
|
||||
"bx %1 \n"
|
||||
: : "r"(stacktop), "r"(entrypoint) :);
|
||||
|
||||
// just to keep noreturn happy
|
||||
for (;;) ;
|
||||
}
|
||||
|
||||
int
|
||||
bootloader_main(void)
|
||||
{
|
||||
bool try_boot = true; /* try booting before we drop to the bootloader */
|
||||
unsigned timeout = BOOTLOADER_DELAY; /* if nonzero, drop out of the bootloader after this time */
|
||||
|
||||
/* Enable the FPU before we hit any FP instructions */
|
||||
SCB_CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 Full Access and set CP11 Full Access */
|
||||
|
||||
#if defined(BOARD_POWER_PIN_OUT)
|
||||
|
||||
/* Here we check for the app setting the POWER_DOWN_RTC_SIGNATURE
|
||||
* in this case, we reset the signature and wait to die
|
||||
*/
|
||||
if (board_get_rtc_signature() == POWER_DOWN_RTC_SIGNATURE) {
|
||||
board_set_rtc_signature(0);
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* do board-specific initialisation */
|
||||
board_init();
|
||||
|
||||
/* configure the clock for bootloader activity */
|
||||
clock_init();
|
||||
|
||||
/*
|
||||
* Check the force-bootloader register; if we find the signature there, don't
|
||||
* try booting.
|
||||
*/
|
||||
if (board_get_rtc_signature() == BOOT_RTC_SIGNATURE) {
|
||||
|
||||
/*
|
||||
* Don't even try to boot before dropping to the bootloader.
|
||||
*/
|
||||
try_boot = false;
|
||||
|
||||
/*
|
||||
* Don't drop out of the bootloader until something has been uploaded.
|
||||
*/
|
||||
timeout = 0;
|
||||
|
||||
/*
|
||||
* Clear the signature so that if someone resets us while we're
|
||||
* in the bootloader we'll try to boot next time.
|
||||
*/
|
||||
board_set_rtc_signature(0);
|
||||
}
|
||||
|
||||
#ifdef BOOT_DELAY_ADDRESS
|
||||
{
|
||||
/*
|
||||
if a boot delay signature is present then delay the boot
|
||||
by at least that amount of time in seconds. This allows
|
||||
for an opportunity for a companion computer to load a
|
||||
new firmware, while still booting fast by sending a BOOT
|
||||
command
|
||||
*/
|
||||
uint32_t sig1 = flash_func_read_word(BOOT_DELAY_ADDRESS);
|
||||
uint32_t sig2 = flash_func_read_word(BOOT_DELAY_ADDRESS + 4);
|
||||
|
||||
if (sig2 == BOOT_DELAY_SIGNATURE2 &&
|
||||
(sig1 & 0xFFFFFF00) == (BOOT_DELAY_SIGNATURE1 & 0xFFFFFF00)) {
|
||||
unsigned boot_delay = sig1 & 0xFF;
|
||||
|
||||
if (boot_delay <= BOOT_DELAY_MAX) {
|
||||
try_boot = false;
|
||||
|
||||
if (timeout < boot_delay * 1000) {
|
||||
timeout = boot_delay * 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if the force-bootloader pins are strapped; if strapped,
|
||||
* don't try booting.
|
||||
*/
|
||||
if (board_test_force_pin()) {
|
||||
try_boot = false;
|
||||
}
|
||||
|
||||
#if INTERFACE_USB
|
||||
|
||||
/*
|
||||
* Check for USB connection - if present, don't try to boot, but set a timeout after
|
||||
* which we will fall out of the bootloader.
|
||||
*
|
||||
* If the force-bootloader pins are tied, we will stay here until they are removed and
|
||||
* we then time out.
|
||||
*/
|
||||
/************************************************************************************
|
||||
* Name: board_read_VBUS_state
|
||||
*
|
||||
* Description:
|
||||
* All boards must provide a way to read the state of VBUS, this my be simple
|
||||
* digital input on a GPIO. Or something more complicated like a Analong input
|
||||
* or reading a bit from a USB controller register.
|
||||
*
|
||||
* Returns - 0 if connected.
|
||||
*
|
||||
************************************************************************************/
|
||||
#undef IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT
|
||||
#define USB1_VBUS_DET_STAT_OFFSET 0xd0
|
||||
#define IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT (IMXRT_USBPHY1_BASE + USB1_VBUS_DET_STAT_OFFSET)
|
||||
|
||||
if ((getreg32(IMXRT_USB_ANALOG_USB1_VBUS_DETECT_STAT) & USB_ANALOG_USB_VBUS_DETECT_STAT_VBUS_3V_VALID) != 0) {
|
||||
usb_connected = true;
|
||||
/* don't try booting before we set up the bootloader */
|
||||
try_boot = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if INTERFACE_USART
|
||||
|
||||
/*
|
||||
* Check for if the USART port RX line is receiving a break command, or is being held low. If yes,
|
||||
* don't try to boot, but set a timeout after
|
||||
* which we will fall out of the bootloader.
|
||||
*
|
||||
* If the force-bootloader pins are tied, we will stay here until they are removed and
|
||||
* we then time out.
|
||||
*/
|
||||
if (board_test_usart_receiving_break()) {
|
||||
try_boot = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Try to boot the app if we think we should just go straight there */
|
||||
if (try_boot) {
|
||||
|
||||
/* set the boot-to-bootloader flag so that if boot fails on reset we will stop here */
|
||||
#ifdef BOARD_BOOT_FAIL_DETECT
|
||||
board_set_rtc_signature(BOOT_RTC_SIGNATURE);
|
||||
#endif
|
||||
|
||||
/* try to boot immediately */
|
||||
jump_to_app();
|
||||
|
||||
// If it failed to boot, reset the boot signature and stay in bootloader
|
||||
board_set_rtc_signature(BOOT_RTC_SIGNATURE);
|
||||
|
||||
/* booting failed, stay in the bootloader forever */
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
|
||||
/* start the interface */
|
||||
#if INTERFACE_USART
|
||||
cinit(BOARD_INTERFACE_CONFIG_USART, USART);
|
||||
#endif
|
||||
#if INTERFACE_USB
|
||||
cinit(BOARD_INTERFACE_CONFIG_USB, USB);
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
// MCO1/02
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO8);
|
||||
gpio_set_af(GPIOA, GPIO_AF0, GPIO8);
|
||||
gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
|
||||
gpio_set_af(GPIOC, GPIO_AF0, GPIO9);
|
||||
#endif
|
||||
|
||||
|
||||
while (1) {
|
||||
/* run the bootloader, come back after an app is uploaded or we time out */
|
||||
bootloader(timeout);
|
||||
|
||||
/* if the force-bootloader pins are strapped, just loop back */
|
||||
if (board_test_force_pin()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if INTERFACE_USART
|
||||
|
||||
/* if the USART port RX line is still receiving a break, just loop back */
|
||||
if (board_test_usart_receiving_break()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* set the boot-to-bootloader flag so that if boot fails on reset we will stop here */
|
||||
#ifdef BOARD_BOOT_FAIL_DETECT
|
||||
board_set_rtc_signature(BOOT_RTC_SIGNATURE);
|
||||
#endif
|
||||
|
||||
/* look to see if we can boot the app */
|
||||
jump_to_app();
|
||||
|
||||
/* launching the app failed - stay in the bootloader forever */
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "lib/systick.h"
|
||||
#include <nvic.h>
|
||||
|
||||
uint8_t systick_get_countflag(void)
|
||||
{
|
||||
return (getreg32(NVIC_SYSTICK_CTRL) & NVIC_SYSTICK_CTRL_COUNTFLAG) ? 1 : 0;
|
||||
}
|
||||
|
||||
// See 2.2.3 SysTick external clock is not HCLK/8
|
||||
uint32_t g_divisor = 1;
|
||||
void systick_set_reload(uint32_t value)
|
||||
{
|
||||
putreg32((((value * g_divisor) << NVIC_SYSTICK_RELOAD_SHIFT) & NVIC_SYSTICK_RELOAD_MASK), NVIC_SYSTICK_RELOAD);
|
||||
}
|
||||
|
||||
|
||||
void systick_set_clocksource(uint8_t clocksource)
|
||||
{
|
||||
g_divisor = (clocksource == CLKSOURCE_EXTERNAL) ? 8 : 1;
|
||||
modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_CLKSOURCE, clocksource & NVIC_SYSTICK_CTRL_CLKSOURCE);
|
||||
}
|
||||
|
||||
void systick_counter_enable(void)
|
||||
{
|
||||
modifyreg32(NVIC_SYSTICK_CTRL, 0, NVIC_SYSTICK_CTRL_ENABLE);
|
||||
}
|
||||
|
||||
void systick_counter_disable(void)
|
||||
{
|
||||
modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_ENABLE, 0);
|
||||
putreg32(0, NVIC_SYSTICK_CURRENT);
|
||||
}
|
||||
|
||||
void systick_interrupt_enable(void)
|
||||
{
|
||||
modifyreg32(NVIC_SYSTICK_CTRL, 0, NVIC_SYSTICK_CTRL_TICKINT);
|
||||
}
|
||||
|
||||
void systick_interrupt_disable(void)
|
||||
{
|
||||
modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_TICKINT, 0);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2023 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(../imxrt_common arch_bootloader)
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2020 PX4 Development Team. All rights reserved.
|
||||
* Copyright (C) 2020, 2023 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
|
||||
@@ -47,6 +47,8 @@ typedef struct {
|
||||
int hi;
|
||||
} lh_t;
|
||||
|
||||
|
||||
#if defined(CONFIG_ARCH_FAMILY_IMXRT106x)
|
||||
const lh_t port_to_irq[9] = {
|
||||
{_IMXRT_GPIO1_0_15_BASE, _IMXRT_GPIO1_16_31_BASE}, {_IMXRT_GPIO2_0_15_BASE, _IMXRT_GPIO2_16_31_BASE},
|
||||
{_IMXRT_GPIO3_0_15_BASE, _IMXRT_GPIO3_16_31_BASE}, {_IMXRT_GPIO4_0_15_BASE, _IMXRT_GPIO4_16_31_BASE},
|
||||
@@ -54,6 +56,41 @@ const lh_t port_to_irq[9] = {
|
||||
{_IMXRT_GPIO7_0_15_BASE, _IMXRT_GPIO7_16_31_BASE}, {_IMXRT_GPIO8_0_15_BASE, _IMXRT_GPIO8_16_31_BASE},
|
||||
{_IMXRT_GPIO9_0_15_BASE, _IMXRT_GPIO9_16_31_BASE},
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_FAMILY_IMXRT117x)
|
||||
const lh_t port_to_irq[13] = {
|
||||
{_IMXRT_GPIO1_0_15_BASE, _IMXRT_GPIO1_16_31_BASE},
|
||||
{_IMXRT_GPIO2_0_15_BASE, _IMXRT_GPIO2_16_31_BASE},
|
||||
{_IMXRT_GPIO3_0_15_BASE, _IMXRT_GPIO3_16_31_BASE},
|
||||
{_IMXRT_GPIO4_0_15_BASE, _IMXRT_GPIO4_16_31_BASE},
|
||||
{_IMXRT_GPIO5_0_15_BASE, _IMXRT_GPIO5_16_31_BASE},
|
||||
{_IMXRT_GPIO6_0_15_BASE, _IMXRT_GPIO6_16_31_BASE},
|
||||
{0, 0}, // GPIO7 Not on CM7
|
||||
{0, 0}, // GPIO8 Not on CM7
|
||||
{0, 0}, // GPIO9 Not on CM7
|
||||
{0, 0}, // GPIO10 Not on CM7
|
||||
{0, 0}, // GPIO11 Not on CM7
|
||||
{0, 0}, // GPIO12 Not on CM7
|
||||
{_IMXRT_GPIO13_BASE, _IMXRT_GPIO13_BASE},
|
||||
};
|
||||
#endif
|
||||
|
||||
static int imxrt_pin_irq(gpio_pinset_t pinset)
|
||||
{
|
||||
volatile int irq = -1;
|
||||
volatile int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
volatile int pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
|
||||
lh_t irqlh = port_to_irq[port];
|
||||
|
||||
if (irqlh.low != 0 && irqlh.hi != 0) {
|
||||
irq = (pin < 16) ? irqlh.low : irqlh.hi;
|
||||
irq += pin % 16;
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: imxrt_pin_irqattach
|
||||
@@ -75,15 +112,16 @@ const lh_t port_to_irq[9] = {
|
||||
|
||||
static int imxrt_pin_irqattach(gpio_pinset_t pinset, xcpt_t func, void *arg)
|
||||
{
|
||||
volatile int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
volatile int pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
volatile int irq;
|
||||
lh_t irqlh = port_to_irq[port];
|
||||
irq = (pin < 16) ? irqlh.low : irqlh.hi;
|
||||
irq += pin % 16;
|
||||
irq_attach(irq, func, arg);
|
||||
up_enable_irq(irq);
|
||||
return 0;
|
||||
int rv = -EINVAL;
|
||||
int irq = imxrt_pin_irq(pinset);
|
||||
|
||||
if (irq != -1) {
|
||||
rv = OK;
|
||||
irq_attach(irq, func, arg);
|
||||
up_enable_irq(irq);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -109,28 +147,31 @@ int imxrt_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
|
||||
bool event, xcpt_t func, void *arg)
|
||||
{
|
||||
int ret = -ENOSYS;
|
||||
int irq = imxrt_pin_irq(pinset);
|
||||
|
||||
if (func == NULL) {
|
||||
imxrt_gpioirq_disable(pinset);
|
||||
pinset &= ~GPIO_INTCFG_MASK;
|
||||
ret = imxrt_config_gpio(pinset);
|
||||
if (irq != -1) {
|
||||
if (func == NULL) {
|
||||
imxrt_gpioirq_disable(irq);
|
||||
pinset &= ~GPIO_INTCFG_MASK;
|
||||
ret = imxrt_config_gpio(pinset);
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
pinset &= ~GPIO_INTCFG_MASK;
|
||||
pinset &= ~GPIO_INTCFG_MASK;
|
||||
|
||||
if (risingedge & fallingedge) {
|
||||
pinset |= GPIO_INTBOTH_EDGES;
|
||||
if (risingedge & fallingedge) {
|
||||
pinset |= GPIO_INTBOTH_EDGES;
|
||||
|
||||
} else if (risingedge) {
|
||||
pinset |= GPIO_INT_RISINGEDGE;
|
||||
} else if (risingedge) {
|
||||
pinset |= GPIO_INT_RISINGEDGE;
|
||||
|
||||
} else if (fallingedge) {
|
||||
pinset |= GPIO_INT_FALLINGEDGE;
|
||||
} else if (fallingedge) {
|
||||
pinset |= GPIO_INT_FALLINGEDGE;
|
||||
}
|
||||
|
||||
imxrt_gpioirq_configure(pinset);
|
||||
ret = imxrt_pin_irqattach(pinset, func, arg);
|
||||
}
|
||||
|
||||
imxrt_gpioirq_configure(pinset);
|
||||
ret = imxrt_pin_irqattach(pinset, func, arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2023 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,521 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2023 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>
|
||||
#include <arm_internal.h>
|
||||
#include <chip.h>
|
||||
#include "imxrt_gpio.h"
|
||||
|
||||
static const px4_spi_bus_t *_spi_bus1;
|
||||
static const px4_spi_bus_t *_spi_bus2;
|
||||
static const px4_spi_bus_t *_spi_bus3;
|
||||
static const px4_spi_bus_t *_spi_bus4;
|
||||
static const px4_spi_bus_t *_spi_bus5;
|
||||
static const px4_spi_bus_t *_spi_bus6;
|
||||
|
||||
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 imxrt_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 1: _spi_bus1 = &px4_spi_buses[i]; break;
|
||||
|
||||
case 2: _spi_bus2 = &px4_spi_buses[i]; break;
|
||||
|
||||
case 3: _spi_bus3 = &px4_spi_buses[i]; break;
|
||||
|
||||
case 4: _spi_bus4 = &px4_spi_buses[i]; break;
|
||||
|
||||
case 5: _spi_bus5 = &px4_spi_buses[i]; break;
|
||||
|
||||
case 6: _spi_bus6 = &px4_spi_buses[i]; break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IMXRT_LPSPI1
|
||||
ASSERT(_spi_bus1);
|
||||
|
||||
if (board_has_bus(BOARD_SPI_BUS, 1)) {
|
||||
spi_bus_configgpio_cs(_spi_bus1);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IMXRT_LPSPI1
|
||||
|
||||
|
||||
#if defined(CONFIG_IMXRT_LPSPI2)
|
||||
ASSERT(_spi_bus2);
|
||||
|
||||
if (board_has_bus(BOARD_SPI_BUS, 2)) {
|
||||
spi_bus_configgpio_cs(_spi_bus2);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IMXRT_LPSPI2
|
||||
|
||||
#ifdef CONFIG_IMXRT_LPSPI3
|
||||
ASSERT(_spi_bus3);
|
||||
|
||||
if (board_has_bus(BOARD_SPI_BUS, 3)) {
|
||||
spi_bus_configgpio_cs(_spi_bus3);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IMXRT_LPSPI3
|
||||
|
||||
#ifdef CONFIG_IMXRT_LPSPI4
|
||||
ASSERT(_spi_bus4);
|
||||
|
||||
if (board_has_bus(BOARD_SPI_BUS, 4)) {
|
||||
spi_bus_configgpio_cs(_spi_bus4);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IMXRT_LPSPI4
|
||||
|
||||
|
||||
#ifdef CONFIG_IMXRT_LPSPI5
|
||||
ASSERT(_spi_bus5);
|
||||
|
||||
if (board_has_bus(BOARD_SPI_BUS, 5)) {
|
||||
spi_bus_configgpio_cs(_spi_bus5);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IMXRT_LPSPI5
|
||||
|
||||
|
||||
#ifdef CONFIG_IMXRT_LPSPI6
|
||||
ASSERT(_spi_bus6);
|
||||
|
||||
if (board_has_bus(BOARD_SPI_BUS, 6)) {
|
||||
spi_bus_configgpio_cs(_spi_bus6);
|
||||
}
|
||||
|
||||
#endif // CONFIG_IMXRT_LPSPI6
|
||||
}
|
||||
|
||||
static inline void imxrt_lpspixselect(const px4_spi_bus_t *bus, struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
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
|
||||
imxrt_gpio_write(bus->devices[i].cs_gpio, !selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
* Name: imxrt_lpspi1select and imxrt_lpspi1select
|
||||
*
|
||||
* Description:
|
||||
* Called by imxrt spi driver on bus 1.
|
||||
*
|
||||
************************************************************************************/
|
||||
#ifdef CONFIG_IMXRT_LPSPI1
|
||||
|
||||
__EXPORT void imxrt_lpspi1select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
imxrt_lpspixselect(_spi_bus1, dev, devid, selected);
|
||||
}
|
||||
|
||||
__EXPORT uint8_t imxrt_lpspi1status(FAR struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return SPI_STATUS_PRESENT;
|
||||
}
|
||||
#endif // CONFIG_IMXRT_LPSPI1
|
||||
|
||||
/************************************************************************************
|
||||
* Name: imxrt_lpspi2select and imxrt_lpspi2select
|
||||
*
|
||||
* Description:
|
||||
* Called by imxrt spi driver on bus 2.
|
||||
*
|
||||
************************************************************************************/
|
||||
#if defined(CONFIG_IMXRT_LPSPI2)
|
||||
__EXPORT void imxrt_lpspi2select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
imxrt_lpspixselect(_spi_bus2, dev, devid, selected);
|
||||
}
|
||||
|
||||
__EXPORT uint8_t imxrt_lpspi2status(FAR struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return SPI_STATUS_PRESENT;
|
||||
}
|
||||
#endif // CONFIG_IMXRT_LPSPI2
|
||||
|
||||
/************************************************************************************
|
||||
* Name: imxrt_lpspi3select and imxrt_lpspi3select
|
||||
*
|
||||
* Description:
|
||||
* Called by imxrt spi driver on bus 3.
|
||||
*
|
||||
************************************************************************************/
|
||||
#if defined(CONFIG_IMXRT_LPSPI3)
|
||||
__EXPORT void imxrt_lpspi3select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
imxrt_lpspixselect(_spi_bus3, dev, devid, selected);
|
||||
}
|
||||
|
||||
__EXPORT uint8_t imxrt_lpspi3status(FAR struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return SPI_STATUS_PRESENT;
|
||||
}
|
||||
#endif // CONFIG_IMXRT_LPSPI3
|
||||
|
||||
/************************************************************************************
|
||||
* Name: imxrt_lpspi4select and imxrt_lpspi4select
|
||||
*
|
||||
* Description:
|
||||
* Called by imxrt spi driver on bus 4.
|
||||
*
|
||||
************************************************************************************/
|
||||
#ifdef CONFIG_IMXRT_LPSPI4
|
||||
|
||||
__EXPORT void imxrt_lpspi4select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
imxrt_lpspixselect(_spi_bus4, dev, devid, selected);
|
||||
}
|
||||
|
||||
__EXPORT uint8_t imxrt_lpspi4status(FAR struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return SPI_STATUS_PRESENT;
|
||||
}
|
||||
#endif // CONFIG_IMXRT_LPSPI4
|
||||
|
||||
/************************************************************************************
|
||||
* Name: imxrt_lpspi5select and imxrt_lpspi5select
|
||||
*
|
||||
* Description:
|
||||
* Called by imxrt spi driver on bus 5.
|
||||
*
|
||||
************************************************************************************/
|
||||
#ifdef CONFIG_IMXRT_LPSPI5
|
||||
|
||||
__EXPORT void imxrt_lpspi5select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
imxrt_lpspixselect(_spi_bus5, dev, devid, selected);
|
||||
}
|
||||
|
||||
__EXPORT uint8_t imxrt_lpspi5status(FAR struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return SPI_STATUS_PRESENT;
|
||||
}
|
||||
#endif // CONFIG_IMXRT_LPSPI5
|
||||
|
||||
/************************************************************************************
|
||||
* Name: imxrt_lpspi6select and imxrt_lpspi6select
|
||||
*
|
||||
* Description:
|
||||
* Called by imxrt spi driver on bus 6.
|
||||
*
|
||||
************************************************************************************/
|
||||
#ifdef CONFIG_IMXRT_LPSPI6
|
||||
|
||||
__EXPORT void imxrt_lpspi6select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
|
||||
{
|
||||
imxrt_lpspixselect(_spi_bus6, dev, devid, selected);
|
||||
}
|
||||
|
||||
__EXPORT uint8_t imxrt_lpspi6status(FAR struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return SPI_STATUS_PRESENT;
|
||||
}
|
||||
#endif // CONFIG_IMXRT_LPSPI6
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
__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_IMXRT_LPSPI1)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 1) {
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI1_SCK));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI1_MISO));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI1_MOSI));
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI2)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 2) {
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI2_SCK));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI2_MISO));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI2_MOSI));
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI3)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 3) {
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI3_SCK));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI3_MISO));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI3_MOSI));
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI4)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 4) {
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI4_SCK));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI4_MISO));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI4_MOSI));
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI5)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 5) {
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI5_SCK));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI5_MISO));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI5_MOSI));
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI6)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 6) {
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI6_SCK));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI6_MISO));
|
||||
px4_arch_configgpio(_PIN_OFF(GPIO_LPSPI6_MOSI));
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
if (px4_spi_buses[bus].devices[i].drdy_gpio != 0) {
|
||||
px4_arch_configgpio(px4_spi_buses[bus].devices[i].drdy_gpio);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IMXRT_LPSPI1)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 1) {
|
||||
px4_arch_configgpio(GPIO_LPSPI1_SCK);
|
||||
px4_arch_configgpio(GPIO_LPSPI1_MISO);
|
||||
px4_arch_configgpio(GPIO_LPSPI1_MOSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI2)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 2) {
|
||||
px4_arch_configgpio(GPIO_LPSPI2_SCK);
|
||||
px4_arch_configgpio(GPIO_LPSPI2_MISO);
|
||||
px4_arch_configgpio(GPIO_LPSPI2_MOSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI3)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 3) {
|
||||
px4_arch_configgpio(GPIO_LPSPI3_SCK);
|
||||
px4_arch_configgpio(GPIO_LPSPI3_MISO);
|
||||
px4_arch_configgpio(GPIO_LPSPI3_MOSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI4)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 4) {
|
||||
px4_arch_configgpio(GPIO_LPSPI4_SCK);
|
||||
px4_arch_configgpio(GPIO_LPSPI4_MISO);
|
||||
px4_arch_configgpio(GPIO_LPSPI4_MOSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI5)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 5) {
|
||||
px4_arch_configgpio(GPIO_LPSPI5_SCK);
|
||||
px4_arch_configgpio(GPIO_LPSPI5_MISO);
|
||||
px4_arch_configgpio(GPIO_LPSPI5_MOSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(CONFIG_IMXRT_LPSPI6)
|
||||
|
||||
if (px4_spi_buses[bus].bus == 6) {
|
||||
px4_arch_configgpio(GPIO_LPSPI6_SCK);
|
||||
px4_arch_configgpio(GPIO_LPSPI6_MISO);
|
||||
px4_arch_configgpio(GPIO_LPSPI6_MOSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -72,12 +72,20 @@
|
||||
# define TONE_ALARM_CLOCK_ALL() imxrt_clockall_gpt_bus() /* The Clock Gating macro for this GPT */
|
||||
#elif TONE_ALARM_TIMER == 2
|
||||
# define TONE_ALARM_CLOCK_ALL() imxrt_clockall_gpt2_bus() /* The Clock Gating macro for this GPT */
|
||||
#elif TONE_ALARM_TIMER == 3
|
||||
# define TONE_ALARM_CLOCK_ALL() imxrt_clockall_gpt3_bus() /* The Clock Gating macro for this GPT */
|
||||
#elif TONE_ALARM_TIMER == 4
|
||||
# define TONE_ALARM_CLOCK_ALL() imxrt_clockall_gpt4_bus() /* The Clock Gating macro for this GPT */
|
||||
#endif
|
||||
|
||||
#if TONE_ALARM_TIMER == 1 && defined(CONFIG_IMXRT_GPT1)
|
||||
# error must not set CONFIG_IMXRT_GPT1=y and TONE_ALARM_TIMER=1
|
||||
#elif TONE_ALARM_TIMER == 2 && defined(CONFIG_IMXRT_GPT2)
|
||||
# error must not set CONFIG_IMXRT_GPT2=y and TONE_ALARM_TIMER=2
|
||||
#elif TONE_ALARM_TIMER == 3 && defined(CONFIG_IMXRT_GPT3)
|
||||
# error must not set CONFIG_IMXRT_GPT3=y and TONE_ALARM_TIMER=3
|
||||
#elif TONE_ALARM_TIMER == 4 && defined(CONFIG_IMXRT_GPT4)
|
||||
# error must not set CONFIG_IMXRT_GPT4=y and TONE_ALARM_TIMER=4
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -81,25 +81,8 @@ void board_get_uuid(uuid_byte_t uuid_bytes)
|
||||
|
||||
void board_get_uuid32(uuid_uint32_t uuid_words)
|
||||
{
|
||||
/* IMXRT_OCOTP_CFG1:0x420[10:0], IMXRT_OCOTP_CFG0:0x410[31:0] LOT_NO_ENC[42:0](SJC_CHALL/UNIQUE_ID[42:0])
|
||||
* 43 bits FSL-wide unique,encoded LOT ID STD II/SJC CHALLENGE/ Unique ID
|
||||
* 0x420[15:11] WAFER_NO[4:0]( SJC_CHALL[47:43] /UNIQUE_ID[47:43])
|
||||
* 5 bits The wafer number of the wafer on which the device was fabricated/SJC CHALLENGE/ Unique ID
|
||||
* 0x420[23:16] DIE-YCORDINATE[7:0]( SJC_CHALL[55:48] /UNIQUE_ID[55:48])
|
||||
* 8 bits The Y-coordinate of the die location on the wafer/SJC CHALLENGE/Unique ID
|
||||
* 0x420[31:24] DIE-XCORDINATE[7:0]( SJC_CHALL[63:56] /UNIQUE_ID[63:56] )
|
||||
* 8 bits The X-coordinate of the die location on the wafer/SJC CHALLENGE/Unique ID
|
||||
*
|
||||
* word [0] word[1]
|
||||
* SJC_CHALL[63:32] [31:00]
|
||||
*/
|
||||
#ifdef CONFIG_ARCH_FAMILY_IMXRT117x
|
||||
uuid_words[0] = getreg32(IMXRT_OCOTP_FUSE(0x10));
|
||||
uuid_words[1] = getreg32(IMXRT_OCOTP_FUSE(0x11));
|
||||
#else
|
||||
uuid_words[0] = getreg32(IMXRT_OCOTP_CFG1);
|
||||
uuid_words[1] = getreg32(IMXRT_OCOTP_CFG0);
|
||||
#endif
|
||||
uuid_words[0] = getreg32(IMXRT_OCOTP_UNIQUE_ID_MSB);
|
||||
uuid_words[1] = getreg32(IMXRT_OCOTP_UNIQUE_ID_LSB);
|
||||
}
|
||||
|
||||
int board_get_uuid32_formated(char *format_buffer, int size,
|
||||
|
||||
@@ -39,6 +39,10 @@ add_subdirectory(../imxrt/board_reset board_reset)
|
||||
#add_subdirectory(../imxrt/dshot dshot)
|
||||
add_subdirectory(../imxrt/hrt hrt)
|
||||
add_subdirectory(../imxrt/led_pwm led_pwm)
|
||||
add_subdirectory(io_pins)
|
||||
#add_subdirectory(../imxrt/tone_alarm tone_alarm)
|
||||
add_subdirectory(../imxrt/io_pins io_pins)
|
||||
add_subdirectory(../imxrt/tone_alarm tone_alarm)
|
||||
add_subdirectory(../imxrt/version version)
|
||||
add_subdirectory(../imxrt/spi spi)
|
||||
|
||||
add_subdirectory(px4io_serial)
|
||||
add_subdirectory(ssarc)
|
||||
|
||||
@@ -37,11 +37,7 @@
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define PX4_SOC_ARCH_ID PX4_SOC_ARCH_ID_NXPIMXRT1176
|
||||
|
||||
#// Fixme: using ??
|
||||
#define PX4_BBSRAM_SIZE 2048
|
||||
#define PX4_BBSRAM_GETDESC_IOCTL 0
|
||||
#define PX4_NUMBER_I2C_BUSES 2 //FIXME
|
||||
#define PX4_NUMBER_I2C_BUSES 6
|
||||
|
||||
#define GPIO_OUTPUT_SET GPIO_OUTPUT_ONE
|
||||
#define GPIO_OUTPUT_CLEAR GPIO_OUTPUT_ZERO
|
||||
@@ -87,6 +83,19 @@ __BEGIN_DECLS
|
||||
|
||||
#define PX4_BUS_OFFSET 0 /* imxrt buses are 1 based no adjustment needed */
|
||||
|
||||
#define px4_savepanic(fileno, context, length) ssarc_dump_savepanic(fileno, context, length)
|
||||
|
||||
#if defined(CONFIG_BOARD_CRASHDUMP)
|
||||
# define HAS_SSARC 1
|
||||
# define PX4_HF_GETDESC_IOCTL SSARC_DUMP_GETDESC_IOCTL
|
||||
# define PX4_SSARC_DUMP_BASE IMXRT_SSARC_HP_BASE
|
||||
# define PX4_SSARC_DUMP_SIZE 9216
|
||||
# define PX4_SSARC_BLOCK_SIZE 16
|
||||
# define PX4_SSARC_BLOCK_DATA 9
|
||||
# define PX4_SSARC_HEADER_SIZE 27
|
||||
#endif
|
||||
|
||||
|
||||
#define px4_spibus_initialize(bus_num_1based) imxrt_lpspibus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based))
|
||||
|
||||
#define px4_i2cbus_initialize(bus_num_1based) imxrt_i2cbus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based))
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 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 "../../../imxrt/include/px4_arch/px4io_serial.h"
|
||||
@@ -0,0 +1,125 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2022 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SSARC_DUMP_GETDESC_IOCTL _DIOC(0x0000) /* Returns a progmem_s */
|
||||
#define SSARC_DUMP_CLEAR_IOCTL _DIOC(0x0010) /* Erases flash sector */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct ssarc_s {
|
||||
struct timespec lastwrite;
|
||||
int fileno;
|
||||
int len;
|
||||
int flags;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
# define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Function: ssarc_dump_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the Progmem dump driver
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - the path to instantiate the files.
|
||||
* sizes - Pointer to a any array of file sizes to create
|
||||
* the last entry should be 0
|
||||
* A size of -1 will use all the remaining spaces
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of files created on success; Negated errno on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ssarc_dump_initialize(char *devpath, int *sizes);
|
||||
|
||||
/****************************************************************************
|
||||
* Function: ssarc_dump_savepanic
|
||||
*
|
||||
* Description:
|
||||
* Saves the panic context in a previously allocated BBSRAM file
|
||||
*
|
||||
* Parameters:
|
||||
* fileno - the value returned by the ioctl SSARC_DUMP_GETDESC_IOCTL
|
||||
* context - Pointer to a any array of bytes to save
|
||||
* length - The length of the data pointed to byt context
|
||||
*
|
||||
* Returned Value:
|
||||
* Length saved or negated errno.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ssarc_dump_savepanic(int fileno, uint8_t *context, int length);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __ASSEMBLY__ */
|
||||
@@ -1,161 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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 <px4_platform_common/px4_config.h>
|
||||
#include <systemlib/px4_macros.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "imxrt_irq.h"
|
||||
#include "hardware/imxrt_gpio.h"
|
||||
|
||||
typedef struct {
|
||||
int low;
|
||||
int hi;
|
||||
} lh_t;
|
||||
|
||||
|
||||
const lh_t port_to_irq[13] = {
|
||||
{_IMXRT_GPIO1_0_15_BASE, _IMXRT_GPIO1_16_31_BASE},
|
||||
{_IMXRT_GPIO2_0_15_BASE, _IMXRT_GPIO2_16_31_BASE},
|
||||
{_IMXRT_GPIO3_0_15_BASE, _IMXRT_GPIO3_16_31_BASE},
|
||||
{_IMXRT_GPIO4_0_15_BASE, _IMXRT_GPIO4_16_31_BASE},
|
||||
{_IMXRT_GPIO5_0_15_BASE, _IMXRT_GPIO5_16_31_BASE},
|
||||
{_IMXRT_GPIO6_0_15_BASE, _IMXRT_GPIO6_16_31_BASE},
|
||||
{0, 0}, // GPIO7 Not on CM7
|
||||
{0, 0}, // GPIO8 Not on CM7
|
||||
{0, 0}, // GPIO9 Not on CM7
|
||||
{0, 0}, // GPIO10 Not on CM7
|
||||
{0, 0}, // GPIO11 Not on CM7
|
||||
{0, 0}, // GPIO12 Not on CM7
|
||||
{_IMXRT_GPIO13_BASE, _IMXRT_GPIO13_BASE},
|
||||
};
|
||||
|
||||
static bool imxrt_pin_irq_valid(gpio_pinset_t pinset)
|
||||
{
|
||||
int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
lh_t irqlh = port_to_irq[port];
|
||||
return (irqlh.low != 0 && irqlh.hi != 0);
|
||||
}
|
||||
/****************************************************************************
|
||||
* Name: imxrt_pin_irqattach
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears GPIO based event and interrupt triggers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: gpio pin configuration
|
||||
* - rising/falling edge: enables
|
||||
* - 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int imxrt_pin_irqattach(gpio_pinset_t pinset, xcpt_t func, void *arg)
|
||||
{
|
||||
int rv = -EINVAL;
|
||||
volatile int port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
|
||||
volatile int pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
|
||||
volatile int irq;
|
||||
lh_t irqlh = port_to_irq[port];
|
||||
|
||||
if (irqlh.low != 0 && irqlh.hi != 0) {
|
||||
rv = OK;
|
||||
irq = (pin < 16) ? irqlh.low : irqlh.hi;
|
||||
irq += pin % 16;
|
||||
irq_attach(irq, func, arg);
|
||||
up_enable_irq(irq);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: imxrt_gpiosetevent
|
||||
*
|
||||
* Description:
|
||||
* Sets/clears GPIO based event and interrupt triggers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* - pinset: gpio pin configuration
|
||||
* - rising/falling edge: enables
|
||||
* - 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
#if defined(CONFIG_IMXRT_GPIO_IRQ)
|
||||
int imxrt_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
|
||||
bool event, xcpt_t func, void *arg)
|
||||
{
|
||||
int ret = -ENOSYS;
|
||||
|
||||
if (imxrt_pin_irq_valid(pinset)) {
|
||||
if (func == NULL) {
|
||||
imxrt_gpioirq_disable(pinset);
|
||||
pinset &= ~GPIO_INTCFG_MASK;
|
||||
ret = imxrt_config_gpio(pinset);
|
||||
|
||||
} else {
|
||||
|
||||
pinset &= ~GPIO_INTCFG_MASK;
|
||||
|
||||
if (risingedge & fallingedge) {
|
||||
pinset |= GPIO_INTBOTH_EDGES;
|
||||
|
||||
} else if (risingedge) {
|
||||
pinset |= GPIO_INT_RISINGEDGE;
|
||||
|
||||
} else if (fallingedge) {
|
||||
pinset |= GPIO_INT_FALLINGEDGE;
|
||||
}
|
||||
|
||||
imxrt_gpioirq_configure(pinset);
|
||||
ret = imxrt_pin_irqattach(pinset, func, arg);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_IMXRT_GPIO_IRQ */
|
||||
+2
-10
@@ -31,14 +31,6 @@
|
||||
#
|
||||
############################################################################
|
||||
|
||||
add_compile_options(
|
||||
-Wno-unused-function
|
||||
) # TODO: remove once io_timer_handlerX are used
|
||||
|
||||
px4_add_library(arch_io_pins
|
||||
../../imxrt/io_pins/io_timer.c
|
||||
../../imxrt/io_pins/pwm_servo.c
|
||||
../../imxrt/io_pins/pwm_trigger.c
|
||||
../../imxrt/io_pins/input_capture.c
|
||||
imxrt_pinirq.c
|
||||
px4_add_library(arch_px4io_serial
|
||||
px4io_serial.cpp
|
||||
)
|
||||
@@ -0,0 +1,516 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 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 px4io_serial.cpp
|
||||
*
|
||||
* Serial interface for PX4IO on RT1170
|
||||
*/
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include <px4_arch/px4io_serial.h>
|
||||
#include <nuttx/cache.h>
|
||||
#include "hardware/imxrt_lpuart.h"
|
||||
#include "hardware/imxrt_dmamux.h"
|
||||
#include "imxrt_lowputc.h"
|
||||
#include "imxrt_edma.h"
|
||||
#include "imxrt_periphclks.h"
|
||||
|
||||
|
||||
/* serial register accessors */
|
||||
#define REG(_x) (*(volatile uint32_t *)(PX4IO_SERIAL_BASE + (_x)))
|
||||
#define rBAUD REG(IMXRT_LPUART_BAUD_OFFSET)
|
||||
#define rSTAT_ERR_FLAGS_MASK (LPUART_STAT_PF | LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_OR)
|
||||
#define rSTAT REG(IMXRT_LPUART_STAT_OFFSET)
|
||||
#define rCTRL REG(IMXRT_LPUART_CTRL_OFFSET)
|
||||
#define rDATA REG(IMXRT_LPUART_DATA_OFFSET)
|
||||
|
||||
#define DMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1)
|
||||
#define DMA_ALIGN_UP(n) (((n) + DMA_BUFFER_MASK) & ~DMA_BUFFER_MASK)
|
||||
|
||||
uint8_t ArchPX4IOSerial::_io_buffer_storage[DMA_ALIGN_UP(sizeof(IOPacket))];
|
||||
|
||||
ArchPX4IOSerial::ArchPX4IOSerial() :
|
||||
_tx_dma(nullptr),
|
||||
_rx_dma(nullptr),
|
||||
_current_packet(nullptr),
|
||||
_rx_dma_result(_dma_status_inactive),
|
||||
_completion_semaphore(SEM_INITIALIZER(0)),
|
||||
_pc_dmaerrs(perf_alloc(PC_COUNT, MODULE_NAME": DMA errors"))
|
||||
{
|
||||
}
|
||||
|
||||
ArchPX4IOSerial::~ArchPX4IOSerial()
|
||||
{
|
||||
if (_tx_dma != nullptr) {
|
||||
imxrt_dmach_stop(_tx_dma);
|
||||
imxrt_dmach_free(_tx_dma);
|
||||
}
|
||||
|
||||
if (_rx_dma != nullptr) {
|
||||
imxrt_dmach_stop(_rx_dma);
|
||||
imxrt_dmach_free(_rx_dma);
|
||||
}
|
||||
|
||||
/* reset the UART */
|
||||
rCTRL = 0;
|
||||
|
||||
/* detach our interrupt handler */
|
||||
up_disable_irq(PX4IO_SERIAL_VECTOR);
|
||||
irq_detach(PX4IO_SERIAL_VECTOR);
|
||||
|
||||
/* restore the GPIOs */
|
||||
px4_arch_unconfiggpio(PX4IO_SERIAL_TX_GPIO);
|
||||
px4_arch_unconfiggpio(PX4IO_SERIAL_RX_GPIO);
|
||||
|
||||
/* Disable clock for the USART peripheral */
|
||||
PX4IO_SERIAL_CLOCK_OFF();
|
||||
|
||||
/* and kill our semaphores */
|
||||
px4_sem_destroy(&_completion_semaphore);
|
||||
|
||||
perf_free(_pc_dmaerrs);
|
||||
}
|
||||
|
||||
int
|
||||
ArchPX4IOSerial::init()
|
||||
{
|
||||
/* initialize base implementation */
|
||||
int r = PX4IO_serial::init((IOPacket *)&_io_buffer_storage[0]);
|
||||
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* allocate DMA */
|
||||
_tx_dma = imxrt_dmach_alloc(PX4IO_SERIAL_TX_DMAMAP | DMAMUX_CHCFG_ENBL, 0);
|
||||
_rx_dma = imxrt_dmach_alloc(PX4IO_SERIAL_RX_DMAMAP | DMAMUX_CHCFG_ENBL, 0);
|
||||
|
||||
if ((_tx_dma == nullptr) || (_rx_dma == nullptr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct uart_config_s config = {
|
||||
.baud = PX4IO_SERIAL_BITRATE,
|
||||
.parity = 0, /* 0=none, 1=odd, 2=even */
|
||||
.bits = 8, /* Number of bits (5-9) */
|
||||
.stopbits2 = false, /* true: Configure with 2 stop bits instead of 1 */
|
||||
.userts = false, /* True: Assert RTS when there are data to be sent */
|
||||
.invrts = false, /* True: Invert sense of RTS pin (true=active high) */
|
||||
.usects = false, /* True: Condition transmission on CTS asserted */
|
||||
.users485 = false, /* True: Assert RTS while transmission progresses */
|
||||
};
|
||||
|
||||
|
||||
int rv = imxrt_lpuart_configure(PX4IO_SERIAL_BASE, &config);
|
||||
|
||||
if (rv == OK) {
|
||||
/* configure pins for serial use */
|
||||
px4_arch_configgpio(PX4IO_SERIAL_TX_GPIO);
|
||||
px4_arch_configgpio(PX4IO_SERIAL_RX_GPIO);
|
||||
|
||||
/* attach serial interrupt handler */
|
||||
irq_attach(PX4IO_SERIAL_VECTOR, _interrupt, this);
|
||||
up_enable_irq(PX4IO_SERIAL_VECTOR);
|
||||
|
||||
/* Idel after Stop, , enable error and line idle interrupts */
|
||||
uint32_t regval = rCTRL;
|
||||
regval &= ~(LPUART_CTRL_IDLECFG_MASK | LPUART_CTRL_ILT);
|
||||
regval |= LPUART_CTRL_ILT | LPUART_CTRL_IDLECFG_1 | LPUART_CTRL_ILIE |
|
||||
LPUART_CTRL_RE | LPUART_CTRL_TE;
|
||||
rCTRL = regval;
|
||||
|
||||
/* create semaphores */
|
||||
px4_sem_init(&_completion_semaphore, 0, 0);
|
||||
|
||||
/* _completion_semaphore use case is a signal */
|
||||
|
||||
px4_sem_setprotocol(&_completion_semaphore, SEM_PRIO_NONE);
|
||||
|
||||
/* XXX this could try talking to IO */
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
ArchPX4IOSerial::ioctl(unsigned operation, unsigned &arg)
|
||||
{
|
||||
switch (operation) {
|
||||
|
||||
case 1: /* XXX magic number - test operation */
|
||||
switch (arg) {
|
||||
case 0:
|
||||
syslog(LOG_INFO, "test 0\n");
|
||||
|
||||
/* kill DMA, this is a PIO test */
|
||||
imxrt_dmach_stop(_tx_dma);
|
||||
imxrt_dmach_stop(_rx_dma);
|
||||
|
||||
/* disable UART DMA */
|
||||
|
||||
rBAUD &= ~(LPUART_BAUD_RDMAE | LPUART_BAUD_TDMAE);
|
||||
|
||||
for (;;) {
|
||||
while (!(rSTAT & LPUART_STAT_TDRE))
|
||||
;
|
||||
|
||||
rDATA = 0x55;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 1: {
|
||||
unsigned fails = 0;
|
||||
|
||||
for (unsigned count = 0;; count++) {
|
||||
uint16_t value = count & 0xffff;
|
||||
|
||||
if (write((PX4IO_PAGE_TEST << 8) | PX4IO_P_TEST_LED, &value, 1) != 0) {
|
||||
fails++;
|
||||
}
|
||||
|
||||
if (count >= 5000) {
|
||||
syslog(LOG_INFO, "==== test 1 : %u failures ====\n", fails);
|
||||
perf_print_counter(_pc_txns);
|
||||
perf_print_counter(_pc_retries);
|
||||
perf_print_counter(_pc_timeouts);
|
||||
perf_print_counter(_pc_crcerrs);
|
||||
perf_print_counter(_pc_dmaerrs);
|
||||
perf_print_counter(_pc_protoerrs);
|
||||
perf_print_counter(_pc_uerrs);
|
||||
perf_print_counter(_pc_idle);
|
||||
perf_print_counter(_pc_badidle);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case 2:
|
||||
syslog(LOG_INFO, "test 2\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ArchPX4IOSerial::_bus_exchange(IOPacket *_packet)
|
||||
{
|
||||
// to be paranoid ensure all previous DMA transfers are cleared
|
||||
_abort_dma();
|
||||
|
||||
_current_packet = _packet;
|
||||
|
||||
/* clear data that may be in the RDR and clear overrun error: */
|
||||
while (rSTAT & LPUART_STAT_RDRF) {
|
||||
(void)rDATA;
|
||||
}
|
||||
|
||||
rSTAT |= (rSTAT_ERR_FLAGS_MASK | LPUART_STAT_IDLE); /* clear the flags */
|
||||
|
||||
/* start RX DMA */
|
||||
perf_begin(_pc_txns);
|
||||
|
||||
/* DMA setup time ~3µs */
|
||||
_rx_dma_result = _dma_status_waiting;
|
||||
|
||||
struct imxrt_edma_xfrconfig_s rx_config;
|
||||
rx_config.saddr = PX4IO_SERIAL_BASE + IMXRT_LPUART_DATA_OFFSET;
|
||||
rx_config.daddr = reinterpret_cast<uint32_t>(_current_packet);
|
||||
rx_config.soff = 0;
|
||||
rx_config.doff = 1;
|
||||
rx_config.iter = sizeof(*_current_packet);
|
||||
rx_config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
|
||||
rx_config.ssize = EDMA_8BIT;
|
||||
rx_config.dsize = EDMA_8BIT;
|
||||
rx_config.nbytes = 1;
|
||||
#ifdef CONFIG_IMXRT_EDMA_ELINK
|
||||
rx_config.linkch = NULL;
|
||||
#endif
|
||||
imxrt_dmach_xfrsetup(_rx_dma, &rx_config);
|
||||
|
||||
/* Enable receive DMA for the UART */
|
||||
|
||||
rBAUD |= LPUART_BAUD_RDMAE;
|
||||
|
||||
imxrt_dmach_start(_rx_dma, _dma_callback, (void *)this);
|
||||
|
||||
/* Clean _current_packet, so DMA can see the data */
|
||||
up_clean_dcache((uintptr_t)_current_packet,
|
||||
(uintptr_t)_current_packet + DMA_ALIGN_UP(sizeof(IOPacket)));
|
||||
|
||||
/* start TX DMA - no callback if we also expect a reply */
|
||||
/* DMA setup time ~3µs */
|
||||
|
||||
struct imxrt_edma_xfrconfig_s tx_config;
|
||||
tx_config.saddr = reinterpret_cast<uint32_t>(_current_packet);
|
||||
tx_config.daddr = PX4IO_SERIAL_BASE + IMXRT_LPUART_DATA_OFFSET;
|
||||
tx_config.soff = 1;
|
||||
tx_config.doff = 0;
|
||||
tx_config.iter = sizeof(*_current_packet);
|
||||
tx_config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
|
||||
tx_config.ssize = EDMA_8BIT;
|
||||
tx_config.dsize = EDMA_8BIT;
|
||||
tx_config.nbytes = 1;
|
||||
#ifdef CONFIG_IMXRT_EDMA_ELINK
|
||||
tx_config.linkch = NULL;
|
||||
#endif
|
||||
imxrt_dmach_xfrsetup(_tx_dma, &tx_config);
|
||||
|
||||
|
||||
/* Enable transmit DMA for the UART */
|
||||
|
||||
rBAUD |= LPUART_BAUD_TDMAE;
|
||||
|
||||
imxrt_dmach_start(_tx_dma, nullptr, nullptr);
|
||||
|
||||
/* compute the deadline for a 10ms timeout */
|
||||
struct timespec abstime;
|
||||
clock_gettime(CLOCK_REALTIME, &abstime);
|
||||
abstime.tv_nsec += 10 * 1000 * 1000;
|
||||
|
||||
if (abstime.tv_nsec >= 1000 * 1000 * 1000) {
|
||||
abstime.tv_sec++;
|
||||
abstime.tv_nsec -= 1000 * 1000 * 1000;
|
||||
}
|
||||
|
||||
/* wait for the transaction to complete - 64 bytes @ 1.5Mbps ~426µs */
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
ret = sem_timedwait(&_completion_semaphore, &abstime);
|
||||
|
||||
if (ret == OK) {
|
||||
/* check for DMA errors */
|
||||
if (_rx_dma_result != OK) {
|
||||
// stream transfer error, ensure all DMA is also stopped before exiting early
|
||||
_abort_dma();
|
||||
perf_count(_pc_dmaerrs);
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* check packet CRC - corrupt packet errors mean IO receive CRC error */
|
||||
uint8_t crc = _current_packet->crc;
|
||||
_current_packet->crc = 0;
|
||||
|
||||
if ((crc != crc_packet(_current_packet)) || (PKT_CODE(*_current_packet) == PKT_CODE_CORRUPT)) {
|
||||
_abort_dma();
|
||||
perf_count(_pc_crcerrs);
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* successful txn (may still be reporting an error) */
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == ETIMEDOUT) {
|
||||
/* something has broken - clear out any partial DMA state and reconfigure */
|
||||
_abort_dma();
|
||||
perf_count(_pc_timeouts);
|
||||
perf_cancel(_pc_txns); /* don't count this as a transaction */
|
||||
break;
|
||||
}
|
||||
|
||||
/* we might? see this for EINTR */
|
||||
syslog(LOG_ERR, "unexpected ret %d/%d\n", ret, errno);
|
||||
}
|
||||
|
||||
/* reset DMA status */
|
||||
_rx_dma_result = _dma_status_inactive;
|
||||
|
||||
/* update counters */
|
||||
perf_end(_pc_txns);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ArchPX4IOSerial::_dma_callback(DMACH_HANDLE handle, void *arg, bool done, int result)
|
||||
{
|
||||
if (arg != nullptr) {
|
||||
ArchPX4IOSerial *ps = reinterpret_cast<ArchPX4IOSerial *>(arg);
|
||||
|
||||
ps->_do_rx_dma_callback(done, result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArchPX4IOSerial::_do_rx_dma_callback(bool done, int result)
|
||||
{
|
||||
/* on completion of a reply, wake the waiter */
|
||||
|
||||
if (done && _rx_dma_result == _dma_status_waiting) {
|
||||
|
||||
if (result != OK) {
|
||||
|
||||
/* check for packet overrun - this will occur after DMA completes */
|
||||
uint32_t sr = rSTAT;
|
||||
|
||||
if (sr & (LPUART_STAT_OR | LPUART_STAT_RDRF)) {
|
||||
while (rSTAT & LPUART_STAT_RDRF) {
|
||||
(void)rDATA;
|
||||
}
|
||||
|
||||
rSTAT = sr & (LPUART_STAT_OR);
|
||||
result = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* save RX status */
|
||||
_rx_dma_result = result;
|
||||
|
||||
/* disable UART DMA */
|
||||
|
||||
rBAUD &= ~(LPUART_BAUD_RDMAE | LPUART_BAUD_TDMAE);
|
||||
|
||||
/* complete now */
|
||||
px4_sem_post(&_completion_semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ArchPX4IOSerial::_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
if (arg != nullptr) {
|
||||
ArchPX4IOSerial *instance = reinterpret_cast<ArchPX4IOSerial *>(arg);
|
||||
|
||||
instance->_do_interrupt();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ArchPX4IOSerial::_do_interrupt()
|
||||
{
|
||||
uint32_t sr = rSTAT;
|
||||
|
||||
while (rSTAT & LPUART_STAT_RDRF) {
|
||||
(void)rDATA; /* read DATA register to clear RDRF */
|
||||
}
|
||||
|
||||
rSTAT |= sr & rSTAT_ERR_FLAGS_MASK; /* clear flags */
|
||||
|
||||
if (sr & (LPUART_STAT_OR | /* overrun error - packet was too big for DMA or DMA was too slow */
|
||||
LPUART_STAT_NF | /* noise error - we have lost a byte due to noise */
|
||||
LPUART_STAT_FE)) { /* framing error - start/stop bit lost or line break */
|
||||
|
||||
/*
|
||||
* If we are in the process of listening for something, these are all fatal;
|
||||
* abort the DMA with an error.
|
||||
*/
|
||||
if (_rx_dma_result == _dma_status_waiting) {
|
||||
_abort_dma();
|
||||
|
||||
perf_count(_pc_uerrs);
|
||||
/* complete DMA as though in error */
|
||||
_do_rx_dma_callback(true, -EIO);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX we might want to use FE / line break as an out-of-band handshake ... handle it here */
|
||||
|
||||
/* don't attempt to handle IDLE if it's set - things went bad */
|
||||
return;
|
||||
}
|
||||
|
||||
if (sr & LPUART_STAT_IDLE) {
|
||||
|
||||
rSTAT |= LPUART_STAT_IDLE; /* clear IDLE flag */
|
||||
|
||||
/* if there is DMA reception going on, this is a short packet */
|
||||
if (_rx_dma_result == _dma_status_waiting) {
|
||||
/* Invalidate _current_packet, so we get fresh data from RAM */
|
||||
up_invalidate_dcache((uintptr_t)_current_packet,
|
||||
(uintptr_t)_current_packet + DMA_ALIGN_UP(sizeof(IOPacket)));
|
||||
|
||||
/* verify that the received packet is complete */
|
||||
size_t length = sizeof(*_current_packet) - imxrt_dmach_getcount(_rx_dma);
|
||||
|
||||
if ((length < 1) || (length < PKT_SIZE(*_current_packet))) {
|
||||
perf_count(_pc_badidle);
|
||||
|
||||
/* stop the receive DMA */
|
||||
imxrt_dmach_stop(_rx_dma);
|
||||
|
||||
/* complete the short reception */
|
||||
_do_rx_dma_callback(true, -EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
perf_count(_pc_idle);
|
||||
|
||||
/* complete the short reception */
|
||||
|
||||
_do_rx_dma_callback(true, _dma_status_done);
|
||||
|
||||
/* stop the receive DMA */
|
||||
imxrt_dmach_stop(_rx_dma);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArchPX4IOSerial::_abort_dma()
|
||||
{
|
||||
/* stop DMA */
|
||||
imxrt_dmach_stop(_tx_dma);
|
||||
imxrt_dmach_stop(_rx_dma);
|
||||
|
||||
/* disable UART DMA */
|
||||
|
||||
rBAUD &= ~(LPUART_BAUD_RDMAE | LPUART_BAUD_TDMAE);
|
||||
|
||||
/* clear data that may be in the DATA register and clear overrun error: */
|
||||
uint32_t sr = rSTAT;
|
||||
|
||||
if (sr & (LPUART_STAT_OR | LPUART_STAT_RDRF)) {
|
||||
|
||||
while (rSTAT & LPUART_STAT_RDRF) {
|
||||
(void)rDATA;
|
||||
}
|
||||
}
|
||||
|
||||
rSTAT |= sr & (rSTAT_ERR_FLAGS_MASK | LPUART_STAT_IDLE); /* clear flags */
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2023 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_ssarc
|
||||
ssarc_dump.c
|
||||
)
|
||||
target_link_libraries(px4_layer PUBLIC arch_ssarc)
|
||||
@@ -0,0 +1,724 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2023 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <board_config.h>
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
||||
#include <crc32.h>
|
||||
|
||||
#ifdef CONFIG_BOARD_CRASHDUMP
|
||||
|
||||
#include <systemlib/hardfault_log.h>
|
||||
#include "chip.h"
|
||||
|
||||
#ifdef HAS_SSARC
|
||||
|
||||
#include <ssarc_dump.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define SSARC_DUMP_FILES 5
|
||||
#define MAX_OPENCNT (255) /* Limit of uint8_t */
|
||||
#define SSARCH_HEADER_SIZE (sizeof(struct ssarcfh_s))
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct ssarc_data_s {
|
||||
uint8_t data[PX4_SSARC_BLOCK_DATA];
|
||||
uint8_t padding[PX4_SSARC_BLOCK_SIZE - PX4_SSARC_BLOCK_DATA];
|
||||
};
|
||||
|
||||
struct ssarcfh_s {
|
||||
int32_t fileno; /* The minor number */
|
||||
uint32_t len; /* Total Bytes in this file */
|
||||
uint8_t padding0[8];
|
||||
uint32_t clean; /* No data has been written to the file */
|
||||
uint8_t padding1[12];
|
||||
struct timespec lastwrite; /* Last write time */
|
||||
uint8_t padding2[8];
|
||||
struct ssarc_data_s data[]; /* Data in the file */
|
||||
};
|
||||
|
||||
struct ssarc_dump_s {
|
||||
sem_t exclsem; /* For atomic accesses to this structure */
|
||||
uint8_t refs; /* Number of references */
|
||||
struct ssarcfh_s *pf; /* File in progmem */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_open(struct file *filep);
|
||||
static int ssarc_dump_close(struct file *filep);
|
||||
static off_t ssarc_dump_seek(struct file *filep, off_t offset,
|
||||
int whence);
|
||||
static ssize_t ssarc_dump_read(struct file *filep, char *buffer,
|
||||
size_t len);
|
||||
static ssize_t ssarc_dump_write(struct file *filep,
|
||||
const char *buffer, size_t len);
|
||||
static int ssarc_dump_ioctl(struct file *filep, int cmd,
|
||||
unsigned long arg);
|
||||
static int ssarc_dump_poll(struct file *filep,
|
||||
struct pollfd *fds, bool setup);
|
||||
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
||||
static int ssarc_dump_unlink(struct inode *inode);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
static const struct file_operations ssarc_dump_fops = {
|
||||
.open = ssarc_dump_open,
|
||||
.close = ssarc_dump_close,
|
||||
.read = ssarc_dump_read,
|
||||
.write = ssarc_dump_write,
|
||||
.seek = ssarc_dump_seek,
|
||||
.ioctl = ssarc_dump_ioctl,
|
||||
.poll = ssarc_dump_poll,
|
||||
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
||||
.unlink = ssarc_dump_unlink
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct ssarc_dump_s g_ssarc[SSARC_DUMP_FILES];
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_semgive
|
||||
****************************************************************************/
|
||||
|
||||
static void ssarc_dump_semgive(struct ssarc_dump_s *priv)
|
||||
{
|
||||
nxsem_post(&priv->exclsem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_semtake
|
||||
*
|
||||
* Description:
|
||||
* Take a semaphore handling any exceptional conditions
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the CAN peripheral state
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_semtake(struct ssarc_dump_s *priv)
|
||||
{
|
||||
return nxsem_wait_uninterruptible(&priv->exclsem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_open
|
||||
*
|
||||
* Description: Open the device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_open(struct file *filep)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct ssarc_dump_s *pmf;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
/* Increment the reference count */
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pmf->refs == MAX_OPENCNT) {
|
||||
return -EMFILE;
|
||||
|
||||
} else {
|
||||
pmf->refs++;
|
||||
}
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_internal_close
|
||||
*
|
||||
* Description:
|
||||
* Close Progmem entry; Recalculate the time and crc
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_internal_close(struct ssarcfh_s *pf)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
pf->lastwrite.tv_sec = ts.tv_sec;
|
||||
pf->lastwrite.tv_nsec = ts.tv_nsec;
|
||||
return pf->len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_close
|
||||
*
|
||||
* Description: close the device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_close(struct file *filep)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct ssarc_dump_s *pmf;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pmf->refs == 0) {
|
||||
ret = -EIO;
|
||||
|
||||
} else {
|
||||
pmf->refs--;
|
||||
|
||||
if (pmf->refs == 0) {
|
||||
if (pmf->pf->clean == 0) {
|
||||
ssarc_dump_internal_close(pmf->pf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_seek
|
||||
****************************************************************************/
|
||||
|
||||
static off_t ssarc_dump_seek(struct file *filep, off_t offset,
|
||||
int whence)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct ssarc_dump_s *pmf;
|
||||
off_t newpos;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return (off_t)ret;
|
||||
}
|
||||
|
||||
/* Determine the new, requested file position */
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
newpos = filep->f_pos + offset;
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
newpos = offset;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
newpos = pmf->pf->len + offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Return EINVAL if the whence argument is invalid */
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Opengroup.org:
|
||||
*
|
||||
* "The lseek() function shall allow the file offset to be set beyond the
|
||||
* end of the existing data in the file. If data is later written at this
|
||||
* point, subsequent reads of data in the gap shall return bytes with the
|
||||
* value 0 until data is actually written into the gap."
|
||||
*
|
||||
* We can conform to the first part, but not the second. But return EINVAL
|
||||
* if "...the resulting file offset would be negative for a regular file,
|
||||
* block special file, or directory."
|
||||
*/
|
||||
|
||||
if (newpos >= 0) {
|
||||
filep->f_pos = newpos;
|
||||
ret = newpos;
|
||||
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_read
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t ssarc_dump_read(struct file *filep, char *buffer,
|
||||
size_t len)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct ssarc_dump_s *pmf;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
/* Trim len if read would go beyond end of device */
|
||||
|
||||
if ((filep->f_pos + len) > pmf->pf->len) {
|
||||
len = pmf->pf->len - filep->f_pos;
|
||||
}
|
||||
|
||||
int offset = filep->f_pos % PX4_SSARC_BLOCK_DATA;
|
||||
int abs_pos = filep->f_pos / PX4_SSARC_BLOCK_DATA;
|
||||
size_t to_read = len;
|
||||
|
||||
if (offset != 0) {
|
||||
memcpy(buffer, &pmf->pf->data[abs_pos], PX4_SSARC_BLOCK_DATA - offset);
|
||||
to_read -= (PX4_SSARC_BLOCK_DATA - offset);
|
||||
abs_pos++;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (len / PX4_SSARC_BLOCK_DATA); i++) {
|
||||
if (to_read >= PX4_SSARC_BLOCK_DATA) {
|
||||
memcpy(buffer, &pmf->pf->data[abs_pos], PX4_SSARC_BLOCK_DATA);
|
||||
abs_pos++;
|
||||
buffer += PX4_SSARC_BLOCK_DATA;
|
||||
to_read -= PX4_SSARC_BLOCK_DATA;
|
||||
|
||||
} else {
|
||||
memcpy(buffer, &pmf->pf->data[abs_pos], to_read);
|
||||
buffer += to_read;
|
||||
abs_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
filep->f_pos += len;
|
||||
ssarc_dump_semgive(pmf);
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_internal_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t ssarc_dump_internal_write(struct ssarcfh_s *pf,
|
||||
const char *buffer,
|
||||
off_t offset, size_t len)
|
||||
{
|
||||
/* Write data */
|
||||
for (size_t i = 0; i <= (len / PX4_SSARC_BLOCK_DATA); i++) {
|
||||
memcpy(&pf->data[offset + i], &buffer[PX4_SSARC_BLOCK_DATA * i],
|
||||
PX4_SSARC_BLOCK_DATA);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t ssarc_dump_write(struct file *filep,
|
||||
const char *buffer, size_t len)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct ssarc_dump_s *pmf;
|
||||
int ret = -EFBIG;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
/* Forbid writes past the end of the device */
|
||||
|
||||
if (filep->f_pos < (int)pmf->pf->len) {
|
||||
/* Clamp len to avoid crossing the end of the memory */
|
||||
|
||||
if ((filep->f_pos + len) > pmf->pf->len) {
|
||||
len = pmf->pf->len - filep->f_pos;
|
||||
}
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
ret = len; /* save number of bytes written */
|
||||
|
||||
ssarc_dump_internal_write(pmf->pf, buffer, filep->f_pos, len);
|
||||
filep->f_pos += len;
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_poll
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_poll(struct file *filep, struct pollfd *fds,
|
||||
bool setup)
|
||||
{
|
||||
if (setup) {
|
||||
fds->revents |= (fds->events & (POLLIN | POLLOUT));
|
||||
|
||||
if (fds->revents != 0) {
|
||||
nxsem_post(fds->sem);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_ioctl
|
||||
*
|
||||
* Description: Return device geometry
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_ioctl(struct file *filep, int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct ssarc_dump_s *pmf;
|
||||
int ret = -ENOTTY;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
if (cmd == SSARC_DUMP_GETDESC_IOCTL) {
|
||||
struct ssarc_s *desc = (struct ssarc_s *)((uintptr_t)arg);
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!desc) {
|
||||
ret = -EINVAL;
|
||||
|
||||
} else {
|
||||
desc->fileno = pmf->pf->fileno;
|
||||
desc->len = pmf->pf->len;
|
||||
desc->flags = ((pmf->pf->clean) ? 0 : 2);
|
||||
desc->lastwrite = pmf->pf->lastwrite;
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_unlink
|
||||
*
|
||||
* Description:
|
||||
* This function will remove the remove the file from the file system
|
||||
* it will zero the contents and time stamp. It will leave the fileno
|
||||
* and pointer to the Progmem intact.
|
||||
* It should be called called on the file used for the crash dump
|
||||
* to remove it from visibility in the file system after it is created or
|
||||
* read thus arming it.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
||||
static int ssarc_dump_unlink(struct inode *inode)
|
||||
{
|
||||
struct ssarc_dump_s *pmf;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(inode && inode->i_private);
|
||||
pmf = (struct ssarc_dump_s *)inode->i_private;
|
||||
|
||||
ret = ssarc_dump_semtake(pmf);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pmf->pf->lastwrite.tv_nsec = 0;
|
||||
pmf->pf->lastwrite.tv_sec = 0;
|
||||
pmf->refs = 0;
|
||||
|
||||
ssarc_dump_semgive(pmf);
|
||||
nxsem_destroy(&pmf->exclsem);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssarc_dump_probe
|
||||
*
|
||||
* Description: Based on the number of files defined and their sizes
|
||||
* Initializes the base pointers to the file entries.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ssarc_dump_probe(int *ent, struct ssarc_dump_s pdev[])
|
||||
{
|
||||
int i, j;
|
||||
int alloc;
|
||||
int size;
|
||||
int avail;
|
||||
struct ssarcfh_s *pf = (struct ssarcfh_s *) PX4_SSARC_DUMP_BASE;
|
||||
int ret = -EFBIG;
|
||||
|
||||
avail = PX4_SSARC_DUMP_SIZE;
|
||||
|
||||
for (i = 0; (i < SSARC_DUMP_FILES) && ent[i] && (avail > 0);
|
||||
i++) {
|
||||
/* Validate the actual allocations against what is in the PROGMEM */
|
||||
|
||||
size = ent[i];
|
||||
|
||||
/* Use all that is left */
|
||||
|
||||
if (size == -1) {
|
||||
size = avail;
|
||||
size -= SSARCH_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/* Add in header size and keep aligned to blocks */
|
||||
|
||||
alloc = (size / PX4_SSARC_BLOCK_DATA) * PX4_SSARC_BLOCK_SIZE;
|
||||
|
||||
/* Does it fit? */
|
||||
|
||||
if (size <= avail) {
|
||||
ret = i + 1;
|
||||
|
||||
if ((int)pf->len != size || pf->fileno != i) {
|
||||
pf->len = size;
|
||||
pf->clean = 1;
|
||||
pf->fileno = i;
|
||||
pf->lastwrite.tv_sec = 0;
|
||||
pf->lastwrite.tv_nsec = 0;
|
||||
|
||||
for (j = 0; j < (size / PX4_SSARC_BLOCK_DATA); j++) {
|
||||
memset(pf->data[j].data, 0, PX4_SSARC_BLOCK_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
pdev[i].pf = pf;
|
||||
pf = (struct ssarcfh_s *)((uint32_t *)pf + ((alloc + sizeof(struct ssarcfh_s)) / 4));
|
||||
nxsem_init(&g_ssarc[i].exclsem, 0, 1);
|
||||
}
|
||||
|
||||
avail -= (size + PX4_SSARC_HEADER_SIZE);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Function: ssarc_dump_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the Battery Backed up SRAM driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - the path to instantiate the files.
|
||||
* sizes - Pointer to a any array of file sizes to create
|
||||
* the last entry should be 0
|
||||
* A size of -1 will use all the remaining spaces
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of files created on success; Negated errno on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ssarc_dump_initialize(char *devpath, int *sizes)
|
||||
{
|
||||
int i;
|
||||
int fcnt;
|
||||
char devname[32];
|
||||
|
||||
int ret = OK;
|
||||
|
||||
if (devpath == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i = strlen(devpath);
|
||||
|
||||
if (i == 0 || i > (int)sizeof(devname) - 3) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(g_ssarc, 0, sizeof(g_ssarc));
|
||||
|
||||
fcnt = ssarc_dump_probe(sizes, g_ssarc);
|
||||
|
||||
for (i = 0; i < fcnt && ret >= OK; i++) {
|
||||
snprintf(devname, sizeof(devname), "%s%d", devpath, i);
|
||||
ret = register_driver(devname, &ssarc_dump_fops, 0666, &g_ssarc[i]);
|
||||
}
|
||||
|
||||
return ret < OK ? ret : fcnt;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: ssarc_dump_savepanic
|
||||
*
|
||||
* Description:
|
||||
* Saves the panic context in a previously allocated PROGMEM file
|
||||
*
|
||||
* Input Parameters:
|
||||
* fileno - the value returned by the ioctl GETDESC_IOCTL
|
||||
* context - Pointer to a any array of bytes to save
|
||||
* length - The length of the data pointed to byt context
|
||||
*
|
||||
* Returned Value:
|
||||
* Length saved or negated errno.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
int ssarc_dump_savepanic(int fileno, uint8_t *context, int length)
|
||||
{
|
||||
struct ssarcfh_s *pf;
|
||||
int ret = -ENOSPC;
|
||||
|
||||
/* On a bad day we could panic while panicking, (and we debug assert)
|
||||
* this is a potential feeble attempt at only writing the first
|
||||
* panic's context to the file
|
||||
*/
|
||||
|
||||
static bool once = false;
|
||||
|
||||
if (!once) {
|
||||
once = true;
|
||||
|
||||
DEBUGASSERT(fileno > 0 && fileno < SSARC_DUMP_FILES);
|
||||
|
||||
pf = g_ssarc[fileno].pf;
|
||||
|
||||
/* If the g_ssarc has been nulled out we return ENXIO.
|
||||
*
|
||||
* As once ensures we will keep the first dump. Checking the time for
|
||||
* 0 protects from over writing a previous crash dump that has not
|
||||
* been saved to long term storage and erased. The dreaded reboot
|
||||
* loop.
|
||||
*/
|
||||
|
||||
if (pf == NULL) {
|
||||
ret = -ENXIO;
|
||||
|
||||
} else if (pf->lastwrite.tv_sec == 0 && pf->lastwrite.tv_nsec == 0) {
|
||||
/* Clamp length if too big */
|
||||
|
||||
if (length > (int)pf->len) {
|
||||
length = pf->len;
|
||||
}
|
||||
|
||||
ssarc_dump_internal_write(pf, (char *) context, 0, length);
|
||||
|
||||
/* Seal the file */
|
||||
|
||||
ssarc_dump_internal_close(pf);
|
||||
ret = length;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HAS_SSARC */
|
||||
#endif /* SYSTEMCMDS_HARDFAULT_LOG */
|
||||
Reference in New Issue
Block a user