Intial Commit PX4 FMUV6RT

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

px4_fmu-6xrt:Using imxrt_flexspi_nor_octal

px4_fmu-6xrt:Entry is start

px4_fmu-6xrt:Add Proper MTD

px4_fmu-6xrt:Set I2C Buses

px4_fmu-6xrt:Proper SPI usage

px4_fmu-6xrt:Adjust memory Map to use the 2 MB

px4_fmu-6xrt:Bring in ROMAPI

px4_fmu-6xrt:Push FLASH to 200Mhz

px4_fmu-6xrt:Use BOARD_I2C_LATEINIT

px4_fmu-6xrt:Clock Config remove unused devices

px4_fmu-6xrt:Remove EVK SDRAM IO

px4_fmu-6xrt:Enable SE550 using HW_VER_REV_DRIVE

px4_fmu-6xrt:Use MTD to mount FRAM on Flex SPI

px4_fmu-6xrt:Manifest

px4_fmu-6xrt:Restore board_peripheral_reset

px4_fmu-6xrt:Set I2C buss Interna/Externa and startup

nxp/rt117x:Set 6 I2C busses

px4_fmu-6xrt:Correct Clock Sources and Freqency Settings

px4_fmu-6xrt:Correct ADC Settings

px4_fmu-6xrt:Tune FlexSPI config and sync header with debug variant Linker prep for rodata ahb partitioning

px4_fmu-6xrt:FlexSPI prefetch partition split .text and .rodata

   Current config
     1KB Prefetch .rodata
     3KB Prefetch .text

px4_fmu-6xrt:Run imxrt_flash_setup_prefetch_partition from ram with barriers

px4_fmu-6xrt:Use All OCTL setting from FLASH g_flash_config SANS lookupTable

px4_fmu-6xrt:Octal spi boot/debug problem bypass

px4_fmu-6xrt:Add PWM test

px4_fmu-6xrt:Fix clockconfig and USB vbus sense

px4_fmu-6xrt: Use TCM

px4_fmu-6xrt: Ethernet bringup

imxrt: use unique_id register for board_identity

px4_fmu-6xrt: update ITCM mapping, todo proper trap on pc hitting 0x0

px4_fmu-6xrt:correct rotation icm42688p onboard imu

rt117x: Add SSARC HP RAM driver for memory dumps

px4_fmu-6xrt: Enable hardfault_log

px4_fmu-6xrt: Enable DMA pool

px4_fmu-6xrt: fix uart mapping

px4_fmu-6xrt: enable SocketCAN & DroneCAN

px4_fmu-6xrt:Command line history TAB completion

px4_fmu-6xrt:Fix pinning duplication

px4_fmu-6xrt:Support conditional PHY address based on selected PHY

px4_fmu-6xrt:Add Pull Downs on CTS, use GPIO for RTS

px4_fmu-6xrt:Set TelemN TX Slew rate and Drive Strenth to max

px4_fmu-6xrt::Set TELEM Buffers add HW HS

px4_fmu-6xrt:Turn off DMA poll

px4_fmu-6xrt:RC_SERIAL_PORT needed to be px4io to disable rc_input using TELEM2!

px4_fmu-6xrt: bootloader (#22228)

* imxrt:Add bootloader support
* bootloader:imxrt clear BOOT_RTC_SIGNATURE
* px4_fmu-6xrt:Add bootloader
* px4_fmu-6xrt:bootloader removed ADC
* px4_fmu-6xrt:bootloader base bootloader script off of script.ld
* px4_fmu-6xrt:add _bootdelay_signature & change entry from 0x30000000 to 0x30040000
* px4_fmu-6xrt:hw_config Bootloader has to have 12 bytes

px4_fmu-6xrt:Default to use LAN8742A PHY

px4_fmu-v6xrt:VID Set to Drone Code

board_reset:Enable ability to write RTC GP regs

px4_fmu-6xrt:Fix CMP0079 error

rt117x:micro_hal Add a PX4_MAKE_GPIO_PULLED_INPUT

px4_fmu-v6xrt:Set CTS High before VDD_5V applided to ports to avoid radios fro entering bootloaders

fmu-v6xrt: increase 5v down time

fmu-v6xrt:Ready for Release DEBUGASSERTS off and Console 57600,
Bootloder updated.

imxrt:board_hw_rev_ver Rework for 3.893V Ref

px4_fmu-v6xrt:Move ADC to Port3
This commit is contained in:
David Sidrane
2023-05-02 07:00:24 -07:00
committed by Daniel Agar
parent e3f8d53718
commit e90e8ae0ea
69 changed files with 11080 additions and 308 deletions

View File

@@ -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")

View File

@@ -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;
}

View File

@@ -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))

View File

@@ -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)) {

View File

@@ -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

View File

@@ -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})

View File

@@ -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
)

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -73,23 +73,26 @@ static char hw_info[HW_INFO_SIZE] = {0};
static int dn_to_ordinal(uint16_t dn)
{
// Refernece is 3.8933 = (1.825f * 64.0f / 30.0f)
// LSB is 0.000950521 = 3.8933 / 4096
// DN's are V/LSB
const struct {
uint16_t low; // High(n-1) + 1
uint16_t high; // Average High(n)+Low(n+1) EX. 1356 = AVRG(1331,1382)
} dn2o[] = {
// R1(up) R2(down) V min V Max DN Min DN Max
{0, 0 }, // 0 No Resistors
{1, 579 }, // 1 24.9K 442K 0.166255191 0.44102252 204 553
{580, 967 }, // 2 32.4K 174K 0.492349322 0.770203609 605 966
{968, 1356}, // 3 38.3K 115K 0.787901749 1.061597759 968 1331
{1357, 1756}, // 4 46.4K 84.5K 1.124833577 1.386007306 1382 1738
{1757, 2137}, // 5 51.1K 61.9K 1.443393279 1.685367869 1774 2113
{2138, 2519}, // 6 61.9K 51.1K 1.758510242 1.974702534 2161 2476
{2520, 2919}, // 7 84.5K 46.4K 2.084546498 2.267198261 2562 2842
{2920, 3308}, // 8 115K 38.3K 2.437863827 2.57656294 2996 3230
{3309, 3699}, // 9 174K 32.4K 2.755223792 2.847933804 3386 3571
{3700, 4095}, // 10 442K 24.9K 3.113737849 3.147347506 3827 3946
// R2(down) R1(up) V min V Max DN Min DN Max
{0, 0 }, // 0 No Resistors
{1, 490 }, // 1 24.9K 442K 0.166255191 0.44102252 174 463
{491, 819 }, // 2 32.4K 174K 0.492349322 0.770203609 517 810
{820, 1149}, // 3 38.3K 115K 0.787901749 1.061597759 828 1116
{1150, 1488}, // 4 46.4K 84.5K 1.124833577 1.386007306 1183 1458
{1489, 1811}, // 5 51.1K 61.9K 1.443393279 1.685367869 1518 1773
{1812, 2135}, // 6 61.9K 51.1K 1.758510242 1.974702534 1850 2077
{2136, 2474}, // 7 84.5K 46.4K 2.084546498 2.267198261 2193 2385
{2475, 2804}, // 8 115K 38.3K 2.437863827 2.57656294 2564 2710
{2805, 3135}, // 9 174K 32.4K 2.755223792 2.847933804 2898 2996
{3136, 4095}, // 10 442K 24.9K 3.113737849 3.147347506 3275 3311
};
for (unsigned int i = 0; i < arraySize(dn2o); i++) {
@@ -141,77 +144,87 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc
/*
* Step one is there resistors?
*
* If we set the mid-point of the ladder which is the ADC input to an
* output, then whatever state is driven out should be seen by the GPIO
* that is on the bottom of the ladder that is switched to an input.
* The SENCE line is effectively an output with a high value pullup
* resistor on it driving an input through a series resistor with a pull up.
* If present the series resistor will form a low pass filter due to stray
* capacitance, but this is fine as long as we give it time to settle.
* With the common REV/VER Drive we have to look at the ADC values.
* to determine if the R's are hooked up. This is because the
* the REV and VER pairs will influence each other and not make
* digital thresholds.
*
* I.E
*
* VDD
* 442K
* REV is a Float
* 24.9K
* Drive as input
* 442K
* VER is 0.
* 24.9K
* VDD
*
* This is 466K up and 442K down.
*
* Driving VER Low and reading DRIVE will result in approximately mid point
* values not a digital Low.
*/
/* Turn the drive lines to digital inputs with No pull up */
imxrt_config_gpio(PX4_MAKE_GPIO_INPUT(gpio_drive) & ~IOMUX_PULL_MASK);
/* Turn the sense lines to digital outputs LOW */
imxrt_config_gpio(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense));
up_udelay(100); /* About 10 TC assuming 485 K */
/* Read Drive lines while sense are driven low */
int low = imxrt_gpio_read(PX4_MAKE_GPIO_INPUT(gpio_drive));
/* Write the sense lines HIGH */
imxrt_gpio_write(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense), 1);
up_udelay(100); /* About 10 TC assuming 485 K */
/* Read Drive lines while sense are driven high */
int high = imxrt_gpio_read(PX4_MAKE_GPIO_INPUT(gpio_drive));
/* restore the pins to ANALOG */
uint32_t dn_sum = 0;
uint32_t dn = 0;
uint32_t high = 0;
uint32_t low = 0;
imxrt_config_gpio(gpio_sense);
/* Turn the drive lines to digital outputs High */
imxrt_config_gpio(gpio_drive);
up_udelay(100); /* About 10 TC assuming 485 K */
for (unsigned av = 0; av < samples; av++) {
if (px4_arch_adc_init(HW_REV_VER_ADC_BASE) == OK) {
dn = px4_arch_adc_sample(HW_REV_VER_ADC_BASE, adc_channel);
if (dn == UINT32_MAX) {
break;
}
dn_sum += dn;
}
}
if (dn != UINT32_MAX) {
high = dn_sum / samples;
}
/* Turn the drive lines to digital outputs LOW */
imxrt_config_gpio(gpio_drive ^ GPIO_OUTPUT_SET);
up_udelay(100); /* About 10 TC assuming 485 K */
/* Are Resistors in place ?*/
dn_sum = 0;
uint32_t dn_sum = 0;
uint32_t dn = 0;
for (unsigned av = 0; av < samples; av++) {
if ((high ^ low) && low == 0) {
/* Yes - Fire up the ADC (it has once control) */
if (px4_arch_adc_init(HW_REV_VER_ADC_BASE) == OK) {
dn = px4_arch_adc_sample(HW_REV_VER_ADC_BASE, adc_channel);
/* Read the value */
for (unsigned av = 0; av < samples; av++) {
dn = px4_arch_adc_sample(HW_REV_VER_ADC_BASE, adc_channel);
if (dn == UINT32_MAX) {
break;
}
dn_sum += dn;
}
if (dn != UINT32_MAX) {
*id = dn_sum / samples;
rv = OK;
}
if (dn == UINT32_MAX) {
break;
}
dn_sum += dn;
}
if (dn != UINT32_MAX) {
low = dn_sum / samples;
}
if ((high > low) && high > ((px4_arch_adc_dn_fullcount() * 800) / 1000)) {
*id = low;
rv = OK;
} else {
/* No - No Resistors is ID 0 */
*id = 0;

View File

@@ -41,9 +41,11 @@
#include <errno.h>
#include <nuttx/board.h>
#include <arm_internal.h>
#include <hardware/imxrt_snvs.h>
#include <hardware/rt117x/imxrt117x_snvs.h>
#define PX4_IMXRT_RTC_REBOOT_REG 3 // Must be common with bootloader and:
#define BOOT_RTC_SIGNATURE 0xb007b007
#define PX4_IMXRT_RTC_REBOOT_REG 3
#define PX4_IMXRT_RTC_REBOOT_REG_ADDRESS IMXRT_SNVS_LPGPR3
#if CONFIG_IMXRT_RTC_MAGIC_REG == PX4_IMXRT_RTC_REBOOT_REG
# error CONFIG_IMXRT_RTC_MAGIC_REG can nt have the save value as PX4_IMXRT_RTC_REBOOT_REG
@@ -51,8 +53,9 @@
static int board_reset_enter_bootloader()
{
uint32_t regvalue = 0xb007b007;
putreg32(regvalue, IMXRT_SNVS_LPGPR(PX4_IMXRT_RTC_REBOOT_REG));
uint32_t regvalue = BOOT_RTC_SIGNATURE;
modifyreg32(IMXRT_SNVS_LPCR, 0, SNVS_LPCR_GPR_Z_DIS);
putreg32(regvalue, PX4_IMXRT_RTC_REBOOT_REG_ADDRESS);
return OK;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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)

View File

@@ -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))
@@ -102,7 +111,12 @@ int imxrt_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, bool
#define px4_arch_gpiosetevent(pinset,r,f,e,fp,a) imxrt_gpiosetevent(pinset,r,f,e,fp,a)
#define PX4_MAKE_GPIO_INPUT(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_INPUT ))
#define PX4_MAKE_GPIO_PULLED_INPUT(gpio, pull) (PX4_MAKE_GPIO_INPUT((gpio)) | (pull))
#define PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_SLEW_FAST))
#define PX4_MAKE_GPIO_OUTPUT_SET(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT | GPIO_OUTPUT_ONE | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_SLEW_FAST))
#if defined(CONFIG_IMXRT_FLEXSPI)
# define HAS_FLEXSPI
#endif
__END_DECLS

View File

@@ -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"

View File

@@ -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__ */

View File

@@ -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 */

View File

@@ -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
)

View File

@@ -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 */
}

View File

@@ -0,0 +1,40 @@
############################################################################
#
# 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.
#
############################################################################
cmake_policy(PUSH)
cmake_policy(SET CMP0079 NEW)
px4_add_library(arch_ssarc
ssarc_dump.c
)
target_link_libraries(px4_layer PUBLIC arch_ssarc)
cmake_policy(POP)

View File

@@ -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 */