diff --git a/.gitignore b/.gitignore index 2e467da624..5d37a8e4e2 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,5 @@ src/systemcmds/topic_listener/listener_generated.cpp # SITL dataman eeprom/ + +!src/drivers/distance_sensor/broadcom/afbrs50/Lib/* diff --git a/boards/ark/can-flow/debug.cmake b/boards/ark/can-flow/debug.cmake index ddcb65e867..3a80b7f028 100644 --- a/boards/ark/can-flow/debug.cmake +++ b/boards/ark/can-flow/debug.cmake @@ -12,6 +12,7 @@ px4_add_board( UAVCAN_INTERFACES 1 DRIVERS bootloaders + distance_sensor/broadcom/afbrs50 imu/bosch/bmi088 optical_flow/paw3902 uavcannode @@ -20,14 +21,13 @@ px4_add_board( load_mon #sensors SYSTEMCMDS - mft - mtd param perf reboot system_time top - topic_listener + #topic_listener + uorb ver work_queue ) diff --git a/boards/ark/can-flow/default.cmake b/boards/ark/can-flow/default.cmake index 7ac68b3f10..4b966eb29a 100644 --- a/boards/ark/can-flow/default.cmake +++ b/boards/ark/can-flow/default.cmake @@ -13,6 +13,7 @@ px4_add_board( UAVCAN_INTERFACES 1 DRIVERS bootloaders + distance_sensor/broadcom/afbrs50 imu/bosch/bmi088 optical_flow/paw3902 uavcannode @@ -21,14 +22,13 @@ px4_add_board( #load_mon #sensors SYSTEMCMDS - mft - mtd param #perf #reboot #system_time #top #topic_listener + #uorb #ver #work_queue ) diff --git a/boards/ark/can-flow/init/rc.board_sensors b/boards/ark/can-flow/init/rc.board_sensors index 7750a31898..696b813919 100644 --- a/boards/ark/can-flow/init/rc.board_sensors +++ b/boards/ark/can-flow/init/rc.board_sensors @@ -4,6 +4,8 @@ #------------------------------------------------------------------------------ # Internal SPI -paw3902 -s start -Y 90 +paw3902 -s start -Y 180 bmi088 -A -s -R 4 start bmi088 -G -s -R 4 start + +afbrs50 start diff --git a/boards/ark/can-flow/nuttx-config/include/board.h b/boards/ark/can-flow/nuttx-config/include/board.h index cd6ea967db..58876a44ce 100644 --- a/boards/ark/can-flow/nuttx-config/include/board.h +++ b/boards/ark/can-flow/nuttx-config/include/board.h @@ -133,8 +133,8 @@ #define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_1 #define GPIO_SPI1_SCK GPIO_SPI1_SCK_1 -#define GPIO_SPI2_MISO GPIO_SPI2_MISO_1 -#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1 -#define GPIO_SPI2_SCK GPIO_SPI2_SCK_1 +#define GPIO_SPI2_MISO GPIO_SPI2_MISO_1 /* PB14 */ +#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1 /* PB15 */ +#define GPIO_SPI2_SCK GPIO_SPI2_SCK_1 /* PB10 */ #endif /* __ARCH_BOARD_BOARD_H */ diff --git a/boards/ark/can-flow/nuttx-config/include/board_dma_map.h b/boards/ark/can-flow/nuttx-config/include/board_dma_map.h index 2d52cfbfec..f6e577b3d5 100644 --- a/boards/ark/can-flow/nuttx-config/include/board_dma_map.h +++ b/boards/ark/can-flow/nuttx-config/include/board_dma_map.h @@ -40,6 +40,4 @@ // DMA2 Channel/Stream Selections //--------------------------------------------//---------------------------//---------------- #define DMACHAN_SPI1_RX DMAMAP_SPI1_RX_2 // DMA2, Stream 2, Channel 3 -#define DMACHAN_SPI2_RX DMAMAP_SPI2_RX // DMA2, Stream 3, Channel 0 -#define DMACHAN_SPI2_TX DMAMAP_SPI2_TX // DMA2, Stream 4, Channel 0 #define DMACHAN_SPI1_TX DMAMAP_SPI1_TX_1 // DMA2, Stream 5, Channel 3 diff --git a/boards/ark/can-flow/nuttx-config/nsh/defconfig b/boards/ark/can-flow/nuttx-config/nsh/defconfig index de632fc595..006729f025 100644 --- a/boards/ark/can-flow/nuttx-config/nsh/defconfig +++ b/boards/ark/can-flow/nuttx-config/nsh/defconfig @@ -144,8 +144,6 @@ CONFIG_STM32_SPI1=y CONFIG_STM32_SPI1_DMA=y CONFIG_STM32_SPI1_DMA_BUFFER=1024 CONFIG_STM32_SPI2=y -CONFIG_STM32_SPI2_DMA=y -CONFIG_STM32_SPI2_DMA_BUFFER=1024 CONFIG_STM32_SPI_DMA=y CONFIG_STM32_TIM8=y CONFIG_STM32_USART2=y diff --git a/boards/ark/can-flow/src/board_config.h b/boards/ark/can-flow/src/board_config.h index 44424aeae7..8096f5a5ad 100644 --- a/boards/ark/can-flow/src/board_config.h +++ b/boards/ark/can-flow/src/board_config.h @@ -56,6 +56,13 @@ #define GPIO_nLED_RED /* PB3 */ (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN3) #define GPIO_nLED_BLUE /* PA8 */ (GPIO_OUTPUT|GPIO_OPENDRAIN|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN8) +#define BROADCOM_AFBR_S50_S2PI_SPI_BUS 2 +#define BROADCOM_AFBR_S50_S2PI_CS /* PB12 */ (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN12) +#define BROADCOM_AFBR_S50_S2PI_IRQ /* PB4 */ (GPIO_INPUT|GPIO_PULLUP|GPIO_PORTB|GPIO_PIN4|GPIO_EXTI) +#define BROADCOM_AFBR_S50_S2PI_CLK /* PB10 */ GPIO_SPI2_SCK_1 +#define BROADCOM_AFBR_S50_S2PI_MOSI /* PB15 */ GPIO_SPI2_MOSI_1 +#define BROADCOM_AFBR_S50_S2PI_MISO /* PB14 */ GPIO_SPI2_MISO_1 + #define BOARD_HAS_CONTROL_STATUS_LEDS 1 #define BOARD_OVERLOAD_LED LED_RED #define BOARD_ARMED_STATE_LED LED_BLUE diff --git a/platforms/nuttx/src/px4/nxp/imxrt/board_hw_info/board_hw_rev_ver.c b/platforms/nuttx/src/px4/nxp/imxrt/board_hw_info/board_hw_rev_ver.c index f0097cb967..d4768fdd1e 100644 --- a/platforms/nuttx/src/px4/nxp/imxrt/board_hw_info/board_hw_rev_ver.c +++ b/platforms/nuttx/src/px4/nxp/imxrt/board_hw_info/board_hw_rev_ver.c @@ -160,7 +160,7 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc /* Turn the sense lines to digital outputs LOW */ - imxrt_config_gpio(PX4_MAKE_GPIO_OUTPUT(gpio_sense)); + imxrt_config_gpio(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense)); up_udelay(100); /* About 10 TC assuming 485 K */ @@ -172,7 +172,7 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc /* Write the sense lines HIGH */ - imxrt_gpio_write(PX4_MAKE_GPIO_OUTPUT(gpio_sense), 1); + imxrt_gpio_write(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense), 1); up_udelay(100); /* About 10 TC assuming 485 K */ diff --git a/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h index 0a870b6a96..0d240f0069 100644 --- a/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h @@ -113,6 +113,7 @@ int kinetis_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, boo #define _PX4_MAKE_GPIO(pin_ftmx, io) ((((uint32_t)(pin_ftmx)) & ~(_PIN_MODE_MASK | _PIN_OPTIONS_MASK)) |(io)) #define PX4_MAKE_GPIO_INPUT(gpio) _PX4_MAKE_GPIO(gpio, GPIO_PULLUP) -#define PX4_MAKE_GPIO_OUTPUT(gpio) _PX4_MAKE_GPIO(gpio, GPIO_HIGHDRIVE) +#define PX4_MAKE_GPIO_OUTPUT_SET(gpio) _PX4_MAKE_GPIO(gpio, GPIO_HIGHDRIVE) +#define PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio) _PX4_MAKE_GPIO(gpio, GPIO_LOWDRIVE) __END_DECLS diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h index 368271913c..f319c80b68 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h @@ -105,6 +105,7 @@ 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 | IOMUX_SCHMITT_TRIGGER | IOMUX_PULL_UP_47K | IOMUX_DRIVE_HIZ)) -#define PX4_MAKE_GPIO_OUTPUT(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_CMOS_OUTPUT | IOMUX_PULL_KEEP | IOMUX_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST)) +#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_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | 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_DRIVE_33OHM | IOMUX_SPEED_MEDIUM | IOMUX_SLEW_FAST)) __END_DECLS diff --git a/platforms/nuttx/src/px4/stm/stm32_common/board_hw_info/board_hw_rev_ver.c b/platforms/nuttx/src/px4/stm/stm32_common/board_hw_info/board_hw_rev_ver.c index c6a7ca5492..c5b8ae2cac 100644 --- a/platforms/nuttx/src/px4/stm/stm32_common/board_hw_info/board_hw_rev_ver.c +++ b/platforms/nuttx/src/px4/stm/stm32_common/board_hw_info/board_hw_rev_ver.c @@ -170,7 +170,7 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc /* Turn the sense lines to digital outputs LOW */ - stm32_configgpio(PX4_MAKE_GPIO_OUTPUT(gpio_sense)); + stm32_configgpio(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense)); up_udelay(100); /* About 10 TC assuming 485 K */ @@ -182,7 +182,7 @@ static int read_id_dn(int *id, uint32_t gpio_drive, uint32_t gpio_sense, int adc /* Write the sense lines HIGH */ - stm32_gpiowrite(PX4_MAKE_GPIO_OUTPUT(gpio_sense), 1); + stm32_gpiowrite(PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio_sense), 1); up_udelay(100); /* About 10 TC assuming 485 K */ diff --git a/platforms/nuttx/src/px4/stm/stm32_common/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/stm/stm32_common/include/px4_arch/micro_hal.h index 63803b5a4a..18fbd4bf27 100644 --- a/platforms/nuttx/src/px4/stm/stm32_common/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/stm/stm32_common/include/px4_arch/micro_hal.h @@ -103,7 +103,8 @@ __BEGIN_DECLS #define px4_arch_gpiosetevent(pinset,r,f,e,fp,a) stm32_gpiosetevent(pinset,r,f,e,fp,a) #define PX4_MAKE_GPIO_INPUT(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_INPUT|GPIO_PULLUP)) -#define PX4_MAKE_GPIO_OUTPUT(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR)) +#define PX4_MAKE_GPIO_OUTPUT_CLEAR(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_CLEAR)) +#define PX4_MAKE_GPIO_OUTPUT_SET(gpio) (((gpio) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET)) #define PX4_GPIO_PIN_OFF(def) (((def) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_INPUT|GPIO_FLOAT|GPIO_SPEED_2MHz)) diff --git a/src/drivers/distance_sensor/CMakeLists.txt b/src/drivers/distance_sensor/CMakeLists.txt index 1c9e783799..e7e3b632f6 100644 --- a/src/drivers/distance_sensor/CMakeLists.txt +++ b/src/drivers/distance_sensor/CMakeLists.txt @@ -31,6 +31,7 @@ # ############################################################################ +add_subdirectory(broadcom) add_subdirectory(cm8jl65) add_subdirectory(leddar_one) add_subdirectory(ll40ls) diff --git a/src/drivers/distance_sensor/broadcom/CMakeLists.txt b/src/drivers/distance_sensor/broadcom/CMakeLists.txt new file mode 100644 index 0000000000..c47ae8fb22 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/CMakeLists.txt @@ -0,0 +1,34 @@ +############################################################################ +# +# Copyright (c) 2021 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +#add_subdirectory(afbrs50) # not suitable for general inclusion diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.cpp b/src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.cpp new file mode 100644 index 0000000000..8cb6355062 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** + * + * Copyright (c) 2021 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* Include Files */ +#include "AFBRS50.hpp" + +#include + +#include +#include + +#define AFBRS50_MEASURE_INTERVAL (1000000 / 100) // 10Hz + +/*! Define the SPI baud rate (to be used in the SPI module). */ +#define SPI_BAUD_RATE 5000000 + +#include "s2pi.h" +#include "timer.h" +#include "argus_hal_test.h" + +AFBRS50 *g_dev{nullptr}; + +AFBRS50::AFBRS50(uint8_t device_orientation): + ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::hp_default), + _px4_rangefinder(0, device_orientation) +{ + device::Device::DeviceId device_id{}; + device_id.devid_s.bus_type = device::Device::DeviceBusType::DeviceBusType_SPI; + device_id.devid_s.bus = BROADCOM_AFBR_S50_S2PI_SPI_BUS; + device_id.devid_s.devtype = DRV_DIST_DEVTYPE_AFBRS50; + + _px4_rangefinder.set_device_id(device_id.devid); +} + +AFBRS50::~AFBRS50() +{ + stop(); + + perf_free(_sample_perf); +} + +status_t AFBRS50::measurement_ready_callback(status_t status, void *data) +{ + if (!up_interrupt_context()) { + if (status == STATUS_OK) { + if (g_dev) { + g_dev->ProcessMeasurement(data); + } + } + } + + return status; +} + +void AFBRS50::ProcessMeasurement(void *data) +{ + if (data != nullptr) { + perf_count(_sample_perf); + + argus_results_t res{}; + status_t evaluate_status = Argus_EvaluateData(_hnd, &res, data); + + if ((evaluate_status == STATUS_OK) && (res.Status == 0)) { + uint32_t result_mm = res.Bin.Range / (Q9_22_ONE / 1000); + float result_m = static_cast(result_mm) / 1000.f; + _px4_rangefinder.update(((res.TimeStamp.sec * 1000000ULL) + res.TimeStamp.usec), result_m); + } + } +} + +int AFBRS50::init() +{ + if (_hnd != nullptr) { + // retry + Argus_Deinit(_hnd); + Argus_DestroyHandle(_hnd); + _hnd = nullptr; + } + + _hnd = Argus_CreateHandle(); + + if (_hnd == nullptr) { + PX4_ERR("Handle not initialized"); + return PX4_ERROR; + } + + // Initialize the S2PI hardware required by the API. + S2PI_Init(BROADCOM_AFBR_S50_S2PI_SPI_BUS, SPI_BAUD_RATE); + + status_t status = Argus_Init(_hnd, BROADCOM_AFBR_S50_S2PI_SPI_BUS); + + if (status == STATUS_OK) { + uint32_t id = Argus_GetChipID(_hnd); + uint32_t value = Argus_GetAPIVersion(); + uint8_t a = (value >> 24) & 0xFFU; + uint8_t b = (value >> 16) & 0xFFU; + uint8_t c = value & 0xFFFFU; + PX4_INFO_RAW("AFBR-S50 Chip ID: %d, API Version: %d v%d.%d.%d\n", id, value, a, b, c); + + argus_module_version_t mv = Argus_GetModuleVersion(_hnd); + + switch (mv) { + case AFBR_S50MV85G_V1: + + // FALLTHROUGH + case AFBR_S50MV85G_V2: + + // FALLTHROUGH + case AFBR_S50MV85G_V3: + _px4_rangefinder.set_min_distance(0.08f); + _px4_rangefinder.set_max_distance(10.f); + _px4_rangefinder.set_fov(math::radians(6.f)); + PX4_INFO_RAW("AFBR-S50MV85G\n"); + break; + + case AFBR_S50LV85D_V1: + _px4_rangefinder.set_min_distance(0.08f); + _px4_rangefinder.set_max_distance(30.f); + _px4_rangefinder.set_fov(math::radians(6.f)); + PX4_INFO_RAW("AFBR-S50LV85D (v1)\n"); + break; + + case AFBR_S50MV68B_V1: + _px4_rangefinder.set_min_distance(0.08f); + _px4_rangefinder.set_max_distance(10.f); + _px4_rangefinder.set_fov(math::radians(1.f)); + PX4_INFO_RAW("AFBR-S50MV68B (v1)\n"); + break; + + case AFBR_S50MV85I_V1: + _px4_rangefinder.set_min_distance(0.08f); + _px4_rangefinder.set_max_distance(5.f); + _px4_rangefinder.set_fov(math::radians(6.f)); + PX4_INFO_RAW("AFBR-S50MV85I (v1)\n"); + break; + + case AFBR_S50SV85K_V1: + _px4_rangefinder.set_min_distance(0.08f); + _px4_rangefinder.set_max_distance(10.f); + _px4_rangefinder.set_fov(math::radians(4.f)); + PX4_INFO_RAW("AFBR-S50SV85K (v1)\n"); + break; + + default: + break; + } + + _state = STATE::CONFIGURE; + ScheduleDelayed(AFBRS50_MEASURE_INTERVAL); + return PX4_OK; + } + + return PX4_ERROR; +} + +void AFBRS50::Run() +{ + // backup schedule + ScheduleDelayed(100_ms); + + switch (_state) { + case STATE::TEST: { + Argus_VerifyHALImplementation(Argus_GetSPISlave(_hnd)); + + _state = STATE::CONFIGURE; + ScheduleDelayed(100_ms); + } + break; + + case STATE::CONFIGURE: { + Argus_SetConfigurationFrameTime(_hnd, AFBRS50_MEASURE_INTERVAL); + + status_t status = Argus_StartMeasurementTimer(_hnd, measurement_ready_callback); + + if (status != STATUS_OK) { + PX4_ERR("CONFIGURE status not okay: %i", status); + _state = STATE::STOP; + ScheduleNow(); + + } else { + _state = STATE::COLLECT; + ScheduleDelayed(AFBRS50_MEASURE_INTERVAL); + } + } + break; + + case STATE::COLLECT: { + // currently handeled by measurement_ready_callback + } + break; + + case STATE::STOP: { + Argus_StopMeasurementTimer(_hnd); + Argus_Deinit(_hnd); + Argus_DestroyHandle(_hnd); + } + break; + + default: + break; + } +} + +void AFBRS50::stop() +{ + _state = STATE::STOP; + ScheduleNow(); +} + +void AFBRS50::print_info() +{ + perf_print_counter(_sample_perf); +} + +namespace afbrs50 +{ + +static int start(const uint8_t rotation) +{ + if (g_dev != nullptr) { + PX4_ERR("already started"); + return PX4_ERROR; + } + + g_dev = new AFBRS50(rotation); + + if (g_dev == nullptr) { + PX4_ERR("object instantiate failed"); + return PX4_ERROR; + } + + // Initialize the sensor. + if (g_dev->init() != PX4_OK) { + PX4_ERR("driver start failed"); + delete g_dev; + g_dev = nullptr; + return PX4_ERROR; + } + + return PX4_OK; +} + +static int status() +{ + if (g_dev == nullptr) { + PX4_ERR("driver not running"); + return PX4_ERROR; + } + + g_dev->print_info(); + + return PX4_OK; +} + +static int stop() +{ + if (g_dev != nullptr) { + delete g_dev; + g_dev = nullptr; + + } + + PX4_INFO("driver stopped"); + return PX4_OK; +} + +static int usage() +{ + PRINT_MODULE_DESCRIPTION( + R"DESCR_STR( +### Description + +Driver for the Broadcom AFBRS50. + +### Examples + +Attempt to start driver on a specified serial device. +$ afbrs50 start +Stop driver +$ afbrs50 stop +)DESCR_STR"); + + PRINT_MODULE_USAGE_NAME("afbrs50", "driver"); + PRINT_MODULE_USAGE_SUBCATEGORY("distance_sensor"); + PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start driver"); + PRINT_MODULE_USAGE_PARAM_STRING('d', nullptr, nullptr, "Serial device", false); + PRINT_MODULE_USAGE_PARAM_INT('r', 25, 0, 25, "Sensor rotation - downward facing by default", true); + PRINT_MODULE_USAGE_COMMAND_DESCR("stop", "Stop driver"); + return PX4_OK; +} + +} // namespace + +extern "C" __EXPORT int afbrs50_main(int argc, char *argv[]) +{ + const char *myoptarg = nullptr; + + int ch = 0; + int myoptind = 1; + + uint8_t rotation = distance_sensor_s::ROTATION_DOWNWARD_FACING; + + while ((ch = px4_getopt(argc, argv, "d:r", &myoptind, &myoptarg)) != EOF) { + switch (ch) { + case 'r': + rotation = (uint8_t)atoi(myoptarg); + break; + + default: + PX4_WARN("Unknown option"); + return afbrs50::usage(); + } + } + + if (myoptind >= argc) { + return afbrs50::usage(); + } + + if (!strcmp(argv[myoptind], "start")) { + return afbrs50::start(rotation); + + } else if (!strcmp(argv[myoptind], "status")) { + return afbrs50::status(); + + } else if (!strcmp(argv[myoptind], "stop")) { + return afbrs50::stop(); + } + + return afbrs50::usage(); +} diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.hpp b/src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.hpp new file mode 100644 index 0000000000..651dc709d3 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.hpp @@ -0,0 +1,92 @@ +/**************************************************************************** + * + * Copyright (c) 2021 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file AFBRS50.hpp + * + * Driver for the Broadcom AFBR-S50 connected via SPI. + * + */ +#pragma once + +#include "argus.h" + +#include +#include +#include +#include +#include +#include + +using namespace time_literals; + +class AFBRS50 : public px4::ScheduledWorkItem +{ +public: + AFBRS50(const uint8_t device_orientation = distance_sensor_s::ROTATION_DOWNWARD_FACING); + ~AFBRS50() override; + + int init(); + + /** + * Diagnostics - print some basic information about the driver. + */ + void print_info(); + + /** + * Stop the automatic measurement state machine. + */ + void stop(); + +private: + void Run() override; + + void ProcessMeasurement(void *data); + + static status_t measurement_ready_callback(status_t status, void *data); + + argus_hnd_t *_hnd{nullptr}; + + enum class STATE : uint8_t { + TEST, + CONFIGURE, + COLLECT, + STOP + } _state{STATE::CONFIGURE}; + + PX4Rangefinder _px4_rangefinder; + + hrt_abstime _measurement_time{0}; + + perf_counter_t _sample_perf{perf_alloc(PC_INTERVAL, MODULE_NAME": sample interval")}; +}; diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/irq.h b/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/irq.h new file mode 100644 index 0000000000..6992ce34e4 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/irq.h @@ -0,0 +1,35 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides functionality to globally turn IRQs on/off. + * + * @copyright Copyright c 2016-2019, Avago Technologies GmbH. + * All rights reserved. + * + *****************************************************************************/ + +#ifndef IRQ_H +#define IRQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup IRQ IRQ: Global Interrupt Control + * @ingroup driver + * @brief Global IRQ Module + * @details This module provides functionality to globally enable/disable + * interrupts by turning the I-bit in the CPSR on/off. + * @addtogroup IRQ + * @{ + *****************************************************************************/ + +#include "platform/argus_irq.h" + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif /* IRQ_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/s2pi.h b/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/s2pi.h new file mode 100644 index 0000000000..747d16f402 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/s2pi.h @@ -0,0 +1,107 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides an interface for the required S2PI module. + * + * @copyright Copyright c 2016-2019, Avago Technologies GmbH. + * All rights reserved. + * + *****************************************************************************/ + +#ifndef S2PI_H +#define S2PI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup SPI SPI: Serial Peripheral Interface + * @ingroup driver + * @brief S2PI: SPI incl. GPIO Hardware Layer Module + * + * @details Provides driver functionality for the S2PI interface module. + * + * The S2PI module consists of a standard SPI interface plus a + * single GPIO interrupt line. Furthermore, the SPI pins are + * accessible via GPIO control to allow a software emulation of + * additional protocols using the same pins. + * + * This module actually implements the #argus_s2pi interface that + * is required for the Argus API. Refer to the module for more + * information. + * + * @addtogroup SPI + * @{ + *****************************************************************************/ + +#include "platform/argus_s2pi.h" + + +/*! Enables the SPI slaves that utilize a GPIO pin for chip select. */ +#define S2PI_GPIO_SLAVES 0 + +/*! The S2PI slaves. */ +enum S2PISlaves { + /*! No SPI slave selected (all pins are disabled w/ high z state). */ + S2PI_NONE = 0, + + /*! The S2PI slave 1 (connected via adapter board). */ + S2PI_S1 = 1, + + /*! The S2PI slave 2 (connected via cable). */ + S2PI_S2 = 2, + +#if S2PI_GPIO_SLAVES + + /*! The S2PI slave 3. */ + S2PI_S3 = 3, + + /*! The S2PI slave 4. */ + S2PI_S4 = 4, + + /*! The experimental S2PI slave 1 w/ GPIO CS + * (connected via adapter board). */ + S2PI_S1_GPIO = 5, + + /*! The experimental S2PI slave 2 w/ GPIO CS + * (connected via cable). */ + S2PI_S2_GPIO = 6, + +#endif + + /*! No SPI slave selected (all pins go to low state). */ + S2PI_PINS_LOW = 0xFFU, +}; + + +/*!*************************************************************************** + * @brief Initializes the S2PI module. + * + * @details Setup the board as a S2PI master, this also sets up up the S2PI pins. + * The SPI interface is initialized with the corresponding default + * SPI slave (i.e. CS and IRQ lines) and the default baud rate. + * + * @param defaultSlave The default SPI slave to be addressed right after + * module initialization. + * @param baudRate_Bps The default SPI baud rate in bauds-per-second. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_Init(s2pi_slave_t defaultSlave, uint32_t baudRate_Bps); + +/*!*************************************************************************** + * @brief Sets the SPI baud rate in bps. + * @param baudRate_Bps The default SPI baud rate in bauds-per-second. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + * - #STATUS_OK on success + * - #ERROR_S2PI_INVALID_BAUD_RATE on invalid baud rate value. + *****************************************************************************/ +status_t S2PI_SetBaudRate(uint32_t baudRate_Bps); + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif // S2PI_H diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/timer.h b/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/timer.h new file mode 100644 index 0000000000..538b8f8c2e --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/API/Inc/timer.h @@ -0,0 +1,52 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides driver functionality for PIT (periodic interrupt timer). + * + * @copyright Copyright c 2016-2019, Avago Technologies GmbH. + * All rights reserved. + * + *****************************************************************************/ + +#ifndef TIMER_H +#define TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup timer Timer Module + * @ingroup driver + * @brief Timer Hardware Driver Module + * @details Provides driver functionality for the timer peripherals. + * This module actually implements the #argus_timer interface that + * is required for the Argus API. It contains two timing + * functionalities: A periodic interrupt/callback timer and + * an lifetime counter. + * + * Note that the current implementation only features a single + * callback timer interval and does not yet support the feature + * of multiple intervalls at a time. + * + * @addtogroup timer + * @{ + *****************************************************************************/ + +/******************************************************************************* + * Include Files + ******************************************************************************/ + +#include "platform/argus_timer.h" + +/*!*************************************************************************** + * @brief Initializes the timer hardware. + *****************************************************************************/ +void Timer_Init(void); + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif /* TIMER_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/irq.c b/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/irq.c new file mode 100644 index 0000000000..833cf9d486 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/irq.c @@ -0,0 +1,24 @@ + +#include + +static volatile irqstate_t irqstate_flags; + +/*!*************************************************************************** +* @brief Enable IRQ Interrupts +* +* @return - +*****************************************************************************/ +void IRQ_UNLOCK(void) +{ + leave_critical_section(irqstate_flags); +} + +/*!*************************************************************************** +* @brief Disable IRQ Interrupts +* +* @return - +*****************************************************************************/ +void IRQ_LOCK(void) +{ + irqstate_flags = enter_critical_section(); +} diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/s2pi.c b/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/s2pi.c new file mode 100644 index 0000000000..7aac79a5e3 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/s2pi.c @@ -0,0 +1,431 @@ + + +#include "irq.h" +#include "s2pi.h" + +#include + +#include + +#include + +#include +#include + +#include + +/*! A structure to hold all internal data required by the S2PI module. */ +typedef struct { + /*! Determines the current driver status. */ + volatile status_t Status; + + /*! Determines the current S2PI slave. */ + volatile s2pi_slave_t Slave; + + /*! A callback function to be called after transfer/run mode is completed. */ + s2pi_callback_t Callback; + + /*! A parameter to be passed to the callback function. */ + void *CallbackData; + + /*! A callback function to be called after external interrupt is triggered. */ + s2pi_irq_callback_t IrqCallback; + + /*! A parameter to be passed to the interrupt callback function. */ + void *IrqCallbackData; + + struct spi_dev_s *spidev; + uint8_t *spi_tx_data; + uint8_t *spi_rx_data; + size_t spi_frame_size; + + /*! The mapping of the GPIO blocks and pins for this device. */ + const uint32_t GPIOs[ S2PI_IRQ + 1 ]; +} +s2pi_handle_t; + +s2pi_handle_t s2pi_ = { .GPIOs = { [ S2PI_CLK ] = BROADCOM_AFBR_S50_S2PI_CLK, + [ S2PI_CS ] = BROADCOM_AFBR_S50_S2PI_CS, + [ S2PI_MOSI ] = BROADCOM_AFBR_S50_S2PI_MOSI, + [ S2PI_MISO ] = BROADCOM_AFBR_S50_S2PI_MISO, + [ S2PI_IRQ ] = BROADCOM_AFBR_S50_S2PI_IRQ + } + }; + +static struct work_s broadcom_s2pi_transfer_work = {}; + +static perf_counter_t s2pi_transfer_perf = NULL; +static perf_counter_t s2pi_transfer_callback_perf = NULL; +static perf_counter_t s2pi_irq_callback_perf = NULL; + +/*!*************************************************************************** +* @brief Initialize the S2PI module. +* @details Setup the board as a S2PI master, this also sets up up the S2PI +* pins. +* The SPI interface is initialized with the corresponding default +* SPI slave (i.e. CS and IRQ lines) and the default baud rate. +* +* @param defaultSlave The default SPI slave to be addressed right after +* module initialization. +* @param baudRate_Bps The default SPI baud rate in bauds-per-second. +* +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ + +static int gpio_falling_edge(int irq, void *context, void *arg) +{ + if (s2pi_.IrqCallback != 0) { + perf_begin(s2pi_irq_callback_perf); + s2pi_.IrqCallback(s2pi_.IrqCallbackData); + perf_end(s2pi_irq_callback_perf); + } + + return 0; +} + +status_t S2PI_Init(s2pi_slave_t defaultSlave, uint32_t baudRate_Bps) +{ + px4_arch_configgpio(BROADCOM_AFBR_S50_S2PI_CS); + + s2pi_.spidev = px4_spibus_initialize(BROADCOM_AFBR_S50_S2PI_SPI_BUS); + + px4_arch_configgpio(BROADCOM_AFBR_S50_S2PI_IRQ); + px4_arch_gpiosetevent(BROADCOM_AFBR_S50_S2PI_IRQ, false, true, false, &gpio_falling_edge, NULL); + + s2pi_transfer_perf = perf_alloc(PC_ELAPSED, MODULE_NAME": transfer"); + s2pi_transfer_callback_perf = perf_alloc(PC_ELAPSED, MODULE_NAME": transfer callback"); + s2pi_irq_callback_perf = perf_alloc(PC_ELAPSED, MODULE_NAME": irq callback"); + + return S2PI_SetBaudRate(baudRate_Bps); +} + +/*!*************************************************************************** +* @brief Returns the status of the SPI module. +* +* @return Returns the \link #status_t status\endlink: +* - #STATUS_IDLE: No SPI transfer or GPIO access is ongoing. +* - #STATUS_BUSY: An SPI transfer is in progress. +* - #STATUS_S2PI_GPIO_MODE: The module is in GPIO mode. +*****************************************************************************/ +status_t S2PI_GetStatus(void) +{ + return s2pi_.Status; +} + +/*!*************************************************************************** +* @brief Sets the SPI baud rate in bps. +* @param baudRate_Bps The default SPI baud rate in bauds-per-second. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +* - #STATUS_OK on success +* - #ERROR_S2PI_INVALID_BAUD_RATE on invalid baud rate value. +*****************************************************************************/ +status_t S2PI_SetBaudRate(uint32_t baudRate_Bps) +{ + SPI_SETMODE(s2pi_.spidev, SPIDEV_MODE3); + SPI_SETBITS(s2pi_.spidev, 8); + SPI_SETFREQUENCY(s2pi_.spidev, baudRate_Bps); + return STATUS_OK; +} + +/*!***************************************************************************** +* @brief Captures the S2PI pins for GPIO usage. +* @details The SPI is disabled (module status: #STATUS_S2PI_GPIO_MODE) and the +* pins are configured for GPIO operation. The GPIO control must be +* release with the #S2PI_ReleaseGpioControl function in order to +* switch back to ordinary SPI functionality. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t S2PI_CaptureGpioControl(void) +{ + /* Check if something is ongoing. */ + IRQ_LOCK(); + status_t status = s2pi_.Status; + + if (status != STATUS_IDLE) { + IRQ_UNLOCK(); + return status; + } + + s2pi_.Status = STATUS_S2PI_GPIO_MODE; + IRQ_UNLOCK(); + + // GPIO mode (output push pull) + px4_arch_configgpio(PX4_MAKE_GPIO_OUTPUT_SET(s2pi_.GPIOs[S2PI_CLK])); + px4_arch_configgpio(PX4_MAKE_GPIO_OUTPUT_SET(s2pi_.GPIOs[S2PI_MISO])); + px4_arch_configgpio(PX4_MAKE_GPIO_OUTPUT_SET(s2pi_.GPIOs[S2PI_MOSI])); + + return STATUS_OK; +} + +/*!***************************************************************************** +* @brief Releases the S2PI pins from GPIO usage and switches back to SPI mode. +* @details The GPIO pins are configured for SPI operation and the GPIO mode is +* left. Must be called if the pins are captured for GPIO operation via +* the #S2PI_CaptureGpioControl function. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t S2PI_ReleaseGpioControl(void) +{ + /* Check if something is ongoing. */ + IRQ_LOCK(); + status_t status = s2pi_.Status; + + if (status != STATUS_S2PI_GPIO_MODE) { + IRQ_UNLOCK(); + return status; + } + + s2pi_.Status = STATUS_IDLE; + IRQ_UNLOCK(); + + // SPI alternate + stm32_configgpio(s2pi_.GPIOs[S2PI_CLK]); + stm32_configgpio(s2pi_.GPIOs[S2PI_MISO]); + stm32_configgpio(s2pi_.GPIOs[S2PI_MOSI]); + + // probably not necessary + stm32_spibus_initialize(BROADCOM_AFBR_S50_S2PI_SPI_BUS); + + return STATUS_OK; +} + +/*!***************************************************************************** +* @brief Writes the output for a specified SPI pin in GPIO mode. +* @details This function writes the value of an SPI pin if the SPI pins are +* captured for GPIO operation via the #S2PI_CaptureGpioControl previously. +* @param slave The specified S2PI slave. +* @param pin The specified S2PI pin. +* @param value The GPIO pin state to write (0 = low, 1 = high). +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t S2PI_WriteGpioPin(s2pi_slave_t slave, s2pi_pin_t pin, uint32_t value) +{ + /* Check if pin is valid. */ + if (pin > S2PI_IRQ || value > 1) { + return ERROR_INVALID_ARGUMENT; + } + + /* Check if in GPIO mode. */ + if (s2pi_.Status != STATUS_S2PI_GPIO_MODE) { + return ERROR_S2PI_INVALID_STATE; + } + + px4_arch_gpiowrite(s2pi_.GPIOs[pin], value); + + return STATUS_OK; +} + +/*!***************************************************************************** +* @brief Reads the input from a specified SPI pin in GPIO mode. +* @details This function reads the value of an SPI pin if the SPI pins are +* captured for GPIO operation via the #S2PI_CaptureGpioControl previously. +* @param slave The specified S2PI slave. +* @param pin The specified S2PI pin. +* @param value The GPIO pin state to read (0 = low, 1 = high). +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t S2PI_ReadGpioPin(s2pi_slave_t slave, s2pi_pin_t pin, uint32_t *value) +{ + /* Check if pin is valid. */ + if (pin > S2PI_IRQ || !value) { + return ERROR_INVALID_ARGUMENT; + } + + /* Check if in GPIO mode. */ + if (s2pi_.Status != STATUS_S2PI_GPIO_MODE) { + return ERROR_S2PI_INVALID_STATE; + } + + *value = px4_arch_gpioread(s2pi_.GPIOs[pin]); + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Cycles the chip select line. +* @details In order to cancel the integration on the ASIC, a fast toggling +* of the chip select pin of the corresponding SPI slave is required. +* Therefore, this function toggles the CS from high to low and back. +* The SPI instance for the specified S2PI slave must be idle, +* otherwise the status #STATUS_BUSY is returned. +* @param slave The specified S2PI slave. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t S2PI_CycleCsPin(s2pi_slave_t slave) +{ + /* Check the driver status. */ + IRQ_LOCK(); + status_t status = s2pi_.Status; + + if (status != STATUS_IDLE) { + IRQ_UNLOCK(); + return status; + } + + s2pi_.Status = STATUS_BUSY; + IRQ_UNLOCK(); + + px4_arch_gpiowrite(s2pi_.GPIOs[S2PI_CS], 0); + px4_arch_gpiowrite(s2pi_.GPIOs[S2PI_CS], 1); + + s2pi_.Status = STATUS_IDLE; + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Transfers a single SPI frame asynchronously. +* @details Transfers a single SPI frame in asynchronous manner. The Tx data +* buffer is written to the device via the MOSI line. +* Optionally the data on the MISO line is written to the provided +* Rx data buffer. If null, the read data is dismissed. +* The transfer of a single frame requires to not toggle the chip +* select line to high in between the data frame. +* An optional callback is invoked when the asynchronous transfer +* is finished. Note that the provided buffer must not change while +* the transfer is ongoing. Use the slave parameter to determine +* the corresponding slave via the given chip select line. +* +* @param slave The specified S2PI slave. +* @param txData The 8-bit values to write to the SPI bus MOSI line. +* @param rxData The 8-bit values received from the SPI bus MISO line +* (pass a null pointer if the data don't need to be read). +* @param frameSize The number of 8-bit values to be sent/received. +* @param callback A callback function to be invoked when the transfer is +* finished. Pass a null pointer if no callback is required. +* @param callbackData A pointer to a state that will be passed to the +* callback. Pass a null pointer if not used. +* +* @return Returns the \link #status_t status\endlink: +* - #STATUS_OK: Successfully invoked the transfer. +* - #ERROR_INVALID_ARGUMENT: An invalid parameter has been passed. +* - #ERROR_S2PI_INVALID_SLAVE: A wrong slave identifier is provided. +* - #STATUS_BUSY: An SPI transfer is already in progress. The +* transfer was not started. +* - #STATUS_S2PI_GPIO_MODE: The module is in GPIO mode. The transfer +* was not started. +*****************************************************************************/ + +static void broadcom_s2pi_transfer_callout(void *arg) +{ + perf_begin(s2pi_transfer_perf); + px4_arch_gpiowrite(s2pi_.GPIOs[S2PI_CS], 0); + SPI_EXCHANGE(s2pi_.spidev, s2pi_.spi_tx_data, s2pi_.spi_rx_data, s2pi_.spi_frame_size); + s2pi_.Status = STATUS_IDLE; + px4_arch_gpiowrite(s2pi_.GPIOs[S2PI_CS], 1); + perf_end(s2pi_transfer_perf); + + /* Invoke callback if there is one */ + if (s2pi_.Callback != 0) { + perf_begin(s2pi_transfer_callback_perf); + s2pi_callback_t callback = s2pi_.Callback; + s2pi_.Callback = 0; + callback(STATUS_OK, s2pi_.CallbackData); + perf_end(s2pi_transfer_callback_perf); + } +} + +status_t S2PI_TransferFrame(s2pi_slave_t spi_slave, uint8_t const *txData, uint8_t *rxData, size_t frameSize, + s2pi_callback_t callback, void *callbackData) +{ + /* Verify arguments. */ + if (!txData || frameSize == 0 || frameSize >= 0x10000) { + return ERROR_INVALID_ARGUMENT; + } + + /* Check the spi slave.*/ + if (spi_slave != S2PI_S2) { + return ERROR_S2PI_INVALID_SLAVE; + } + + /* Check the driver status, lock if idle. */ + IRQ_LOCK(); + status_t status = s2pi_.Status; + + if (status != STATUS_IDLE) { + IRQ_UNLOCK(); + return status; + } + + s2pi_.Status = STATUS_BUSY; + + /* Set the callback information */ + s2pi_.Callback = callback; + s2pi_.CallbackData = callbackData; + + s2pi_.spi_tx_data = (uint8_t *)txData; + s2pi_.spi_rx_data = rxData; + s2pi_.spi_frame_size = frameSize; + work_queue(HPWORK, &broadcom_s2pi_transfer_work, broadcom_s2pi_transfer_callout, NULL, 0); + + IRQ_UNLOCK(); + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Terminates a currently ongoing asynchronous SPI transfer. +* @details When a callback is set for the current ongoing activity, it is +* invoked with the #ERROR_ABORTED error byte. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t S2PI_Abort(void) +{ + status_t status = s2pi_.Status; + + /* Check if something is ongoing. */ + if (status == STATUS_IDLE) { + return STATUS_OK; + } + + /* Abort SPI transfer. */ + if (status == STATUS_BUSY) { + work_cancel(HPWORK, &broadcom_s2pi_transfer_work); + } + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Set a callback for the GPIO IRQ for a specified S2PI slave. +* +* @param slave The specified S2PI slave. +* @param callback A callback function to be invoked when the specified +* S2PI slave IRQ occurs. Pass a null pointer to disable +* the callback. +* @param callbackData A pointer to a state that will be passed to the +* callback. Pass a null pointer if not used. +* +* @return Returns the \link #status_t status\endlink: +* - #STATUS_OK: Successfully installation of the callback. +* - #ERROR_S2PI_INVALID_SLAVE: A wrong slave identifier is provided. +*****************************************************************************/ +status_t S2PI_SetIrqCallback(s2pi_slave_t slave, s2pi_irq_callback_t callback, void *callbackData) +{ + s2pi_.IrqCallback = callback; + s2pi_.IrqCallbackData = callbackData; + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Reads the current status of the IRQ pin. +* @details In order to keep a low priority for GPIO IRQs, the state of the +* IRQ pin must be read in order to reliable check for chip timeouts. +* +* The execution of the interrupt service routine for the data-ready +* interrupt from the corresponding GPIO pin might be delayed due to +* priority issues. The delayed execution might disable the timeout +* for the eye-safety checker too late causing false error messages. +* In order to overcome the issue, the state of the IRQ GPIO input +* pin is read before raising a timeout error in order to check if +* the device has already finished but the IRQ is still pending to be +* executed! +* @param slave The specified S2PI slave. +* @return Returns 1U if the IRQ pin is high (IRQ not pending) and 0U if the +* devices pulls the pin to low state (IRQ pending). +*****************************************************************************/ +uint32_t S2PI_ReadIrqPin(s2pi_slave_t slave) +{ + return px4_arch_gpioread(s2pi_.GPIOs[S2PI_IRQ]); +} diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/timer.c b/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/timer.c new file mode 100644 index 0000000000..d627f0490b --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/API/Src/timer.c @@ -0,0 +1,138 @@ + +#include "timer.h" + +#include + +#include + +#include + +static struct hrt_call broadcom_hrt_call = {}; + +static timer_cb_t timer_callback_; /*! Callback function for PIT timer */ + +static uint32_t period_us_; + +/*! Storage for the callback parameter */ +static void *callback_param_; + +static void broadcom_hrt_callout(void *arg) +{ + if (timer_callback_ != 0) { + //timer_callback_(arg); + timer_callback_(callback_param_); + hrt_call_after(&broadcom_hrt_call, period_us_, broadcom_hrt_callout, callback_param_); + } +} + +void Timer_Init(void) +{ + hrt_cancel(&broadcom_hrt_call); +} + +/*!*************************************************************************** +* @brief Obtains the lifetime counter value from the timers. +* +* @details The function is required to get the current time relative to any +* point in time, e.g. the startup time. The returned values \p hct and +* \p lct are given in seconds and microseconds respectively. The current +* elapsed time since the reference time is then calculated from: +* +* t_now [usec] = hct * 1000000 usec + lct * 1 usec +* +* @param hct A pointer to the high counter value bits representing current +* time in seconds. +* @param lct A pointer to the low counter value bits representing current +* time in microseconds. Range: 0, .., 999999 usec +* @return - +*****************************************************************************/ + +void Timer_GetCounterValue(uint32_t *hct, uint32_t *lct) +{ + hrt_abstime time = hrt_absolute_time(); + *hct = time / 1000000ULL; + *lct = time - (*hct * 1000000ULL); +} + +/*!*************************************************************************** +* @brief Starts the timer for a specified callback parameter. +* @details Sets the callback interval for the specified parameter and starts +* the timer with a new interval. If there is already an interval with +* the given parameter, the timer is restarted with the given interval. +* Passing a interval of 0 disables the timer. +* @param dt_microseconds The callback interval in microseconds. +* @param param An abstract parameter to be passed to the callback. This is +* also the identifier of the given interval. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ + +status_t Timer_Start(uint32_t period, void *param) +{ + callback_param_ = param; + period_us_ = period; + + if (period != 0) { + hrt_call_after(&broadcom_hrt_call, period, broadcom_hrt_callout, param); + + } else { + hrt_cancel(&broadcom_hrt_call); + } + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Stops the timer for a specified callback parameter. +* @details Stops a callback interval for the specified parameter. +* @param param An abstract parameter that identifies the interval to be stopped. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t Timer_Stop(void *param) +{ + period_us_ = 0; + callback_param_ = 0; + hrt_cancel(&broadcom_hrt_call); + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Sets the timer interval for a specified callback parameter. +* @details Sets the callback interval for the specified parameter and starts +* the timer with a new interval. If there is already an interval with +* the given parameter, the timer is restarted with the given interval. +* If the same time interval as already set is passed, nothing happens. +* Passing a interval of 0 disables the timer. +* @param dt_microseconds The callback interval in microseconds. +* @param param An abstract parameter to be passed to the callback. This is +* also the identifier of the given interval. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ +status_t Timer_SetInterval(uint32_t dt_microseconds, void *param) +{ + if (dt_microseconds != 0) { + period_us_ = dt_microseconds; + hrt_call_after(&broadcom_hrt_call, dt_microseconds, broadcom_hrt_callout, param); + + } else { + hrt_cancel(&broadcom_hrt_call); + } + + return STATUS_OK; +} + +/*!*************************************************************************** +* @brief Installs an periodic timer callback function. +* @details Installs an periodic timer callback function that is invoked whenever +* an interval elapses. The callback is the same for any interval, +* however, the single intervals can be identified by the passed +* parameter. +* Passing a zero-pointer removes and disables the callback. +* @param f The timer callback function. +* @return Returns the \link #status_t status\endlink (#STATUS_OK on success). +*****************************************************************************/ + +status_t Timer_SetCallback(timer_cb_t f) +{ + timer_callback_ = f; + return STATUS_OK; +} diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/CMakeLists.txt b/src/drivers/distance_sensor/broadcom/afbrs50/CMakeLists.txt new file mode 100644 index 0000000000..8073128881 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/CMakeLists.txt @@ -0,0 +1,59 @@ +############################################################################ +# +# Copyright (c) 2021 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +add_library(afbrs50_m4_fpu STATIC IMPORTED GLOBAL) +set_property(TARGET afbrs50_m4_fpu PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/Lib/libafbrs50_m4_fpu.a) + +px4_add_module( + MODULE drivers__distance_sensor__afbrs50 + MAIN afbrs50 + COMPILE_FLAGS + STACK_MAIN + 4096 + INCLUDES + API/Inc + Inc + SRCS + AFBRS50.cpp + AFBRS50.hpp + API/Src/irq.c + API/Src/s2pi.c + API/Src/timer.c + argus_hal_test.c + DEPENDS + px4_work_queue + drivers_rangefinder + afbrs50_m4_fpu + ) + +target_link_libraries(afbrs50_m4_fpu INTERFACE drivers__distance_sensor__afbrs50) diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_api.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_api.h new file mode 100644 index 0000000000..598b33375c --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_api.h @@ -0,0 +1,1185 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides generic functionality belonging to all + * devices from the AFBR-S50 product family. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_API_H +#define ARGUS_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup argusapi AFBR-S50 API + * + * @brief The main module of the API from the AFBR-S50 SDK. + * + * @details General API for the AFBR-S50 time-of-flight sensor device family. + * + * @addtogroup argusapi + * @{ + *****************************************************************************/ + +#include "argus_def.h" +#include "argus_res.h" +#include "argus_pba.h" +#include "argus_dfm.h" +#include "argus_snm.h" +#include "argus_xtalk.h" + +/*! The data structure for the API representing a AFBR-S50 device instance. */ +typedef void argus_hnd_t; + +/*! The S2PI slave identifier. */ +typedef int32_t s2pi_slave_t; + +/*!*************************************************************************** + * @brief Initializes the API modules and the device with default parameters. + * + * @details The function that needs to be called once after power up to + * initialize the modules state (i.e. the corresponding handle) and the + * dedicated Time-of-Flight device. In order to obtain a handle, + * reference the #Argus_CreateHandle method. + * + * Prior to calling the function, the required peripherals (i.e. S2PI, + * GPIO w/ IRQ and Timers) must be initialized and ready to use. + * + * The function executes the following tasks: + * - Initialization of the internal state represented by the handle + * object. + * - Setup the device such that an safe configuration is present in + * the registers. + * - Initialize sub modules such as calibration or measurement modules. + * . + * + * The modules configuration is initialized with reasonable default values. + * + * @param hnd The API handle; contains all internal states and data. + * + * @param spi_slave The SPI hardware slave, i.e. the specified CS and IRQ + * lines. This is actually just a number that is passed + * to the SPI interface to distinct for multiple SPI slave + * devices. Note that the slave must be not equal to 0, + * since is reserved for error handling. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_Init(argus_hnd_t *hnd, s2pi_slave_t spi_slave); + +/*!*************************************************************************** + * @brief Reinitializes the API modules and the device with default parameters. + * + * @details The function reinitializes the device with default configuration. + * Can be used as reset sequence for the device. See #Argus_Init for + * more information on the initialization. + * + * Note that the #Argus_Init function must be called first! Otherwise, + * the function will return an error if it is called for an yet + * uninitialized device/handle. + * + * @param hnd The API handle; contains all internal states and data. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_Reinit(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Deinitializes the API modules and the device. + * + * @details The function deinitializes the device and clear all internal states. + * Can be used to cleanup before releaseing the memory. The device + * can not be used any more and must be initialized again prior to next + * usage. + * + * Note that the #Argus_Init function must be called first! Otherwise, + * the function will return an error if it is called for an yet + * uninitialized device/handle. + * + * @param hnd The API handle; contains all internal states and data. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_Deinit(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Creates a new device data handle object to store all internal states. + * + * @details The function must be called to obtain a new device handle object. + * The handle is basically an abstract object in memory that contains + * all the internal states and settings of the API module. The handle + * is passed to all the API methods in order to address the specified + * device. This allows to use the API with more than a single measurement + * device. + * + * The handler is created by calling the memory allocation method from + * the standard library: @code void * malloc(size_t size) @endcode + * In order to implement an individual memory allocation method, + * define and implement the following weakly binded method and return + * a pointer to the newly allocated memory. * + * @code void * Argus_Malloc (size_t size) @endcode + * Also see the #Argus_DestroyHandle method for the corresponding + * deallocation of the allocated memory. + * + * @return Returns a pointer to the newly allocated device handler object. + * Returns a null pointer if the allocation failed! + *****************************************************************************/ +argus_hnd_t *Argus_CreateHandle(void); + +/*!*************************************************************************** + * @brief Destroys a given device data handle object. + * + * @details The function can be called to free the previously created device + * data handle object in order to save memory when the device is not + * used any more. + * + * Please refer to the #Argus_CreateHandle method for the corresponding + * allocation of the memory. + * + * The handler is destroyed by freeing the corresponding memory with the + * method from the standard library, @code void free(void * ptr) @endcode. + * In order to implement an individual memory deallocation method, define + * and implement the following weakly binded method and free the memory + * object passed to the method by a pointer. + * + * @code void Argus_Free (void * ptr) @endcode + * + * @param hnd The device handle object to be deallocated. + *****************************************************************************/ +void Argus_DestroyHandle(argus_hnd_t *hnd); + +/*!************************************************************************** + * Generic API + ****************************************************************************/ + +/*!*************************************************************************** + * @brief Gets the version number of the current API library. + * + * @details The version is compiled of a major (a), minor (b) and bugfix (c) + * number: a.b.c. + * + * The values are encoded into a 32-bit value: + * + * - [ 31 .. 24 ] - Major Version Number + * - [ 23 .. 16 ] - Minor Version Number + * - [ 15 .. 0 ] - Bugfix Version Number + * . + * + * To obtain the parts from the returned uin32_t value: + * + * @code + * uint32_t value = Argus_GetAPIVersion(); + * uint8_t a = (value >> 24) & 0xFFU; + * uint8_t b = (value >> 16) & 0xFFU; + * uint8_t c = value & 0xFFFFU; + * @endcode + * + * @return Returns the current version number. + *****************************************************************************/ +uint32_t Argus_GetAPIVersion(void); + +/*!*************************************************************************** + * @brief Gets the build number of the current API library. + * + * @return Returns the current build number as a C-string. + *****************************************************************************/ +char const *Argus_GetBuildNumber(void); + +/*!*************************************************************************** + * @brief Gets the version/variant of the module. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the current module number. + *****************************************************************************/ +argus_module_version_t Argus_GetModuleVersion(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Gets the version number of the chip. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the current version number. + *****************************************************************************/ +argus_chip_version_t Argus_GetChipVersion(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Gets the type number of the device laser. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the current device laser type number. + *****************************************************************************/ +argus_laser_type_t Argus_GetLaserType(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Gets the unique identification number of the chip. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the unique identification number. + *****************************************************************************/ +uint32_t Argus_GetChipID(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Gets the SPI hardware slave identifier. + * + * @param hnd The API handle; contains all internal states and data. + * @return The SPI hardware slave identifier. + *****************************************************************************/ +s2pi_slave_t Argus_GetSPISlave(argus_hnd_t *hnd); + +/*! @} */ + +/*!************************************************************************** + * Measurement/Device Operation + **************************************************************************** + * @addtogroup argusmeas + * @{ + ****************************************************************************/ + +/*!*************************************************************************** + * @brief Starts the timer based measurement cycle asynchronously. + * + * @details This function starts a timer based measurement cycle asynchronously. + * in the background. A periodic timer interrupt triggers the measurement + * frames on the ASIC and the data readout afterwards. When the frame is + * finished, a callback (which is passed as a parameter to the function) + * is invoked in order to inform the main thread to call the \link + * #Argus_EvaluateData data evaluation method\endlink. This call is + * mandatory to release the data buffer for the next measurement cycle + * and it must not be invoked from the callback since it is within an + * interrupt service routine. Rather a flag should inform the main thread + * to invoke the evaluation as soon as possible in order to not introduce + * any unwanted delays to the next measurement frame. + * The next measurement frame will be started as soon as the pre- + * conditions are meet. These are: + * 1. timer flag set (i.e. a certain time has passed since the last + * measurement in order to fulfill eye-safety), + * 2. device idle (i.e. no measurement currently ongoing) and + * 3. data buffer ready (i.e. the previous data has been evaluated). + * Usually, the device idle and data buffer ready conditions are met + * before the timer tick occurs and thus the timer dictates the frame + * rate. + * + * The callback function pointer will be invoked when the measurement + * frame has finished successfully or whenever an error, that cannot + * be handled internally, occurs. + * + * The periodic timer interrupts are used to check the measurement status + * for timeouts. An error is invoked when a measurement cycle have not + * finished within the specified time. + * + * Use #Argus_StopMeasurementTimer to stop the measurements. + * + * @note In order to use this function, the periodic interrupt timer module + * (see @ref argus_timer) must be implemented! + * + * @param hnd The API handle; contains all internal states and data. + * @param cb Callback function that will be invoked when the measurement + * is completed. Its parameters are the \link #status_t status + * \endlink and a pointer to the \link #argus_results_t results + * \endlink structure. If an error occurred, the status differs + * from #STATUS_OK and the second parameter is null. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_StartMeasurementTimer(argus_hnd_t *hnd, argus_callback_t cb); + +/*!*************************************************************************** + * @brief Stops the timer based measurement cycle. + * + * @details This function stops the ongoing timer based measurement cycles + * that have been started using the #Argus_StartMeasurementTimer + * function. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_StopMeasurementTimer(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Triggers a single measurement frame asynchronously. + * + * @details This function immediately triggers a single measurement frame + * asynchronously if all the pre-conditions are met. Otherwise it returns + * with a corresponding status. + * When the frame is finished, a callback (which is passed as a parameter + * to the function) is invoked in order to inform the main thread to + * call the \link #Argus_EvaluateData data evaluation method\endlink. + * This call is mandatory to release the data buffer for the next + * measurement and it must not be invoked from the callback since it is + * within an interrupt service routine. Rather a flag should inform + * the main thread to invoke the evaluation. + * The pre-conditions for starting a measurement frame are: + * 1. timer flag set (i.e. a certain time has passed since the last + * measurement in order to fulfill eye-safety), + * 2. device idle (i.e. no measurement currently ongoing) and + * 3. data buffer ready (i.e. the previous data has been evaluated). + * + * The callback function pointer will be invoked when the measurement + * frame has finished successfully or whenever an error, that cannot + * be handled internally, occurs. + * + * The successful finishing of the measurement frame is not checked + * for timeouts! Instead, the user can call the #Argus_GetStatus() + * function on a regular function to do so. + * + * @param hnd The API handle; contains all internal states and data. + * @param cb Callback function that will be invoked when the measurement + * is completed. Its parameters are the \link #status_t status + * \endlink and a pointer to the \link #argus_results_t results + * \endlink structure. If an error occurred, the status differs + * from #STATUS_OK and the second parameter is null. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_TriggerMeasurement(argus_hnd_t *hnd, argus_callback_t cb); + +/*!*************************************************************************** + * @brief Stops the currently ongoing measurements and SPI activity immediately. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_Abort(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Checks the state of the device/driver. + * + * @details Returns the current module state: + * + * Status: + * - Idle/OK: Device and SPI interface are idle (== #STATUS_IDLE). + * - Busy: Device or SPI interface are busy (== #STATUS_BUSY). + * - Initializing: The modules and devices are currently initializing + * (== #STATUS_INITIALIZING). + * . + * + * Error: + * - Not Initialized: The modules (or any submodule) has not been + * initialized yet (== #ERROR_NOT_INITIALIZED). + * - Not Connected: No device has been connected (or connection errors + * have occured) (== #ERROR_ARGUS_NOT_CONNECTED). + * - Timeout: A previous frame measurement has not finished within a + * specified time (== #ERROR_TIMEOUT). + * . + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetStatus(argus_hnd_t *hnd); + +/*!***************************************************************************** + * @brief Tests the connection to the device by sending a ping message. + * + * @details A ping is transfered to the device in order to check the device and + * SPI connection status. Returns #STATUS_OK on success and + * #ERROR_ARGUS_NOT_CONNECTED elsewise. + * + * @param hnd The API handle; contains all internal states and data. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + ******************************************************************************/ +status_t Argus_Ping(argus_hnd_t *hnd); + +/*!*************************************************************************** + * @brief Evaluate useful information from the raw measurement data. + * + * @details This function is called with a pointer to the raw results obtained + * from the measurement cycle. It evaluates this data and creates + * useful information from it. Furthermore, calibration is applied to + * the data. Finally, the results are used in order to adapt the device + * configuration to the ambient conditions in order to achieve optimal + * device performance.\n + * Therefore, it consists of the following sub-functions: + * - Apply pre-calibration: Applies calibration steps before evaluating + * the data, i.e. calculations that are to the integration results + * directly. + * - Evaluate data: Calculates measurement parameters such as range, + * amplitude or ambient light intensity, depending on the configurations. + * - Apply post-calibration: Applies calibrations after evaluation of + * measurement data, i.e. calibrations applied to the calculated + * values such as range. + * - Dynamic Configuration Adaption: checks if the configuration needs + * to be adjusted before the next measurement cycle in order to + * achieve optimum performance. Note that the configuration might not + * applied directly but before the next measurement starts. This is + * due to the fact that the device could be busy measuring already + * the next frame and thus no SPI activity is allowed. + * . + * However, if the device is idle, the configuration will be written + * immediately. + * + * @param hnd The API handle; contains all internal states and data. + * @param res A pointer to the results structure that will be populated + * with evaluated data. + * @param raw The pointer to the raw data that has been obtained by the + * measurement finished callback. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_EvaluateData(argus_hnd_t *hnd, argus_results_t *res, void *raw); + +/*!*************************************************************************** + * @brief Executes a crosstalk calibration measurement. + * + * @details This function immediately triggers a crosstalk vector calibration + * measurement sequence. The ordinary measurement activity is suspended + * while the calibration is ongoing. + * + * In order to perform a crosstalk calibration, the reflection of the + * transmitted signal must be kept from the receiver side, by either + * covering the TX completely (or RX respectively) or by setting up + * an absorbing target at far distance. + * + * After calibration has finished successfully, the obtained data is + * applied immediately and can be read from the API using the + * #Argus_GetCalibrationCrosstalkVectorTable function. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_ExecuteXtalkCalibrationSequence(argus_hnd_t *hnd, argus_mode_t mode); + + +/*!*************************************************************************** + * @brief Executes a relative range offset calibration measurement. + * + * @details This function immediately triggers a relative range offset calibration + * measurement sequence. The ordinary measurement activity is suspended + * while the calibration is ongoing. + * + * In order to perform a relative range offset calibration, a flat + * calibration target must be setup perpendicular to the sensors + * field-of-view. + * + * \code + * AFBR-S50 ToF Sensor + * #| + * #| | + * #|-----+ | + * #| Rx | | + * Reference #|----++ | Calibration + * Plane #| Tx | | Target + * #|----+ | + * #| | + * #| <------- targetRange -----------------> | + * \endcode + * + * There are two options to run the offset calibration: relative and + * absolute. + * - Relative (#Argus_ExecuteRelativeRangeOffsetCalibrationSequence): + * when the absolute distance is not essential or the distance to + * the calibration target is not known, the relative method can be + * used to compensate the relative pixel range offset w.r.t. the + * average range. The absolute or global range offset is not changed. + * - Absolute (#Argus_ExecuteAbsoluteRangeOffsetCalibrationSequence): + * when the absolute distance is essential and the distance to the + * calibration target is known, the absolute method can be used to + * calibrate the absolute measured distance. Additionally, the + * relative pixel offset w.r.t. the average range is also compensated. + * . + * + * After calibration has finished successfully, the obtained data is + * applied immediately and can be read from the API using the + * #Argus_GetCalibrationPixelRangeOffsets or + * #Argus_GetCalibrationGlobalRangeOffset function. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_ExecuteRelativeRangeOffsetCalibrationSequence(argus_hnd_t *hnd, + argus_mode_t mode); + +/*!*************************************************************************** + * @brief Executes an absolute range offset calibration measurement. + * + * @details This function immediately triggers an absolute range offset calibration + * measurement sequence. The ordinary measurement activity is suspended + * while the calibration is ongoing. + * + * In order to perform a relative range offset calibration, a flat + * calibration target must be setup perpendicular to the sensors + * field-of-view. + * + * \code + * AFBR-S50 ToF Sensor + * #| + * #| | + * #|-----+ | + * #| Rx | | + * Reference #|----++ | Calibration + * Plane #| Tx | | Target + * #|----+ | + * #| | + * #| <------- targetRange -----------------> | + * \endcode + * + * There are two options to run the offset calibration: relative and + * absolute. + * - Relative (#Argus_ExecuteRelativeRangeOffsetCalibrationSequence): + * when the absolute distance is not essential or the distance to + * the calibration target is not known, the relative method can be + * used to compensate the relative pixel range offset w.r.t. the + * average range. The absolute or global range offset is not changed. + * - Absolute (#Argus_ExecuteAbsoluteRangeOffsetCalibrationSequence): + * when the absolute distance is essential and the distance to the + * calibration target is known, the absolute method can be used to + * calibrate the absolute measured distance. Additionally, the + * relative pixel offset w.r.t. the average range is also compensated. + * . + * + * After calibration has finished successfully, the obtained data is + * applied immediately and can be read from the API using the + * #Argus_GetCalibrationPixelRangeOffsets or + * #Argus_GetCalibrationGlobalRangeOffset function. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param targetRange The absolute range between the reference plane and the + * calibration target in meter an Q9.22 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_ExecuteAbsoluteRangeOffsetCalibrationSequence(argus_hnd_t *hnd, + argus_mode_t mode, + q9_22_t targetRange); + +/*! @} */ + +/*!************************************************************************** + * Configuration API + **************************************************************************** + * @addtogroup arguscfg + * @{ + ****************************************************************************/ + +/*!*************************************************************************** + * @brief Sets the measurement mode to a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The new measurement mode. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationMeasurementMode(argus_hnd_t *hnd, + argus_mode_t value); + +/*!*************************************************************************** + * @brief Gets the measurement mode from a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The current measurement mode. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationMeasurementMode(argus_hnd_t *hnd, + argus_mode_t *value); + +/*!*************************************************************************** + * @brief Sets the frame time to a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The measurement frame time in microseconds. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationFrameTime(argus_hnd_t *hnd, uint32_t value); + +/*!*************************************************************************** + * @brief Gets the frame time from a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The current frame time in microseconds. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationFrameTime(argus_hnd_t *hnd, uint32_t *value); + +/*!*************************************************************************** + * @brief Sets the smart power save enabled flag to a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new smart power save enabled flag. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationSmartPowerSaveEnabled(argus_hnd_t *hnd, + argus_mode_t mode, + bool value); + +/*!*************************************************************************** + * @brief Gets the smart power save enabled flag from a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current smart power save enabled flag. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationSmartPowerSaveEnabled(argus_hnd_t *hnd, + argus_mode_t mode, + bool *value); + +/*!*************************************************************************** + * @brief Sets the Dual Frequency Mode (DFM) to a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new DFM mode value. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationDFMMode(argus_hnd_t *hnd, + argus_mode_t mode, + argus_dfm_mode_t value); + + +/*!*************************************************************************** + * @brief Gets the Dual Frequency Mode (DFM) from a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current DFM mode value. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationDFMMode(argus_hnd_t *hnd, + argus_mode_t mode, + argus_dfm_mode_t *value); + +/*!*************************************************************************** + * @brief Sets the Shot Noise Monitor (SNM) mode to a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new SNM mode value. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationShotNoiseMonitorMode(argus_hnd_t *hnd, + argus_mode_t mode, + argus_snm_mode_t value); + +/*!*************************************************************************** + * @brief Gets the Shot Noise Montor (SNM) mode from a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current SNM mode value. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationShotNoiseMonitorMode(argus_hnd_t *hnd, + argus_mode_t mode, + argus_snm_mode_t *value); + +/*!*************************************************************************** + * @brief Sets the full DCA module configuration to a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new DCA configuration set. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationDynamicAdaption(argus_hnd_t *hnd, + argus_mode_t mode, + argus_cfg_dca_t const *value); + +/*!*************************************************************************** + * @brief Gets the # from a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current DCA configuration set value. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationDynamicAdaption(argus_hnd_t *hnd, + argus_mode_t mode, + argus_cfg_dca_t *value); +/*!*************************************************************************** + * @brief Sets the pixel binning configuration parameters to a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new pixel binning configuration parameters. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetConfigurationPixelBinning(argus_hnd_t *hnd, + argus_mode_t mode, + argus_cfg_pba_t const *value); + +/*!*************************************************************************** + * @brief Gets the pixel binning configuration parameters from a specified device. + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current pixel binning configuration parameters. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationPixelBinning(argus_hnd_t *hnd, + argus_mode_t mode, + argus_cfg_pba_t *value); + +/*!*************************************************************************** + * @brief Gets the current unambiguous range in mm. + * @param hnd The API handle; contains all internal states and data. + * @param range_mm The returned range in mm. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetConfigurationUnambiguousRange(argus_hnd_t *hnd, + uint32_t *range_mm); + +/*! @} */ + +/*!************************************************************************** + * Calibration API + **************************************************************************** + * @addtogroup arguscal + * @{ + ****************************************************************************/ + +/*!*************************************************************************** + * @brief Sets the global range offset value to a specified device. + * + * @details The global range offset is subtracted from the raw range values. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new global range offset in meter and Q9.22 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationGlobalRangeOffset(argus_hnd_t *hnd, + argus_mode_t mode, + q9_22_t value); + +/*!*************************************************************************** + * @brief Gets the global range offset value from a specified device. + * + * @details The global range offset is subtracted from the raw range values. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current global range offset in meter and Q9.22 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationGlobalRangeOffset(argus_hnd_t *hnd, + argus_mode_t mode, + q9_22_t *value); + +/*!*************************************************************************** + * @brief Sets the relative pixel offset table to a specified device. + * + * @details The relative pixel offset values are subtracted from the raw range + * values for each individual pixel. Note that a global range offset + * is applied additionally. The relative pixel offset values are meant + * to be with respect to the average range of all pixels, i.e. the + * average of all relative offsets should be 0! + * + * The crosstalk vector table is a two dimensional array of type + * #q0_15_t. + * + * The dimensions are: + * - size(0) = #ARGUS_PIXELS_X (Pixel count in x-direction) + * - size(1) = #ARGUS_PIXELS_Y (Pixel count in y-direction) + * . + * + * Its recommended to use the built-in pixel offset calibration + * sequence (see #Argus_ExecuteRelativeRangeOffsetCalibrationSequence) + * to determine the offset table for the current device. + * + * If a constant offset table for all device needs to be incorporated + * into the sources, the #Argus_GetExternalPixelRangeOffsets_Callback + * should be used. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new relative range offset in meter and Q0.15 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationPixelRangeOffsets(argus_hnd_t *hnd, argus_mode_t mode, + q0_15_t value[ARGUS_PIXELS_X][ARGUS_PIXELS_Y]); + + +/*!*************************************************************************** + * @brief Gets the relative pixel offset table from a specified device. + * + * @details The relative pixel offset values are subtracted from the raw range + * values for each individual pixel. Note that a global range offset + * is applied additionally. The relative pixel offset values are meant + * to be with respect to the average range of all pixels, i.e. the + * average of all relative offsets should be 0! + * + * The crosstalk vector table is a two dimensional array of type + * #q0_15_t. + * + * The dimensions are: + * - size(0) = #ARGUS_PIXELS_X (Pixel count in x-direction) + * - size(1) = #ARGUS_PIXELS_Y (Pixel count in y-direction) + * . + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current relative range offset in meter and Q0.15 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationPixelRangeOffsets(argus_hnd_t *hnd, argus_mode_t mode, + q0_15_t value[ARGUS_PIXELS_X][ARGUS_PIXELS_Y]); + + +/*!*************************************************************************** + * @brief Gets the relative pixel offset table from a specified device. + * + * @details The relative pixel offset values are subtracted from the raw range + * values for each individual pixel. Note that a global range offset + * is applied additionally. The relative pixel offset values are meant + * to be with respect to the average range of all pixels, i.e. the + * average of all relative offsets should be 0! + * + * The crosstalk vector table is a two dimensional array of type + * #q0_15_t. + * + * The dimensions are: + * - size(0) = #ARGUS_PIXELS_X (Pixel count in x-direction) + * - size(1) = #ARGUS_PIXELS_Y (Pixel count in y-direction) + * + * The total offset table consists of the custom pixel offset values + * (set via #Argus_SetCalibrationPixelRangeOffsets) and the internal, + * factory calibrated device specific offset values. + * This is informational only! + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current total relative range offset in meter and Q0.15 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationTotalPixelRangeOffsets(argus_hnd_t *hnd, argus_mode_t mode, + q0_15_t value[ARGUS_PIXELS_X][ARGUS_PIXELS_Y]); + + +/*!*************************************************************************** + * @brief Resets the relative pixel offset values for the specified device to + * the factory calibrated default values. + * + * @details The relative pixel offset values are subtracted from the raw range + * values for each individual pixel. Note that a global range offset + * is applied additionally. + * + * The factory defaults are device specific values. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_ResetCalibrationPixelRangeOffsets(argus_hnd_t *hnd, argus_mode_t mode); + +/*!*************************************************************************** + * @brief A callback that returns the external pixel range offsets. + * + * @details The function needs to be implemented by the host application in + * order to set the external pixel range offsets values upon system + * initialization. If not defined in user code, the default + * implementation will return an all zero offset table, assuming there + * is no (additional) external pixel range offset values. + * + * If defined in user code, the function must fill all offset values + * in the provided \par offsets parameter with external range offset + * values. + * The values can be obtained by the calibration routine. + * + * Example usage: + * + * @code + * status_t Argus_GetExternalPixelRangeOffsets_Callback(q0_15_t offsets[ARGUS_PIXELS_X][ARGUS_PIXELS_Y], + * argus_mode_t mode) + * { + * (void) mode; // Ignore mode; use same values for all modes. + * memset(offsets, 0, sizeof(q0_15_t) * ARGUS_PIXELS); + * + * // Set offset values in meter and Q0.15 format. + * offsets[0][0].dS = -16384; offsets[0][0].dC = -32768; + * offsets[0][1].dS = -32768; offsets[0][1].dC = 0; + * offsets[0][2].dS = 16384; offsets[0][2].dC = -16384; + * // etc. + * } + * @endcode + * + * @param offsets The pixel range offsets in meter and Q0.15 format; to be + * filled with data. + * @param mode Determines the current measurement mode; can be ignored if + * only a single measurement mode is utilized. + *****************************************************************************/ +void Argus_GetExternalPixelRangeOffsets_Callback(q0_15_t offsets[ARGUS_PIXELS_X][ARGUS_PIXELS_Y], + argus_mode_t mode); + +/*!*************************************************************************** + * @brief Sets the sample count for the range offset calibration sequence. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The new range offset calibration sequence sample count. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationRangeOffsetSequenceSampleCount(argus_hnd_t *hnd, uint16_t value); + +/*!*************************************************************************** + * @brief Gets the sample count for the range offset calibration sequence. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The current range offset calibration sequence sample count. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationRangeOffsetSequenceSampleCount(argus_hnd_t *hnd, uint16_t *value); + +/*!*************************************************************************** + * @brief Sets the pixel-to-pixel crosstalk compensation parameters to a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new pixel-to-pixel crosstalk compensation parameters. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationCrosstalkPixel2Pixel(argus_hnd_t *hnd, + argus_mode_t mode, + argus_cal_p2pxtalk_t const *value); + +/*!*************************************************************************** + * @brief Gets the pixel-to-pixel crosstalk compensation parameters from a specified device. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current pixel-to-pixel crosstalk compensation parameters. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationCrosstalkPixel2Pixel(argus_hnd_t *hnd, + argus_mode_t mode, + argus_cal_p2pxtalk_t *value); + + +/*!*************************************************************************** + * @brief Sets the custom crosstalk vector table to a specified device. + * + * @details The crosstalk vectors are subtracted from the raw sampling data + * in the data evaluation phase. + * + * The crosstalk vector table is a three dimensional array of type + * #xtalk_t. + * + * The dimensions are: + * - size(0) = #ARGUS_DFM_FRAME_COUNT (Dual-frequency mode A- or B-frame) + * - size(1) = #ARGUS_PIXELS_X (Pixel count in x-direction) + * - size(2) = #ARGUS_PIXELS_Y (Pixel count in y-direction) + * . + * + * Its recommended to use the built-in crosstalk calibration sequence + * (see #Argus_ExecuteXtalkCalibrationSequence) to determine the + * crosstalk vector table. + * + * If a constant table for all device needs to be incorporated into + * the sources, the #Argus_GetExternalCrosstalkVectorTable_Callback + * should be used. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The new crosstalk vector table. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationCrosstalkVectorTable(argus_hnd_t *hnd, + argus_mode_t mode, + xtalk_t value[ARGUS_DFM_FRAME_COUNT][ARGUS_PIXELS_X][ARGUS_PIXELS_Y]); + +/*!*************************************************************************** + * @brief Gets the custom crosstalk vector table from a specified device. + * + * @details The crosstalk vectors are subtracted from the raw sampling data + * in the data evaluation phase. + * + * The crosstalk vector table is a three dimensional array of type + * #xtalk_t. + * + * The dimensions are: + * - size(0) = #ARGUS_DFM_FRAME_COUNT (Dual-frequency mode A- or B-frame) + * - size(1) = #ARGUS_PIXELS_X (Pixel count in x-direction) + * - size(2) = #ARGUS_PIXELS_Y (Pixel count in y-direction) + * . + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current crosstalk vector table. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationCrosstalkVectorTable(argus_hnd_t *hnd, + argus_mode_t mode, + xtalk_t value[ARGUS_DFM_FRAME_COUNT][ARGUS_PIXELS_X][ARGUS_PIXELS_Y]); + +/*!*************************************************************************** + * @brief Gets the factory calibrated default crosstalk vector table for the + * specified device. + * + * @details The crosstalk vectors are subtracted from the raw sampling data + * in the data evaluation phase. + * + * The crosstalk vector table is a three dimensional array of type + * #xtalk_t. + * + * The dimensions are: + * - size(0) = #ARGUS_DFM_FRAME_COUNT (Dual-frequency mode A- or B-frame) + * - size(1) = #ARGUS_PIXELS_X (Pixel count in x-direction) + * - size(2) = #ARGUS_PIXELS_Y (Pixel count in y-direction) + * . + * + * The total vector table consists of the custom crosstalk vector + * table (set via #Argus_SetCalibrationCrosstalkVectorTable) and + * an internal, factory calibrated device specific vector table. + * This is informational only! + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @param value The current total crosstalk vector table. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationTotalCrosstalkVectorTable(argus_hnd_t *hnd, + argus_mode_t mode, + xtalk_t value[ARGUS_DFM_FRAME_COUNT][ARGUS_PIXELS_X][ARGUS_PIXELS_Y]); + +/*!*************************************************************************** + * @brief Resets the crosstalk vector table for the specified device to the + * factory calibrated default values. + * + * @details The crosstalk vectors are subtracted from the raw sampling data + * in the data evaluation phase. + * * + * The factory defaults are device specific calibrated values. + * + * @param hnd The API handle; contains all internal states and data. + * @param mode The targeted measurement mode. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_ResetCalibrationCrosstalkVectorTable(argus_hnd_t *hnd, + argus_mode_t mode); + +/*!*************************************************************************** + * @brief Sets the sample count for the crosstalk calibration sequence. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The new crosstalk calibration sequence sample count. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationCrosstalkSequenceSampleCount(argus_hnd_t *hnd, + uint16_t value); + +/*!*************************************************************************** + * @brief Gets the sample count for the crosstalk calibration sequence. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The current crosstalk calibration sequence sample count. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationCrosstalkSequenceSampleCount(argus_hnd_t *hnd, + uint16_t *value); + +/*!*************************************************************************** + * @brief Sets the max. amplitude threshold for the crosstalk calibration sequence. + * + * @details The maximum amplitude threshold defines a maximum crosstalk vector + * amplitude before causing an error message. If the crosstalk is + * too high, there is usually an issue with the measurement setup, i.e. + * there is still a measurement signal detected. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The new crosstalk calibration sequence maximum amplitude + * threshold value in UQ12.4 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationCrosstalkSequenceAmplitudeThreshold(argus_hnd_t *hnd, + uq12_4_t value); + +/*!*************************************************************************** + * @brief Gets the max. amplitude threshold for the crosstalk calibration sequence. + * + * @details The maximum amplitude threshold defines a maximum crosstalk vector + * amplitude before causing an error message. If the crosstalk is + * too high, there is usually an issue with the measurement setup, i.e. + * there is still a measurement signal detected. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The current max. amplitude threshold value in UQ12.4 format. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationCrosstalkSequenceAmplitudeThreshold(argus_hnd_t *hnd, + uq12_4_t *value); + +/*!*************************************************************************** + * @brief Sets the sample count for the substrate voltage calibration sequence. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The new substrate voltage calibration sequence sample count. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_SetCalibrationVsubSequenceSampleCount(argus_hnd_t *hnd, + uint16_t value); + +/*!*************************************************************************** + * @brief Gets the sample count for the substrate voltage calibration sequence. + * + * @param hnd The API handle; contains all internal states and data. + * @param value The current substrate voltage calibration sequence sample count. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_GetCalibrationVsubSequenceSampleCount(argus_hnd_t *hnd, + uint16_t *value); + +/*!*************************************************************************** + * @brief A callback that returns the external crosstalk vector table. + * + * @details The function needs to be implemented by the host application in + * order to set the external crosstalk vector table upon system + * initialization. If not defined in user code, the default + * implementation will return an all zero vector table, assuming there + * is no (additional) external crosstalk. + * + * If defined in user code, the function must fill all vector values + * in the provided \par xtalk parameter with external crosstalk values. + * The values can be obtained by the calibration routine. + * + * Example usage: + * + * @code + * status_t Argus_GetExternalCrosstalkVectorTable_Callback(xtalk_t xtalk[ARGUS_DFM_FRAME_COUNT][ARGUS_PIXELS_X][ARGUS_PIXELS_Y], + * argus_mode_t mode) + * { + * (void) mode; // Ignore mode; use same values for all modes. + * memset(&xtalk, 0, sizeof(xtalk)); + * + * // Set crosstalk vectors in Q11.4 format. + * // Note on dual-frequency frame index: 0 = A-Frame; 1 = B-Frame + * xtalk[0][0][0].dS = -9; xtalk[0][0][0].dC = -11; + * xtalk[0][0][1].dS = -13; xtalk[0][0][1].dC = -16; + * xtalk[0][0][2].dS = 6; xtalk[0][0][2].dC = -18; + * // etc. + * } + * @endcode + * + * @param xtalk The crosstalk vector array; to be filled with data. + * @param mode Determines the current measurement mode; can be ignored if + * only a single measurement mode is utilized. + *****************************************************************************/ +void Argus_GetExternalCrosstalkVectorTable_Callback(xtalk_t + xtalk[ARGUS_DFM_FRAME_COUNT][ARGUS_PIXELS_X][ARGUS_PIXELS_Y], + argus_mode_t mode); + + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif /* ARGUS_API_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_dca.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_dca.h new file mode 100644 index 0000000000..f5f6845368 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_dca.h @@ -0,0 +1,489 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines the dynamic configuration adaption (DCA) setup parameters + * and data structure. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_DCA_H +#define ARGUS_DCA_H + +/*!*************************************************************************** + * @defgroup argusdca Dynamic Configuration Adaption + * @ingroup argusapi + * + * @brief Dynamic Configuration Adaption (DCA) parameter definitions and API functions. + * + * @details The DCA contains an algorithms that detect ambient conditions + * and adopt the device configuration to the changing parameters + * dynamically while operating the sensor. This is achieved by + * rating the currently received signal quality and changing the + * device configuration accordingly to the gathered information + * from the current measurement frame results before the next + * integration cycle starts. + * + * The DCA consists of the following features: + * - Static or Dynamic mode. The first is utilizing the nominal + * values while the latter is dynamically adopting between min. + * and max. value and starting from the nominal values. + * - Analog Integration Depth Adaption (from multiple patterns down to single pulses) + * - Optical Output Power Adaption + * - Pixel Input Gain Adaption (w/ ambient light rejection) + * - ADC Sensitivity (i.e. ADC Range) Adaption + * - Power Saving Ratio (to decrease the average output power and thus the current consumption) + * - All that features are heeding the Laser Safety limits. + * . + * + * @addtogroup argusdca + * @{ + *****************************************************************************/ + +#include "argus_def.h" + + + +/*! The minimum amplitude threshold value. */ +#define ARGUS_CFG_DCA_ATH_MIN (1U << 6U) + +/*! The maximum amplitude threshold value. */ +#define ARGUS_CFG_DCA_ATH_MAX (0xFFFFU) + + +/*! The minimum saturated pixel threshold value. */ +#define ARGUS_CFG_DCA_PXTH_MIN (1U) + +/*! The maximum saturated pixel threshold value. */ +#define ARGUS_CFG_DCA_PXTH_MAX (33U) + + +/*! The maximum analog integration depth in UQ10.6 format, + * i.e. the maximum pattern count per sample. */ +#define ARGUS_CFG_DCA_DEPTH_MAX ((uq10_6_t)(ADS_SEQCT_N_MASK << (6U - ADS_SEQCT_N_SHIFT))) + +/*! The minimum analog integration depth in UQ10.6 format, + * i.e. the minimum pattern count per sample. */ +#define ARGUS_CFG_DCA_DEPTH_MIN ((uq10_6_t)(1U)) // 1/64, i.e. 1/2 nibble + + +/*! The maximum optical output power, i.e. the maximum VCSEL 1 high current in LSB. */ +#define ARGUS_CFG_DCA_POWER_MAX_LSB (ADS_LASET_VCSEL_HC1_MASK >> ADS_LASET_VCSEL_HC1_SHIFT) + +/*! The minimum optical output power, i.e. the minimum VCSEL 1 high current in mA. */ +#define ARGUS_CFG_DCA_POWER_MIN_LSB (1) + +/*! The maximum optical output power, i.e. the maximum VCSEL 1 high current in LSB. */ +#define ARGUS_CFG_DCA_POWER_MAX (ADS0032_HIGH_CURRENT_LSB2MA(ARGUS_CFG_DCA_POWER_MAX_LSB + 1)) + +/*! The minimum optical output power, i.e. the minimum VCSEL 1 high current in mA. */ +#define ARGUS_CFG_DCA_POWER_MIN (1) + + + + + + + + +/*! The dynamic configuration algorithm Pixel Input Gain stage count. */ +#define ARGUS_DCA_GAIN_STAGE_COUNT (4U) + +/*! The dynamic configuration algorithm state mask for the Pixel Input Gain stage. */ +#define ARGUS_STATE_DCA_GAIN_MASK (0x03U) + +/*! The dynamic configuration algorithm state mask for the Pixel Input Gain stage. */ +#define ARGUS_STATE_DCA_GAIN_SHIFT (14U) + +/*! Getter for the dynamic configuration algorithm Pixel Input Gain stage. */ +#define ARGUS_STATE_DCA_GAIN_GET(state) \ + (((state) >> ARGUS_STATE_DCA_GAIN_SHIFT) & ARGUS_STATE_DCA_GAIN_MASK) + + +/*! The dynamic configuration algorithm Optical Output Power stage count. */ +#define ARGUS_DCA_POWER_STAGE_COUNT (4U) + +/*! The dynamic configuration algorithm state mask for the Optical Output Power stage. */ +#define ARGUS_STATE_DCA_POWER_MASK (0x03U) + +/*! The dynamic configuration algorithm state mask for the Optical Output Power stage. */ +#define ARGUS_STATE_DCA_POWER_SHIFT (12U) + +/*! Getter for the dynamic configuration algorithm Optical Output Power stage. */ +#define ARGUS_STATE_DCA_POWER_GET(state) \ + (((state) >> ARGUS_STATE_DCA_POWER_SHIFT) & ARGUS_STATE_DCA_POWER_MASK) + + +/*! The dynamic configuration algorithm state mask for the Max. Analog Integration Depth shift value. */ +#define ARGUS_STATE_DCA_DEPTH_SHFT_MASK (0x0FU) + +/*! The dynamic configuration algorithm state mask for the Max. Analog Integration Depth shift value. */ +#define ARGUS_STATE_DCA_DEPTH_SHFT_SHIFT (8U) + +/*! Getter for the dynamic configuration algorithm Max. Analog Integration Depth shift value. */ +#define ARGUS_STATE_DCA_DEPTH_SHFT_GET(state) \ + (((state) >> ARGUS_STATE_DCA_DEPTH_SHFT_SHIFT) & ARGUS_STATE_DCA_DEPTH_SHFT_MASK) + + +/*!*************************************************************************** + * @brief The dynamic configuration algorithm enable flags. + *****************************************************************************/ +typedef enum { + /*! DCA is disabled and will be completely skipped. */ + DCA_ENABLE_OFF = 0, + + /*! DCA is enabled and will dynamically adjust the device configuration. */ + DCA_ENABLE_DYNAMIC = 1, + + /*! DCA is enabled and will apply the static (nominal) values to the device. */ + DCA_ENABLE_STATIC = -1, + +} argus_dca_enable_t; + +/*!*************************************************************************** + * @brief The dynamic configuration algorithm Optical Output Power stages enumerator. + *****************************************************************************/ +typedef enum { + /*! Low output power stage. */ + DCA_POWER_LOW = 0, + + /*! Medium low output power stage. */ + DCA_POWER_MEDIUM_LOW = 1, + + /*! Medium high output power stage. */ + DCA_POWER_MEDIUM_HIGH = 2, + + /*! High output power stage. */ + DCA_POWER_HIGH = 3 + +} argus_dca_power_t; + +/*!*************************************************************************** + * @brief The dynamic configuration algorithm Pixel Input Gain stages enumerator. + *****************************************************************************/ +typedef enum { + /*! Low gain stage. */ + DCA_GAIN_LOW = 0, + + /*! Medium low gain stage. */ + DCA_GAIN_MEDIUM_LOW = 1, + + /*! Medium high gain stage. */ + DCA_GAIN_MEDIUM_HIGH = 2, + + /*! High gain stage. */ + DCA_GAIN_HIGH = 3 + +} argus_dca_gain_t; + + +/*!*************************************************************************** + * @brief State flags for the current frame. + * @details State flags determine the current state of the measurement frame: + * - [0]: #ARGUS_STATE_MEASUREMENT_MODE: Measurement Mode: + * - 0: Mode A + * - 1: Mode B + * . + * - [1]: #ARGUS_STATE_DUAL_FREQ_MODE: Dual Frequency Mode Enabled Flag + * - 0: Disabled, measurements w/ base frequency only + * - 1: Enabled, measurements w/ detuned frequency + * . + * - [2]: #ARGUS_STATE_MEASUREMENT_FREQ: Measurement Frequency for + * Dual Frequency Mode, (only valid if #ARGUS_STATE_DUAL_FREQ_MODE + * flag is set) + * - 0: A-Frame w/ detuned frequency + * - 1: B-Frame w/ detuned frequency + * . + * - [3]: #ARGUS_STATE_DEBUG_MODE + * - [4]: #ARGUS_STATE_GOLDEN_PIXEL_MODE + * - [5]: #ARGUS_STATE_BGL_WARNING + * - [6]: #ARGUS_STATE_BGL_ERROR + * - [7]: #ARGUS_STATE_PLL_LOCKED + * - 0: PLL_LOCKED bit was not set at start of integration; + * - 0: PLL_LOCKED bit was set at start of integration; + * . + * - [8-11]: Max. Depth Shift Value + * - [12-13]: Power Stages + * - [14-15]: Gain Stages + * . + *****************************************************************************/ +typedef enum { + /*! No state flag set. */ + ARGUS_STATE_NONE = 0, + + /*! 0x01: Measurement Mode. + * - 0: Mode A: Long Range / Medium Precision + * - 1: Mode B: Short Range / High Precision */ + ARGUS_STATE_MEASUREMENT_MODE = 1U << 0U, + + /*! 0x02: Dual Frequency Mode Enabled. + * - 0: Disabled: measurements with base frequency, + * - 1: Enabled: measurement with detuned frequency. */ + ARGUS_STATE_DUAL_FREQ_MODE = 1U << 1U, + + /*! 0x04: Measurement Frequency for Dual Frequency Mode + * (only if #ARGUS_STATE_DUAL_FREQ_MODE flag is set). + * - 0: A-Frame w/ detuned frequency, + * - 1: B-Frame w/ detuned frequency */ + ARGUS_STATE_MEASUREMENT_FREQ = 1U << 2U, + + /*! 0x08: Debug Mode. If set, the range value of erroneous pixels are not + * cleared or reset. + * - 0: Disabled (default). + * - 1: Enabled. */ + ARGUS_STATE_DEBUG_MODE = 1U << 3U, + + /*! 0x10: Golden Pixel Mode Flag. + * Set whenever the Pixel Binning Algorithm is operating in the + * Golden Pixel Mode. + * - 0: Normal Pixel Binning Mode. + * - 1: Golden Pixel Mode. */ + ARGUS_STATE_GOLDEN_PIXEL_MODE = 1U << 4U, + + /*! 0x20: Background Light Warning Flag. + * Set whenever the background light is very high and the + * measurement data might be unreliable. + * - 0: No Warning Background Light is within valid range. + * - 1: Warning: Background Light is very high. */ + ARGUS_STATE_BGL_WARNING = 1U << 5U, + + /*! 0x40: Background Light Error Flag. + * Set whenever the background light is too high and the + * measurement data is unreliable or invalid. + * - 0: No Error, Background Light is within valid range. + * - 1: Error: Background Light is too high. */ + ARGUS_STATE_BGL_ERROR = 1U << 6U, + + /*! 0x80: PLL_LOCKED bit. + * - 0: PLL not locked at start of integration. + * - 1: PLL locked at start of integration. */ + ARGUS_STATE_PLL_LOCKED = 1U << 7U, + + /*! DCA is in low Optical Output Power stage. */ + ARGUS_STATE_DCA_POWER_LOW = DCA_GAIN_LOW << ARGUS_STATE_DCA_POWER_SHIFT, + + /*! DCA is in medium-low Optical Output Power stage. */ + ARGUS_STATE_DCA_POWER_MED_LOW = DCA_GAIN_MEDIUM_LOW << ARGUS_STATE_DCA_POWER_SHIFT, + + /*! DCA is in medium-high Optical Output Power stage. */ + ARGUS_STATE_DCA_POWER_MED_HIGH = DCA_GAIN_MEDIUM_HIGH << ARGUS_STATE_DCA_POWER_SHIFT, + + /*! DCA is in high Optical Output Power stage. */ + ARGUS_STATE_DCA_POWER_HIGH = DCA_GAIN_HIGH << ARGUS_STATE_DCA_POWER_SHIFT, + + + /*! DCA is in low Pixel Input Gain stage. */ + ARGUS_STATE_DCA_GAIN_LOW = DCA_GAIN_LOW << ARGUS_STATE_DCA_GAIN_SHIFT, + + /*! DCA is in medium-low Pixel Input Gain stage. */ + ARGUS_STATE_DCA_GAIN_MED_LOW = DCA_GAIN_MEDIUM_LOW << ARGUS_STATE_DCA_GAIN_SHIFT, + + /*! DCA is in medium-high Pixel Input Gain stage. */ + ARGUS_STATE_DCA_GAIN_MED_HIGH = DCA_GAIN_MEDIUM_HIGH << ARGUS_STATE_DCA_GAIN_SHIFT, + + /*! DCA is in high Pixel Input Gain stage. */ + ARGUS_STATE_DCA_GAIN_HIGH = DCA_GAIN_HIGH << ARGUS_STATE_DCA_GAIN_SHIFT, + +} argus_state_t; + +/*!*************************************************************************** + * @brief Dynamic Configuration Adaption (DCA) Parameters. + * @details DCA contains: + * - Static or dynamic mode. The first is utilizing the nominal values + * while the latter is dynamically adopting between min. and max. + * value and starting form the nominal values. + * - Analog Integration Depth Adaption down to single pulses. + * - Optical Output Power Adaption + * - Pixel Input Gain Adaption + * - Digital Integration Depth Adaption + * - Dynamic Global Phase Shift Injection. + * - All that features are heeding the Laser Safety limits. + * . + *****************************************************************************/ +typedef struct { + /*! Enables the automatic configuration adaption features. + * Enables the dynamic part if #DCA_ENABLE_DYNAMIC and the static only if + * #DCA_ENABLE_STATIC. If set to DCA_ENABLE_OFF, the DCA is completely + * skipped and the static register values are considered which is + * recommended for advanced debugging only. */ + argus_dca_enable_t Enabled; + + /*! The threshold value of saturated pixels that causes a linear reduction + * of the integration energy, i.e. if the number of saturated pixels are + * larger or equal to this value, the integration energy will be reduced + * by a single step (one pattern if the current integration depth is > 1, + * one pulse if the current integration depth is <= 1 or one power LSB for + * the optical power range). + * + * Valid values: 1, ..., 33; (use 33 to disable the linear decrease) + * Note that the linear value must be smaller or equal to the exponential + * value. To sum up, it must hold: + * 1 <= SatPxThLin <= SatPxThExp <= SatPxThRst <= 33 */ + uint8_t SatPxThLin; + + /*! The threshold number of saturated pixels that causes a exponential + * reduction of the integration energy, i.e. if the number of saturated + * pixels is larger or equal to this value, the integration energy will be + * halved. + * + * Valid values: 1, ..., 33; (use 33 to disable the exponential decrease) + * Note that the exponential value must be between the linear and reset + * values. To sum up, it must hold: + * 1 <= SatPxThLin <= SatPxThExp <= SatPxThRst <= 33 */ + uint8_t SatPxThExp; + + /*! The threshold number of saturated pixels that causes a sudden reset of + * the integration energy to the minimal value, i.e. if the number of + * saturated pixels are larger or equal to this value, the integration + * energy will suddenly be reset to the minimum values. The gain setting + * will stay at the mid value and a decrease happens after the next step + * if still required. + * + * Valid values: 1, ..., 33; (use 33 to disable the sudden reset) + * Note that the reset value must be larger or equal to the exponential + * value. To sum up, it must hold: + * 1 <= SatPxThLin <= SatPxThExp <= SatPxThRst <= 33 */ + uint8_t SatPxThRst; + + /*! The amplitude to be targeted from the lower regime. If the amplitude + * lower than the target value, a linear increase of integration energy + * will happen in order to optimize for best performance. + * + * Valid values: #ARGUS_CFG_DCA_ATH_MIN, ... #ARGUS_CFG_DCA_ATH_MAX or 0 + * Set 0 to disable optimization toward the target amplitude. + * Note further that the following condition must hold: + * 'MIN' <= AthLow <= Atarget <= AthHigh <= 'MAX' */ + uq12_4_t Atarget; + + /*! The low threshold value for the max. amplitude. If the max. amplitude + * falls below this value, the integration depth will be increases. + * + * Valid values: #ARGUS_CFG_DCA_ATH_MIN, ... #ARGUS_CFG_DCA_ATH_MAX + * Note further that the following condition must hold: + * 'MIN' <= AthLow <= Atarget <= AthHigh <= 'MAX' */ + uq12_4_t AthLow; + + /*! The high threshold value for the max. amplitude. If the max. amplitude + * exceeds this value, the integration depth will be decreases. Note that + * also saturated pixels will cause a decrease of the integration depth. + * + * Valid values: #ARGUS_CFG_DCA_ATH_MIN, ... #ARGUS_CFG_DCA_ATH_MAX + * Note further that the following condition must hold: + * 'MIN' <= AthLow <= Atarget <= AthHigh <= 'MAX' */ + uq12_4_t AthHigh; + + /*! The nominal analog integration depth in UQ10.6 format, + * i.e. the nominal pattern count per sample. + * + * Valid values: #ARGUS_CFG_DCA_DEPTH_MIN, ... #ARGUS_CFG_DCA_DEPTH_MAX + * Note further that the following condition must hold: + * 'MIN' <= DepthLow <= DepthNom <= DepthHigh <= 'MAX' */ + uq10_6_t DepthNom; + + /*! The minimum analog integration depth in UQ10.6 format, + * i.e. the minimum pattern count per sample. + * + * Valid values: #ARGUS_CFG_DCA_DEPTH_MIN, ... #ARGUS_CFG_DCA_DEPTH_MAX + * Note further that the following condition must hold: + * 'MIN' <= DepthLow <= DepthNom <= DepthHigh <= 'MAX' */ + uq10_6_t DepthMin; + + /*! The maximum analog integration depth in UQ10.6 format, + * i.e. the maximum pattern count per sample. + * + * Valid values: #ARGUS_CFG_DCA_DEPTH_MIN, ... #ARGUS_CFG_DCA_DEPTH_MAX + * Note further that the following condition must hold: + * 'MIN' <= DepthMin <= DepthNom <= DepthMax <= 'MAX' */ + uq10_6_t DepthMax; + + /*! The nominal optical output power in mA, + * i.e. the nominal VCSEL_HC1 setting. + * + * Valid values: #ARGUS_CFG_DCA_POWER_MIN, ... #ARGUS_CFG_DCA_POWER_MAX + * Note further that the following condition must hold: + * 'MIN' <= PowerMin <= PowerNom <= 'MAX' */ + uq12_4_t PowerNom; + + /*! The minimum optical output power in mA, + * i.e. the minimum VCSEL_HC1 setting. + * + * Valid values: #ARGUS_CFG_DCA_POWER_MIN, ... #ARGUS_CFG_DCA_POWER_MAX + * Note further that the following condition must hold: + * 'MIN' <= PowerMin <= PowerNom <= 'MAX' */ + uq12_4_t PowerMin; + + /*! The nominal pixel gain setting, i.e. the setting for + * nominal/default gain stage. + * + * Valid values: 0,..,3: #DCA_GAIN_LOW, ... #DCA_GAIN_HIGH + * Note further that the following condition must hold: + * 'MIN' <= GainMin <= GainNom <= GainMax <= 'MAX' */ + argus_dca_gain_t GainNom; + + /*! The minimal pixel gain setting, i.e. the setting for + * minimum gain stage. + * + * Valid values: 0,..,3: #DCA_GAIN_LOW, ... #DCA_GAIN_HIGH + * Note further that the following condition must hold: + * 'MIN' <= GainMin <= GainNom <= GainMax <= 'MAX' */ + argus_dca_gain_t GainMin; + + /*! The maximum pixel gain setting, i.e. the setting for + * maximum gain stage. + * + * Valid values: 0,..,3: #DCA_GAIN_LOW, ... #DCA_GAIN_HIGH + * Note further that the following condition must hold: + * 'MIN' <= GainMin <= GainNom <= GainMax <= 'MAX' */ + argus_dca_gain_t GainMax; + + /*! Power Saving Ratio value. + * + * Determines the percentage of the full available frame time that is not + * exploited for digital integration. Thus the device is idle within the + * specified portion of the frame time and does consume less energy. + * + * Note that the laser safety might already limit the maximum integration + * depth and the power saving ratio might not take effect for all ambient + * situations. Thus the Power Saving Ratio is to be understood as a minimum + * percentage where the device is idle per frame. + * + * The value is a UQ0.8 format that ranges from 0.0 (=0x00) to 0.996 (=0xFF), + * where 0 means no power saving (i.e. feature disabled) and 0xFF determines + * maximum power saving, i.e. the digital integration depth is limited to a + * single sample. + * + * Range: 0x00, .., 0xFF; set 0 to disable. */ + uq0_8_t PowerSavingRatio; + +} argus_cfg_dca_t; + +/*! @} */ +#endif /* ARGUS_DCA_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_def.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_def.h new file mode 100644 index 0000000000..4762e1d9cd --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_def.h @@ -0,0 +1,205 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 hardware API. + * @details This file provides generic definitions belonging to all + * devices from the AFBR-S50 product family. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_DEF_H +#define ARGUS_DEF_H + +/*!*************************************************************************** + * Include files + *****************************************************************************/ +#include "argus_status.h" +#include "argus_version.h" +#include "utility/fp_def.h" +#include "utility/time.h" +#include +#include +#include +#include +#include + +/*!*************************************************************************** + * @addtogroup argusapi + * @{ + *****************************************************************************/ + +/*!*************************************************************************** + * @brief Maximum number of phases per measurement cycle. + * @details The actual phase number is defined in the register configuration. + * However the software does only support a fixed value of 4 yet. + *****************************************************************************/ +#define ARGUS_PHASECOUNT 4U + +/*!*************************************************************************** + * @brief The device pixel field size in x direction (long edge). + *****************************************************************************/ +#define ARGUS_PIXELS_X 8U + +/*!*************************************************************************** + * @brief The device pixel field size in y direction (short edge). + *****************************************************************************/ +#define ARGUS_PIXELS_Y 4U + +/*!*************************************************************************** + * @brief The total device pixel count. + *****************************************************************************/ +#define ARGUS_PIXELS ((ARGUS_PIXELS_X)*(ARGUS_PIXELS_Y)) + +/*!*************************************************************************** + * @brief The AFBR-S50 module types. + *****************************************************************************/ +typedef enum { + /*! No device connected or not recognized. */ + MODULE_NONE = 0, + + /*! AFBR-S50MV85G: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and infra-red, 850 nm, laser source for + * medium range 3D applications. + * Version 1 - legacy version! */ + AFBR_S50MV85G_V1 = 1, + + /*! AFBR-S50MV85G: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and infra-red, 850 nm, laser source for + * medium range 3D applications. + * Version 2 - legacy version! */ + AFBR_S50MV85G_V2 = 2, + + /*! AFBR-S50MV85G: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and infra-red, 850 nm, laser source for + * medium range 3D applications. + * Version 7 - current version! */ + AFBR_S50MV85G_V3 = 7, + + /*! AFBR-S50LV85D: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and infra-red, 850 nm, laser source for + * long range 1D applications. + * Version 1 - current version! */ + AFBR_S50LV85D_V1 = 3, + + /*! AFBR-S50MV68B: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and red, 680 nm, laser source for + * medium range 1D applications. + * Version 1 - current version! */ + AFBR_S50MV68B_V1 = 4, + + /*! AFBR-S50MV85I: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and infra-red, 850 nm, laser source for + * medium range 3D applications. + * Version 1 - current version! */ + AFBR_S50MV85I_V1 = 5, + + /*! AFBR-S50MV85G: an ADS0032 based multi-pixel range finder device + * w/ 4x8 pixel matrix and infra-red, 850 nm, laser source for + * short range 3D applications. + * Version 1 - current version! */ + AFBR_S50SV85K_V1 = 6, + + + /*! Reserved for future extensions. */ + Reserved = 0b111111 + +} argus_module_version_t; + +/*!*************************************************************************** + * @brief The AFBR-S50 laser configurations. + *****************************************************************************/ +typedef enum { + /*! No laser connected. */ + LASER_NONE = 0, + + /*! 850nm Infra-Red VCSEL v1 */ + LASER_H_V1 = 1, + + /*! 850nm Infra-Red VCSEL v2 */ + LASER_H_V2 = 2, + + /*! 680nm Red VCSEL v1 */ + LASER_R_V1 = 3, + +} argus_laser_type_t; + +/*!*************************************************************************** + * @brief The AFBR-S50 chip versions. + *****************************************************************************/ +typedef enum { + /*! No device connected or not recognized. */ + ADS0032_NONE = 0, + + /*! ADS0032 v1.0 */ + ADS0032_V1_0 = 1, + + /*! ADS0032 v1.1 */ + ADS0032_V1_1 = 2, + + /*! ADS0032 v1.2 */ + ADS0032_V1_2 = 3, + +} argus_chip_version_t; + +/*!*************************************************************************** + * @brief The number of measurement modes with distinct configuration and + * calibration records. + *****************************************************************************/ +#define ARGUS_MODE_COUNT (2) + +/*!*************************************************************************** + * @brief The measurement modes. + *****************************************************************************/ +typedef enum { + /*! Measurement Mode A: Long Range Mode. */ + ARGUS_MODE_A = 1, + + /*! Measurement Mode B: Short Range Mode. */ + ARGUS_MODE_B = 2, + +} argus_mode_t; + +/*!*************************************************************************** + * @brief Generic API callback function. + * @details Invoked by the API. The content of the abstract data pointer + * depends upon the context. + * @param status The module status that caused the callback. #STATUS_OK if + * everything was as expected. + * @param data An abstract pointer to an user defined data. This will + * usually be passed to the function that also takes the + * callback as an parameter. Otherwise it has a special + * meaning such as configuration or calibration data. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +typedef status_t (*argus_callback_t)(status_t status, void *data); + +/*! @} */ +#endif /* ARGUS_DEF_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_dfm.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_dfm.h new file mode 100644 index 0000000000..c5ec32dfa8 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_dfm.h @@ -0,0 +1,81 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines the dual frequency mode (DFM) setup parameters. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_DFM_H +#define ARGUS_DFM_H + +/*!*************************************************************************** + * @defgroup argusdfm Dual Frequency Mode + * @ingroup argusdev + * + * @brief Dual Frequency Mode (DFM) parameter definitions and API functions. + * + * @details The DFM is an algorithm to extend the unambiguous range of the + * sensor by utilizing two detuned measurement frequencies. + * + * The AFBR-S50 API provides three measurement modes: + * - 1X: Single Frequency Measurement + * - 4X: Dual Frequency Measurement w/ 4 times the unambiguous + * range of the Single Frequency Measurement + * - 8X: Dual Frequency Measurement w/ 8 times the unambiguous + * range of the Single Frequency Measurement + * + * @addtogroup argusdfm + * @{ + *****************************************************************************/ + +/*! The Dual Frequency Mode frequency count. */ +#define ARGUS_DFM_FRAME_COUNT (2U) + +/*! The Dual Frequency Mode measurement modes count. Excluding the disabled mode. */ +#define ARGUS_DFM_MODE_COUNT (2U) // expect off-mode! + +/*! The Dual Frequency Mode measurement modes enumeration. */ +typedef enum { + /*! Single Frequency Measurement Mode (w/ 1x Unambiguous Range). */ + DFM_MODE_OFF = 0U, + + /*! 4X Dual Frequency Measurement Mode (w/ 4x Unambiguous Range). */ + DFM_MODE_4X = 1U, + + /*! 8X Dual Frequency Measurement Mode (w/ 8x Unambiguous Range). */ + DFM_MODE_8X = 2U, + +} argus_dfm_mode_t; + + +/*! @} */ +#endif /* ARGUS_DFM_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_meas.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_meas.h new file mode 100644 index 0000000000..e57de35711 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_meas.h @@ -0,0 +1,118 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 hardware API. + * @details Defines the generic measurement parameters and data structures. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_MEAS_H +#define ARGUS_MEAS_H + +/*!*************************************************************************** + * @defgroup argusmeas Measurement/Device Control + * @ingroup argusapi + * + * @brief Measurement/Device control module + * + * @details This module contains measurement and device control specific + * definitions and methods. + * + * @addtogroup argusmeas + * @{ + *****************************************************************************/ + +#include "argus_dca.h" +#include "argus_def.h" + +/*! Number of raw data values. */ +#define ARGUS_RAW_DATA_VALUES 132U // 33 channels * 4 phases + +/*! Size of the raw data in bytes. */ +#define ARGUS_RAW_DATA_SIZE (3U * ARGUS_RAW_DATA_VALUES) // 3 bytes * 33 channels * 4 phases + +/*! The number channels for auxiliary measurements readout. */ +#define ARGUS_AUX_CHANNEL_COUNT (5U) + +/*! Size of the auxiliary data in bytes. */ +#define ARGUS_AUX_DATA_SIZE (3U * ARGUS_AUX_CHANNEL_COUNT) // 3 bytes * x channels * 1 phase + +/*!*************************************************************************** + * @brief The device measurement configuration structure. + * @details The portion of the configuration data that belongs to the + * measurement cycle. I.e. the data that defines a measurement frame. + *****************************************************************************/ +typedef struct { + /*! ADC channel enabled mask for the first + * channels 0 .. 31 (active pixels channels). + * See [pixel mapping](@ref argusmap) for more + * details on the pixel mask. */ + uint32_t PxEnMask; + + /*! ADS channel enabled mask for the remaining + * channels 31 .. 63 (miscellaneous values). + * See [pixel mapping](@ref argusmap) for more + * details on the channel mask. */ + uint32_t ChEnMask; + + /*! Pattern count per sample in uq10.6 format. + * Determines the analog integration depth. */ + uq10_6_t AnalogIntegrationDepth; + + /*! Sample count per phase/frame. + * Determines the digital integration depth. */ + uint16_t DigitalIntegrationDepth; + + /*! Laser current per sample in mA. + * Determines the optical output power. */ + uq12_4_t OutputPower; + + /*! Charge pump voltage per sample in LSB. + * Determines the pixel gain. */ + uint8_t PixelGain; + + /*! PLL Frequency Offset, caused by temperature + * compensation, in PLL_INT_PRD LSBs. */ + int8_t PllOffset; + + /*! The current state of the measurement frame: + * - Measurement Mode, + * - A/B Frame, + * - PLL_Locked Bit, + * - BGL Warning/Error, + * - DCA State, + * - ... */ + argus_state_t State; + +} argus_meas_frame_t; + +/*! @} */ +#endif /* ARGUS_MEAS_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_msk.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_msk.h new file mode 100644 index 0000000000..258fb38260 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_msk.h @@ -0,0 +1,170 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines macros to work with pixel and ADC channel masks. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_MSK_H +#define ARGUS_MSK_H + +/*!*************************************************************************** + * @defgroup argusmap ADC Channel Mapping + * @ingroup argusres + * + * @brief Pixel ADC Channel (n) to x-y-Index Mapping + * + * @details The ADC Channels of each pixel or auxiliary channel on the device + * is numbered in a way that is convenient on the chip. The macros + * in this module are defined in order to obtain the x-y-indices of + * each channel and vice versa. + * + * @addtogroup argusmap + * @{ + *****************************************************************************/ + +#include "api/argus_def.h" +#include "utility/int_math.h" + +/*!***************************************************************************** + * @brief Macro to determine the channel number of an specified Pixel. + * @param x The x index of the pixel. + * @param y The y index of the pixel. + * @return The channel number n of the pixel. + ******************************************************************************/ +#define PIXEL_XY2N(x, y) ((((x) ^ 7) << 1) | ((y) & 2) << 3 | ((y) & 1)) + +/*!***************************************************************************** + * @brief Macro to determine the x index of an specified Pixel channel. + * @param n The channel number of the pixel. + * @return The x index number of the pixel. + ******************************************************************************/ +#define PIXEL_N2X(n) ((((n) >> 1U) & 7) ^ 7) + +/*!***************************************************************************** + * @brief Macro to determine the y index of an specified Pixel channel. + * @param n The channel number of the pixel. + * @return The y index number of the pixel. + ******************************************************************************/ +#define PIXEL_N2Y(n) (((n) & 1U) | (((n) >> 3) & 2U)) + +/*!***************************************************************************** + * @brief Macro to determine if a ADC Pixel channel was enabled from a pixel mask. + * @param msk The 32-bit pixel mask + * @param ch The channel number of the pixel. + * @return True if the pixel channel n was enabled, false elsewise. + ******************************************************************************/ +#define PIXELN_ISENABLED(msk, ch) (((msk) >> (ch)) & 0x01U) + +/*!***************************************************************************** + * @brief Macro enables an ADC Pixel channel in a pixel mask. + * @param msk The 32-bit pixel mask + * @param ch The channel number of the pixel. + ******************************************************************************/ +#define PIXELN_ENABLE(msk, ch) ((msk) |= (0x01U << (ch))) + +/*!***************************************************************************** + * @brief Macro disables an ADC Pixel channel in a pixel mask. + * @param msk The 32-bit pixel mask + * @param ch The channel number of the pixel. + ******************************************************************************/ +#define PIXELN_DISABLE(msk, ch) ((msk) &= (~(0x01U << (ch)))) + +/*!***************************************************************************** + * @brief Macro to determine if an ADC Pixel channel was enabled from a pixel mask. + * @param msk 32-bit pixel mask + * @param x x index of the pixel. + * @param y y index of the pixel. + * @return True if the pixel (x,y) was enabled, false elsewise. + ******************************************************************************/ +#define PIXELXY_ISENABLED(msk, x, y) (PIXELN_ISENABLED(msk, PIXEL_XY2N(x, y))) + +/*!***************************************************************************** + * @brief Macro enables an ADC Pixel channel in a pixel mask. + * @param msk 32-bit pixel mask + * @param x x index of the pixel. + * @param y y index of the pixel. + ******************************************************************************/ +#define PIXELXY_ENABLE(msk, x, y) (PIXELN_ENABLE(msk, PIXEL_XY2N(x, y))) + +/*!***************************************************************************** + * @brief Macro disables an ADC Pixel channel in a pixel mask. + * @param msk 32-bit pixel mask + * @param x x index of the pixel. + * @param y y index of the pixel. + ******************************************************************************/ +#define PIXELXY_DISABLE(msk, x, y) (PIXELN_DISABLE(msk, PIXEL_XY2N(x, y))) + +/*!***************************************************************************** + * @brief Macro to determine if a ADC channel was enabled from a channel mask. + * @param msk 32-bit channel mask + * @param ch channel number of the ADC channel. + * @return True if the ADC channel n was enabled, false elsewise. + ******************************************************************************/ +#define CHANNELN_ISENABLED(msk, ch) (((msk) >> ((ch) - 32U)) & 0x01U) + +/*!***************************************************************************** + * @brief Macro to determine if a ADC channel was enabled from a channel mask. + * @param msk 32-bit channel mask + * @param ch channel number of the ADC channel. + * @return True if the ADC channel n was enabled, false elsewise. + ******************************************************************************/ +#define CHANNELN_ENABLE(msk, ch) ((msk) |= (0x01U << ((ch) - 32U))) + +/*!***************************************************************************** + * @brief Macro to determine if a ADC channel was enabled from a channel mask. + * @param msk 32-bit channel mask + * @param ch channel number of the ADC channel. + * @return True if the ADC channel n was enabled, false elsewise. + ******************************************************************************/ +#define CHANNELN_DISABLE(msk, ch) ((msk) &= (~(0x01U << ((ch) - 32U)))) + + +/*!***************************************************************************** + * @brief Macro to determine the number of enabled pixel channels via a popcount + * algorithm. + * @param pxmsk 32-bit pixel mask + * @return The count of enabled pixel channels. + ******************************************************************************/ +#define PIXEL_COUNT(pxmsk) popcount(pxmsk) + +/*!***************************************************************************** + * @brief Macro to determine the number of enabled channels via a popcount + * algorithm. + * @param pxmsk 32-bit pixel mask + * @param chmsk 32-bit channel mask + * @return The count of enabled ADC channels. + ******************************************************************************/ +#define CHANNEL_COUNT(pxmsk, chmsk) (popcount(pxmsk) + popcount(chmsk)) + +/*! @} */ +#endif /* ARGUS_MSK_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_pba.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_pba.h new file mode 100644 index 0000000000..1d4a5c43b9 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_pba.h @@ -0,0 +1,221 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines the pixel binning algorithm (PBA) setup parameters and + * data structure. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_PBA_H +#define ARGUS_PBA_H + +/*!*************************************************************************** + * @defgroup arguspba Pixel Binning Algorithm + * @ingroup argusapi + * + * @brief Pixel Binning Algorithm (PBA) parameter definitions and API functions. + * + * @details Defines the generic pixel binning algorithm (PBA) setup parameters + * and data structure. + * + * The PBA module contains filter algorithms that determine the + * pixels with the best signal quality and extract an 1d distance + * information from the filtered pixels. + * + * The pixel filter algorithm is a three-stage filter with a + * fallback value: + * + * -# A fixed pre-filter mask is applied to statically disable + * specified pixels. + * -# A relative and absolute amplitude filter is applied in the + * second stage. The relative filter is determined by a ratio + * of the maximum amplitude off all available (i.e. not filtered + * in stage 1) pixels. Pixels that have an amplitude below the + * relative threshold are dismissed. The same holds true for + * the absolute amplitude threshold. All pixel with smaller + * amplitude are dismissed.\n + * The relative threshold is useful to setup a distance + * measurement scenario. All well illuminated pixels are + * selected and considered for the final 1d distance. The + * absolute threshold is used to dismiss pixels that are below + * the noise level. The latter would be considered for the 1d + * result if the maximum amplitude is already very low. + * -# A distance filter is used to distinguish pixels that target + * the actual object from pixels that see the brighter background, + * e.g. white walls. Thus, the pixel with the minimum distance + * is referenced and all pixel that have a distance between + * the minimum and the given minimum distance scope are selected + * for the 1d distance result. The minimum distance scope is + * determined by an relative (to the current minimum distance) + * and an absolute value. The larger scope value is the + * relevant one, i.e. the relative distance scope can be used + * to heed the increasing noise at larger distances. + * -# If all of the above filters fail to determine a single valid + * pixel, the golden pixel is used as a fallback value. The + * golden pixel is the pixel that sits right at the focus point + * of the optics at large distances. + * . + * + * After filtering is done, there may be more than a single pixel + * left to determine the 1d signal. Therefore several averaging + * methods are implemented to obtain the best 1d result from many + * pixels. See #argus_pba_averaging_mode_t for details. + * + * + * @addtogroup arguspba + * @{ + *****************************************************************************/ + +#include "argus_def.h" + +/*!*************************************************************************** + * @brief Enable flags for the pixel binning algorithm. + * + * @details Determines the pixel binning algorithm feature enable status. + * - [0]: #PBA_ENABLE: Enables the pixel binning feature. + * - [1]: reserved + * - [2]: reserved + * - [3]: reserved + * - [4]: reserved + * - [5]: #PBA_ENABLE_GOLDPX: Enables the golden pixel feature. + * - [6]: #PBA_ENABLE_MIN_DIST_SCOPE: Enables the minimum distance scope + * feature. + * - [7]: reserved + * . + *****************************************************************************/ +typedef enum { + /*! Enables the pixel binning feature. */ + PBA_ENABLE = 1U << 0U, + + /*! Enables the golden pixel. */ + PBA_ENABLE_GOLDPX = 1U << 5U, + + /*! Enables the minimum distance scope filter. */ + PBA_ENABLE_MIN_DIST_SCOPE = 1U << 6U, + +} argus_pba_flags_t; + +/*!*************************************************************************** + * @brief The averaging modes for the pixel binning algorithm. + *****************************************************************************/ +typedef enum { + /*! Evaluate the 1D range from all available pixels using + * a simple average. */ + PBA_SIMPLE_AVG = 1U, + + /*! Evaluate the 1D range from all available pixels using + * a linear amplitude weighted averaging method. + * Formula: x_mean = sum(x_i * A_i) / sum(A_i) */ + PBA_LINEAR_AMPLITUDE_WEIGHTED_AVG = 2U, + +} argus_pba_averaging_mode_t; + +/*!*************************************************************************** + * @brief The pixel binning algorithm settings data structure. + * @details Describes the pixel binning algorithm settings. + *****************************************************************************/ +typedef struct { + /*! Enables the pixel binning features. + * Each bit may enable a different feature. See #argus_pba_flags_t + * for details about the enabled flags. */ + argus_pba_flags_t Enabled; + + /*! Determines the PBA averaging mode which is used to obtain the + * final range value from the algorithm, for example, the average + * of all pixels. See #argus_pba_averaging_mode_t for more details + * about the individual evaluation modes. */ + argus_pba_averaging_mode_t Mode; + + /*! The Relative amplitude threshold value (in %) of the max. amplitude. + * Pixels with amplitude below this threshold value are dismissed. + * + * All available values from the 8-bit representation are valid. + * The actual percentage value is determined by 100%/256*x. + * + * Use 0 to disable the relative amplitude threshold. */ + uq0_8_t RelAmplThreshold; + + /*! The relative minimum distance scope value in %. + * Pixels that have a range value within [x0, x0 + dx] are considered + * for the pixel binning, where x0 is the minimum distance of all + * amplitude picked pixels and dx is the minimum distance scope value. + * The minimum distance scope value will be the maximum of relative + * and absolute value. + * + * All available values from the 8-bit representation are valid. + * The actual percentage value is determined by 100%/256*x. + * + * Special values: + * - 0: Use 0 for absolute value only or to choose the pixel with the + * minimum distance only (of also the absolute value is 0)! */ + uq0_8_t RelMinDistanceScope; + + /*! The Absolute amplitude threshold value in LSB. + * Pixels with amplitude below this threshold value are dismissed. + * + * All available values from the 16-bit representation are valid. + * The actual LSB value is determined by x/16. + * + * Use 0 to disable the absolute amplitude threshold. */ + uq12_4_t AbsAmplThreshold; + + /*! The absolute minimum distance scope value in m. + * Pixels that have a range value within [x0, x0 + dx] are considered + * for the pixel binning, where x0 is the minimum distance of all + * amplitude picked pixels and dx is the minimum distance scope value. + * The minimum distance scope value will be the maximum of relative + * and absolute value. + * + * All available values from the 16-bit representation are valid. + * The actual LSB value is determined by x/2^15. + * + * Special values: + * - 0: Use 0 for relative value only or to choose the pixel with the + * minimum distance only (of also the relative value is 0)! */ + uq1_15_t AbsMinDistanceScope; + + /*! The pre-filter pixel mask determines the pixel channels that are + * statically excluded from the pixel binning (i.e. 1D distance) result. + * + * The pixel enabled mask is an 32-bit mask that determines the + * device internal channel number. It is recommended to use the + * - #PIXELXY_ISENABLED(msk, x, y) + * - #PIXELXY_ENABLE(msk, x, y) + * - #PIXELXY_DISABLE(msk, x, y) + * . + * macros to work with the pixel enable masks. */ + uint32_t PrefilterMask; + +} argus_cfg_pba_t; + +/*! @} */ +#endif /* ARGUS_PBA_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_px.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_px.h new file mode 100644 index 0000000000..2977312d8e --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_px.h @@ -0,0 +1,143 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines the device pixel measurement results data structure. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_PX_H +#define ARGUS_PX_H + +/*!*************************************************************************** + * @addtogroup argusres + * @{ + *****************************************************************************/ + +/*! Maximum amplitude value in UQ12.4 format. */ +#define ARGUS_AMPLITUDE_MAX (0xFFF0U) + +/*! Maximum range value in Q9.22 format. + * Also used as a special value to determine no object detected or infinity range. */ +#define ARGUS_RANGE_MAX (Q9_22_MAX) + +/*!*************************************************************************** + * @brief Status flags for the evaluated pixel structure. + * + * @details Determines the pixel status. 0 means OK (#PIXEL_OK). + * - [0]: #PIXEL_OFF: Pixel was disabled and not read from the device. + * - [1]: #PIXEL_SAT: The pixel was saturated. + * - [2]: #PIXEL_BIN_EXCL: The pixel was excluded from the 1D result. + * - [3]: #PIXEL_AMPL_MIN: The pixel amplitude has evaluated to 0. + * - [4]: #PIXEL_PREFILTERED: The was pre-filtered by static mask. + * - [5]: #PIXEL_NO_SIGNAL: The pixel has no valid signal. + * - [6]: #PIXEL_OUT_OF_SYNC: The pixel has lost signal trace. + * - [7]: #PIXEL_STALLED: The pixel value is stalled due to errors. + * . + *****************************************************************************/ +typedef enum { + /*! 0x00: Pixel status OK. */ + PIXEL_OK = 0, + + /*! 0x01: Pixel is disabled (in hardware) and no data has been read from the device. */ + PIXEL_OFF = 1U << 0U, + + /*! 0x02: Pixel is saturated (i.e. at least one saturation bit for any + * sample is set or the sample is in the invalidity area). */ + PIXEL_SAT = 1U << 1U, + + /*! 0x04: Pixel is excluded from the pixel binning (1d) result. */ + PIXEL_BIN_EXCL = 1U << 2U, + + /*! 0x08: Pixel amplitude minimum underrun + * (i.e. the amplitude calculation yields 0). */ + PIXEL_AMPL_MIN = 1U << 3U, + + /*! 0x10: Pixel is pre-filtered by the static pixel binning pre-filter mask, + * i.e. the pixel is disabled by software. */ + PIXEL_PREFILTERED = 1U << 4U, + + /*! 0x20: Pixel amplitude is below its threshold value. The received signal + * strength is too low to evaluate a valid signal. The range value is + * set to the maximum possible value (approx. 512 m). */ + PIXEL_NO_SIGNAL = 1U << 5U, + + /*! 0x40: Pixel is not in sync with respect to the dual frequency algorithm. + * I.e. the pixel may have a correct value but is estimated into the + * wrong unambiguous window. */ + PIXEL_OUT_OF_SYNC = 1U << 6U, + + /*! 0x80: Pixel is stalled due to one of the following reasons: + * - #PIXEL_SAT + * - #PIXEL_AMPL_MIN + * - #PIXEL_OUT_OF_SYNC + * - Global Measurement Error + * . + * A stalled pixel does not update its measurement data and keeps the + * previous values. If the issue is resolved, the stall disappears and + * the pixel is updating again. */ + PIXEL_STALLED = 1U << 7U + +} argus_px_status_t; + +/*!*************************************************************************** + * @brief The evaluated measurement results per pixel. + * @details This structure contains the evaluated data for a single pixel.\n + * If the amplitude is 0, the pixel is turned off or has invalid data. + *****************************************************************************/ +typedef struct { + /*! Range Values from the device in meter. It is the actual distance before + * software adjustments/calibrations. */ + q9_22_t Range; + + /*! Phase Values from the device in units of PI, i.e. 0 ... 2. */ + uq1_15_t Phase; + + /*! Amplitudes of measured signals in LSB. + * Special values: 0 == Pixel Off, 0xFFFF == Overflow/Error */ + uq12_4_t Amplitude; + + /*! Pixel status; determines if the pixel is disabled, saturated, .. + * See the \link #argus_px_status_t pixel status flags\endlink for more + * information. */ + argus_px_status_t Status; + + /*! The unambiguous window determined by the dual frequency feature. */ + int8_t RangeWindow; + + /*! The raw amplitudes of measured signals in LSB. */ + uq12_4_t AmplitudeRaw; + +} argus_pixel_t; + + +/*! @} */ +#endif /* ARGUS_PX_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_res.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_res.h new file mode 100644 index 0000000000..468a913671 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_res.h @@ -0,0 +1,173 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines the generic measurement results data structure. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_RES_H +#define ARGUS_RES_H + +/*!*************************************************************************** + * @defgroup argusres Measurement Data + * @ingroup argusapi + * + * @brief Measurement results data structures. + * + * @details The interface defines all data structures that correspond to + * the AFBR-S50 measurement results, e.g. + * - 1D distance and amplitude values, + * - 3D distance and amplitude values (i.e. per pixel), + * - Auxiliary channel measurement results (VDD, IAPD, temperature, ...) + * - Device and result status + * - ... + * . + * + * @addtogroup argusres + * @{ + *****************************************************************************/ + +#include "argus_def.h" +#include "argus_px.h" +#include "argus_meas.h" + +/*!*************************************************************************** + * @brief The 1d measurement results data structure. + * @details The 1d measurement results obtained by the pixel binning algorithm. + *****************************************************************************/ +typedef struct { + /*! Raw 1D range value in meter (Q9.22 format). The distance obtained by + * the pixel binning algorithm from the current measurement frame. */ + q9_22_t Range; + + /*! The 1D amplitude in LSB (Q12.4 format). The (maximum) amplitude obtained + * by the pixel binning algorithm from the current measurement frame. + * Special value: 0 == No/Invalid Result. */ + uq12_4_t Amplitude; + +} argus_results_bin_t; + +/*!*************************************************************************** + * @brief The auxiliary measurement results data structure. + * @details The auxiliary measurement results obtained by the auxiliary task. + * Special values, i.e. 0xFFFFU, indicate no readout value available. + *****************************************************************************/ +typedef struct { + /*! VDD ADC channel readout value. + * Special Value if no value has been measured: + * Invalid/NotAvailable = 0xFFFFU (UQ12_4_MAX) */ + uq12_4_t VDD; + + /*! Temperature sensor ADC channel readout value. + * Special Value if no value has been measured: + * Invalid/NotAvailable = 0x7FFFU (Q11_4_MAX) */ + q11_4_t TEMP; + + /*! Substrate Voltage ADC Channel readout value. + * Special Value if no value has been measured: + * Invalid/NotAvailable = 0xFFFFU (UQ12_4_MAX) */ + uq12_4_t VSUB; + + /*! VDD VCSEL ADC channel readout value. + * Special Value if no value has been measured: + * Invalid/NotAvailable = 0xFFFFU (UQ12_4_MAX) */ + uq12_4_t VDDL; + + /*! APD current ADC Channel readout value. + * Special Value if no value has been measured: + * Invalid/NotAvailable = 0xFFFFU (UQ12_4_MAX) */ + uq12_4_t IAPD; + + /*! Background Light Value in arbitrary. units, + * estimated by the substrate voltage control task. + * Special Value if no value is available: + * Invalid/NotAvailable = 0xFFFFU (UQ12_4_MAX) */ + uq12_4_t BGL; + + /*! Shot Noise Amplitude in LSB units, + * estimated by the shot noise monitor task from + * the average amplitude of the passive pixels. + * Special Value if no value is available: + * Invalid/NotAvailable = 0xFFFFU (UQ12_4_MAX) */ + uq12_4_t SNA; + +} argus_results_aux_t; + +/*!*************************************************************************** + * @brief The measurement results data structure. + * @details Measurement data from the device. + * @code + * // Pixel Field: Pixel[x][y] + * // + * // 0 -----------> x + * // | O O O O O O O O + * // | O O O O O O O O + * // | O O O O O O O O O (ref. Px) + * // y O O O O O O O O + * @endcode + *****************************************************************************/ +typedef struct { + /*! The \link #status_t status\endlink of the current measurement frame. + * - 0 (i.e. #STATUS_OK) for a good measurement signal. + * - > 0 for warnings and weak measurement signal. + * - < 0 for errors and invalid measurement signal. */ + status_t Status; + + /*! Time in milliseconds (measured since the last MCU startup/reset) + * when the measurement was triggered. */ + ltc_t TimeStamp; + + /*! The configuration for the current measurement frame. */ + argus_meas_frame_t Frame; + + /*! Raw unmapped ADC results from the device. */ + uint32_t Data[ARGUS_RAW_DATA_VALUES]; + + /*! Raw Range Values from the device in meter. + * It is the actual distance before software adjustments/calibrations. */ + argus_pixel_t PixelRef; + + /*! Raw Range Values from the device in meter. + * It is the actual distance before software adjustments/calibrations. */ + argus_pixel_t Pixel[ARGUS_PIXELS_X][ARGUS_PIXELS_Y]; + + /*! Pixel binned results. */ + argus_results_bin_t Bin; + + /*! The auxiliary ADC channel data. */ + argus_results_aux_t Auxiliary; + +} argus_results_t; + + +/*! @} */ +#endif /* ARGUS_RES_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_snm.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_snm.h new file mode 100644 index 0000000000..2bb6ad0a0d --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_snm.h @@ -0,0 +1,82 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Defines the Shot Noise Monitor (SNM) setup parameters. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_SNM_H +#define ARGUS_SNM_H + +/*!*************************************************************************** + * @defgroup argussnm Shot Noise Monitor + * @ingroup argusdev + * + * @brief Shot Noise Monitor (SNM) parameter definitions and API functions. + * + * @details The SNM is an algorithm to monitor and react on shot noise + * induced by harsh environment conditions like high ambient + * light. + * + * The AFBR-S50 API provides three modes: + * - Dynamic: Automatic mode, automatically adopts to current + * ambient conditions. + * - Static (Outdoor): Static mode, optimized for outdoor applications. + * - Static (Indoor): Static mode, optimized for indoor applications. + * . + * + * @addtogroup argussnm + * @{ + *****************************************************************************/ + +/*! The Shot Noise Monitor modes enumeration. */ +typedef enum { + /*! Static Shot Noise Monitoring Mode, optimized for indoor applications. + * Assumes the best case scenario, i.e. no bad influence from ambient conditions. + * Thus it uses a fixed setting that will result in the best performance. + * Equivalent to Shot Noise Monitoring disabled. */ + SNM_MODE_STATIC_INDOOR = 0U, + + /*! Static Shot Noise Monitoring Mode, optimized for outdoor applications. + * Assumes the worst case scenario, i.e. it uses a fixed setting that will + * work under all ambient conditions. */ + SNM_MODE_STATIC_OUTDOOR = 1U, + + /*! Dynamic Shot Noise Monitoring Mode. + * Adopts the system performance dynamically to the current ambient conditions. */ + SNM_MODE_DYNAMIC = 2U, + +} argus_snm_mode_t; + + +/*! @} */ +#endif /* ARGUS_SNM_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_status.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_status.h new file mode 100644 index 0000000000..77ac2fcafc --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_status.h @@ -0,0 +1,271 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Provides status codes for the AFBR-S50 API. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_STATUS_H +#define ARGUS_STATUS_H + +#include + +/*!*************************************************************************** + * @defgroup status Status Codes + * @brief Status and Error Code Definitions + * @details Defines status and error codes for function return values. + * Basic status number structure: + * - 0 is OK or no error. + * - negative values determine errors. + * - positive values determine warnings or status information. + * . + * @addtogroup status + * @{ + *****************************************************************************/ + +/*!*************************************************************************** + * @brief Type used for all status and error return values. + * @details Basic status number structure: + * - 0 is OK or no error. + * - negative values determine errors. + * - positive values determine warnings or status information. + * . + *****************************************************************************/ +typedef int32_t status_t; + +/*! AFBR-S50 API status and error return codes. */ +enum Status { + /********************************************************************************************** + ********** Generic Status ******************************************************************** + *********************************************************************************************/ + + /*! 0: Status for success/no error. */ + STATUS_OK = 0, + + /*! 0: Status for device/module/hardware idle. Implies #STATUS_OK. */ + STATUS_IDLE = 0, + + /*! 1: Status to be ignored. */ + STATUS_IGNORE = 1, + + /*! 2: Status for device/module/hardware busy. */ + STATUS_BUSY = 2, + + /*! 3: Status for device/module/hardware is currently initializing. */ + STATUS_INITIALIZING = 3, + + /*! -1: Error for generic fail/error. */ + ERROR_FAIL = -1, + + /*! -2: Error for process aborted by user/external. */ + ERROR_ABORTED = -2, + + /*! -3: Error for invalid read only operations. */ + ERROR_READ_ONLY = -3, + + /*! -4: Error for out of range parameters. */ + ERROR_OUT_OF_RANGE = -4, + + /*! -5: Error for invalid argument passed to an function. */ + ERROR_INVALID_ARGUMENT = -5, + + /*! -6: Error for timeout occurred. */ + ERROR_TIMEOUT = -6, + + /*! -7: Error for not initialized modules. */ + ERROR_NOT_INITIALIZED = -7, + + /*! -8: Error for not supported. */ + ERROR_NOT_SUPPORTED = -8, + + /*! -9: Error for yet not implemented functions. */ + ERROR_NOT_IMPLEMENTED = -9, + + + /********************************************************************************************** + ********** S2PI Layer Status ***************************************************************** + *********************************************************************************************/ + + /*! 51: SPI is disabled and pins are used in GPIO mode. */ + STATUS_S2PI_GPIO_MODE = 51, + + /*! -51: Error occurred on the Rx line. */ + ERROR_S2PI_RX_ERROR = -51, + + /*! -52: Error occurred on the Tx line. */ + ERROR_S2PI_TX_ERROR = -52, + + /*! -53: Called a function at a wrong driver state. */ + ERROR_S2PI_INVALID_STATE = -53, + + /*! -54: The specified baud rate is not valid. */ + ERROR_S2PI_INVALID_BAUD_RATE = -54, + + /*! -55: The specified slave identifier is not valid. */ + ERROR_S2PI_INVALID_SLAVE = -55, + + + /********************************************************************************************** + ********** NVM / Flash Layer Status ********************************************************* + *********************************************************************************************/ + + /*! -98: Flash Error: The version of the settings in the flash memory is not compatible. */ + ERROR_NVM_INVALID_FILE_VERSION = -98, + + /*! -99: Flash Error: The memory is out of range. */ + ERROR_NVM_OUT_OF_RANGE = -99, + + + /********************************************************************************************** + ********** AFBR-S50 Specific Status ********************************************************** + *********************************************************************************************/ + + /*! 104: AFBR-S50 Status: All (internal) raw data buffers are currently in use. + * The measurement was not executed due to lack of available raw data buffers. + * Please call #Argus_EvaluateData to free the buffers. */ + STATUS_ARGUS_BUFFER_BUSY = 104, + + /*! 105: AFBR-S50 Status: The measurement was not executed/started due to output power + * limitations. */ + STATUS_ARGUS_POWERLIMIT = 105, + + /*! 107: AFBR-S50 Status: No valid signal was detected at any active pixel + * via the Pixel Binning Algorithm. The Golden Pixel was Choosen as a + * fallback value that is consider to be the last pixel that has a valid + * signal for low reflective (or far away) objects. + * The current results should be considered carefully. */ + STATUS_ARGUS_UNDERFLOW = 107, + + /*! 108: AFBR-S50 Status: No object was detected within the field-of-view + * and measurement range of the device. */ + STATUS_ARGUS_NO_OBJECT = 108, + + /*! 109: AFBR-S50 Status: The readout algorithm for the EEPROM has detected a bit + * error which has been corrected. However, if more than a single bit error + * has occurred, the corrected value is invalid! This cannot be distinguished + * from the valid case. Thus, if the error starts to occur, the sensor + * should be replaced soon! */ + STATUS_ARGUS_EEPROM_BIT_ERROR = 109, + + /*! 110: AFBR-S50 Status: Inconsistent EEPROM readout data. No calibration + * trimming values are applied. The calibration remains invalid. */ + STATUS_ARGUS_INVALID_EEPROM = 110, + + /*! -101: AFBR-S50 Error: No device connected. Initial SPI tests failed. */ + ERROR_ARGUS_NOT_CONNECTED = -101, + + /*! -102: AFBR-S50 Error: Inconsistent configuration parameters. */ + ERROR_ARGUS_INVALID_CFG = -102, + + + /*! -105: AFBR-S50 Error: Invalid measurement mode configuration parameter. */ + ERROR_ARGUS_INVALID_MODE = -105, + + /*! -107: AFBR-S50 Error: The APD bias voltage is reinitializing due to a dropout. + * The current measurement data set is invalid! */ + ERROR_ARGUS_BIAS_VOLTAGE_REINIT = -107, + + + /*! -109: AFBR-S50 Error: The EEPROM readout has failed. The failure is detected + * by three distinct read attempts, each resulting in invalid data. + * Note: this state differs from that #STATUS_ARGUS_EEPROM_BIT_ERROR + * such that it is usually temporarily and due to harsh ambient conditions. */ + ERROR_ARGUS_EEPROM_FAILURE = -109, + + /*! -110: AFBR-S50 Error: The measurement signals of all active pixels are invalid + * and thus the 1D range is also invalid and stalled. + * This means the range value is not updated and kept at the previous valid value. */ + ERROR_ARGUS_STALLED = -110, + + /*! -111: AFBR-S50 Error: The background light is too bright. */ + ERROR_ARGUS_BGL_EXCEEDANCE = -111, + + /*! -112: AFBR-S50 Error: The crosstalk vector amplitude is too high. */ + ERROR_ARGUS_XTALK_AMPLITUDE_EXCEEDANCE = -112, + + /*! -113: AFBR-S50 Error: Laser malfunction! Laser Safety may not be given! */ + ERROR_ARGUS_LASER_FAILURE = -113, + + /*! -114: AFBR-S50 Error: Register data integrity is lost (e.g. due to unexpected + * power-on-reset cycle or invalid write cycle of SPI. System tries to + * reset the values. */ + ERROR_ARGUS_DATA_INTEGRITY_LOST = -114, + + /*! -115: AFBR-S50 Error: The range offsets calibration failed! */ + ERROR_ARGUS_RANGE_OFFSET_CALIBRATION_FAILED = -115, + + /*! -191: AFBR-S50 Error: The device is currently busy and cannot execute the + * requested command. */ + ERROR_ARGUS_BUSY = -191, + + + /*! -199: AFBR-S50 Error: Unknown module number. */ + ERROR_ARGUS_UNKNOWN_MODULE = -199, + + /*! -198: AFBR-S50 Error: Unknown chip version number. */ + ERROR_ARGUS_UNKNOWN_CHIP = -198, + + /*! -197: AFBR-S50 Error: Unknown laser type number. */ + ERROR_ARGUS_UNKNOWN_LASER = -197, + + + + /*! 193: AFBR-S50 Status (internal): The device is currently busy with updating the + * configuration (i.e. with writing register values). */ + STATUS_ARGUS_BUSY_CFG_UPDATE = 193, + + /*! 194: AFBR-S50 Status (internal): The device is currently busy with updating the + * calibration data (i.e. writing to register values). */ + STATUS_ARGUS_BUSY_CAL_UPDATE = 194, + + /*! 195: AFBR-S50 Status (internal): The device is currently executing a calibration + * sequence. */ + STATUS_ARGUS_BUSY_CAL_SEQ = 195, + + /*! 196: AFBR-S50 Status (internal): The device is currently executing a measurement + * cycle. */ + STATUS_ARGUS_BUSY_MEAS = 196, + + + /*! 100: AFBR-S50 Status (internal): The ASIC is initializing a new measurement, i.e. + * a register value is written that starts an integration cycle on the ASIC. */ + STATUS_ARGUS_STARTING = 100, + + /*! 103: AFBR-S50 Status (internal): The ASIC is performing an integration cycle. */ + STATUS_ARGUS_ACTIVE = 103, + + + +}; + +/*! @} */ +#endif /* ARGUS_STATUS_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_version.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_version.h new file mode 100644 index 0000000000..2a2ca9d62c --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_version.h @@ -0,0 +1,76 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file contains the current API version number. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_VERSION_H +#define ARGUS_VERSION_H + +/*!*************************************************************************** + * @defgroup version API Version + * @ingroup argusapi + * + * @brief API and library core version number + * + * @details Contains the AFBR-S50 API and Library Core Version Number. + * + * @addtogroup version + * @{ + *****************************************************************************/ + +/*! Major version number of the AFBR-S50 API. */ +#define ARGUS_API_VERSION_MAJOR 1 + +/*! Minor version number of the AFBR-S50 API. */ +#define ARGUS_API_VERSION_MINOR 2 + +/*! Bugfix version number of the AFBR-S50 API. */ +#define ARGUS_API_VERSION_BUGFIX 3 + +/*! Build version nunber of the AFBR-S50 API. */ +#define ARGUS_API_VERSION_BUILD "20201120091253" + +/*****************************************************************************/ + +/*! Construct the version number for drivers. */ +#define MAKE_VERSION(major, minor, bugfix) \ + (((major) << 24) | ((minor) << 16) | (bugfix)) + +/*! Version number of the AFBR-S50 API. */ +#define ARGUS_API_VERSION MAKE_VERSION((ARGUS_API_VERSION_MAJOR), \ + (ARGUS_API_VERSION_MINOR), \ + (ARGUS_API_VERSION_BUGFIX)) + +/*! @} */ +#endif /* ARGUS_VERSION_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_xtalk.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_xtalk.h new file mode 100644 index 0000000000..5613706267 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/api/argus_xtalk.h @@ -0,0 +1,114 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 hardware API. + * @details Defines the generic device calibration API. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_XTALK_H +#define ARGUS_XTALK_H + +/*!*************************************************************************** + * @addtogroup arguscal + * @{ + *****************************************************************************/ + +#include "api/argus_def.h" + +/*!*************************************************************************** + * @brief Pixel Crosstalk Compensation Vector. + * @details Contains calibration data (per pixel) that belongs to the + * RX-TX-Crosstalk compensation feature. + *****************************************************************************/ + +/*! Pixel Crosstalk Vector */ +typedef struct { + /*! Crosstalk Vector - Sine component. + * Special Value: Q11_4_MIN == not available */ + q11_4_t dS; + + /*! Crosstalk Vector - Cosine component. + * Special Value: Q11_4_MIN == not available */ + q11_4_t dC; + +} xtalk_t; + +/*!*************************************************************************** + * @brief Pixel-To-Pixel Crosstalk Compensation Parameters. + * @details Contains calibration data that belongs to the pixel-to-pixel + * crosstalk compensation feature. + *****************************************************************************/ +typedef struct { + /*! Pixel-To-Pixel Compensation on/off. */ + bool Enabled; + + /*! The relative threshold determines when the compensation is active for + * each individual pixel. The value determines the ratio of the individual + * pixel signal is with respect to the overall average signal. If the + * ratio is smaller than the value, the compensation is active. Absolute + * and relative conditions are connected with AND logic. */ + uq0_8_t RelativeThreshold; + + /*! The absolute threshold determines the minimum total crosstalk + * amplitude (i.e. the average amplitude of all pixels weighted by + * the Kc factor) that is required for the compensation to become + * active. Set to 0 to always enable. Absolute and relative + * conditions are connected with AND logic. */ + uq12_4_t AbsoluteTreshold; + + /*! The sine component of the Kc factor that determines the amount of the total + * signal of all pixels that influences the individual signal of each pixel. + * Higher values determine more influence on the individual pixel signal. */ + q3_12_t KcFactorS; + + /*! The cosine component of the Kc factor that determines the amount of the total + * signal of all pixels that influences the individual signal of each pixel. + * Higher values determine more influence on the individual pixel signal. */ + q3_12_t KcFactorC; + + /*! The sine component of the reference pixel Kc factor that determines the + * amount of the total signal on all pixels that influences the individual + * signal of the reference pixel. + * Higher values determine more influence on the reference pixel signal. */ + q3_12_t KcFactorSRefPx; + + /*! The cosine component of the reference pixel Kc factor that determines the + * amount of the total signal on all pixels that influences the individual + * signal of the reference pixel. + * Higher values determine more influence on the reference pixel signal. */ + q3_12_t KcFactorCRefPx; + +} argus_cal_p2pxtalk_t; + + +/*! @} */ +#endif /* ARGUS_XTALK_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/argus.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/argus.h new file mode 100644 index 0000000000..dcea881d02 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/argus.h @@ -0,0 +1,50 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file the main header of the AFBR-S50 API. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_H +#define ARGUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "api/argus_api.h" + +#ifdef __cplusplus +} +#endif + +#endif /* ARGUS_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_irq.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_irq.h new file mode 100644 index 0000000000..0a9e11241e --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_irq.h @@ -0,0 +1,121 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides an interface for enabling/disabling interrupts. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_IRQ_H +#define ARGUS_IRQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup argus_irq IRQ: Global Interrupt Control Layer + * @ingroup argus_platform + * + * @brief Global Interrupt Control Layer + * + * @details This module provides functionality to globally enable/disable + * interrupts by turning the I-bit in the CPSR on/off. + * + * Here is a simple example implementation using the CMSIS functions + * "__enable_irq()" and "__disable_irq()". An integer counter is + * used to achieve nested interrupt disabling: + * + * @code + * + * // Global lock level counter value. + * static volatile int g_irq_lock_ct; + * + * // Global unlock all interrupts using CMSIS function "__enable_irq()". + * void IRQ_UNLOCK(void) + * { + * assert(g_irq_lock_ct > 0); + * if (--g_irq_lock_ct <= 0) + * { + * g_irq_lock_ct = 0; + * __enable_irq(); + * } + * } + * + * // Global lock all interrupts using CMSIS function "__disable_irq()". + * void IRQ_LOCK(void) + * { + * __disable_irq(); + * g_irq_lock_ct++; + * } + * + * @endcode + * + * @note The IRQ locking mechanism is used to create atomic sections + * (within the scope of the AFBR-S50 API) that are very few processor + * instruction only. It does NOT lock interrupts for considerable + * amounts of time. + * + * @note The interrupts utilized by the AFBR-S50 API can be interrupted + * by other, higher prioritized interrupts, e.g. some system + * critical interrupts. In this case, the IRQ_LOCK/IRQ_UNLOCK + * mechanism can be implemented such that only the interrupts + * required for the AFBR-S50 API are locked. The above example is + * dedicated to a ARM Corex-M0 architecture, where interrupts + * can only disabled at a global scope. Other architectures like + * ARM Cortex-M4 allow selective disabling of interrupts. + * + * @addtogroup argus_irq + * @{ + *****************************************************************************/ + +/*!*************************************************************************** + * @brief Enable IRQ Interrupts + * + * @details Enables IRQ interrupts by clearing the I-bit in the CPSR. + * Can only be executed in Privileged modes. + *****************************************************************************/ +void IRQ_UNLOCK(void); + +/*!*************************************************************************** + * @brief Disable IRQ Interrupts + * + * @details Disables IRQ interrupts by setting the I-bit in the CPSR. + * Can only be executed in Privileged modes. + *****************************************************************************/ +void IRQ_LOCK(void); + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif // ARGUS_IRQ_H diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_nvm.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_nvm.h new file mode 100644 index 0000000000..0c0bf237cb --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_nvm.h @@ -0,0 +1,135 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides an interface for the optional non-volatile memory. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_NVM_H +#define ARGUS_NVM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup argus_nvm NVM: Non-Volatile Memory Layer + * @ingroup argus_platform + * + * @brief Non-Volatile Memory Layer + * + * @details This module provides functionality to access the non-volatile + * memory (e.g. flash) on the underlying platform. + * + * This module is optional and only required if calibration data + * needs to be stored within the API. + * + * @note The implementation of this module is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disables the NVM feature. + * + * @addtogroup argus_nvm + * @{ + *****************************************************************************/ + +#include "argus.h" + +/*!*************************************************************************** + * @brief Initializes the non-volatile memory unit and reserves a chunk of memory. + * + * @details The function is called upon API initialization sequence. If available, + * the non-volatile memory module reserves a chunk of memory with the + * provides number of bytes (size) and returns with #STATUS_OK. + * + * If not implemented, the function should return #ERROR_NOT_IMPLEMENTED + * in oder to inform the API to not use the NVM module. + * + * After initialization, the API calls the #NVM_Write and #NVM_Read + * methods to write within the reserved chunk of memory. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disables the NVM feature. + * + * @param size The required size of NVM to store all parameters. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t NVM_Init(uint32_t size); + +/*!*************************************************************************** + * @brief Write a block of data to the non-volatile memory. + * + * @details The function is called whenever the API wants to write data into + * the previously reserved (#NVM_Init) memory block. The data shall + * be written at a given offset and with a given size. + * + * If no NVM module is available, the function can return with error + * #ERROR_NOT_IMPLEMENTED. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disables the NVM feature. + * + * @param offset The index offset where the first byte needs to be written. + * @param size The number of bytes to be written. + * @param buf The pointer to the data buffer with the data to be written. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t NVM_Write(uint32_t offset, uint32_t size, uint8_t const *buf); + +/*!*************************************************************************** + * @brief Reads a block of data from the non-volatile memory. + * + * @details The function is called whenever the API wants to read data from + * the previously reserved (#NVM_Init) memory block. The data shall + * be read at a given offset and with a given size. + * + * If no NVM module is available, the function can return with error + * #ERROR_NOT_IMPLEMENTED. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disables the NVM feature. + * + * @param offset The index offset where the first byte needs to be read. + * @param size The number of bytes to be read. + * @param buf The pointer to the data buffer to copy the data to. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t NVM_Read(uint32_t offset, uint32_t size, uint8_t *buf); + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif // ARGUS_NVM_H diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_print.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_print.h new file mode 100644 index 0000000000..d53b2df35a --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_print.h @@ -0,0 +1,83 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides an interface for the optional debug module. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_PRINT_H +#define ARGUS_PRINT_H + +/*!*************************************************************************** + * @defgroup argus_log Debug: Logging Interface + * @ingroup argus_platform + * + * @brief Logging interface for the AFBR-S50 API. + * + * @details This interface provides logging utility functions. + * Defines a printf-like function that is used to print error and + * log messages. + * + * @addtogroup argus_log + * @{ + *****************************************************************************/ + +#include "api/argus_def.h" + +/*!*************************************************************************** + * @brief A printf-like function to print formated data to an debugging interface. + * + * @details Writes the C string pointed by fmt_t to an output. If format + * includes format specifiers (subsequences beginning with %), the + * additional arguments following fmt_t are formatted and inserted in + * the resulting string replacing their respective specifiers. + * + * To enable the print functionality, an implementation of the function + * must be provided that maps the output to an interface like UART or + * a debugging console, e.g. by forwarding to standard printf() method. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that does nothing. This will improve + * the performance but no error messages are logged. + * + * @note The naming is different from the standard printf() on purpose to + * prevent builtin compiler optimizations. + * + * @param fmt_s The usual print() format string. + * @param ... The usual print() parameters. * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t print(const char *fmt_s, ...); + +/*! @} */ +#endif /* ARGUS_PRINT_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_s2pi.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_s2pi.h new file mode 100644 index 0000000000..3c17096e8e --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_s2pi.h @@ -0,0 +1,352 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides an interface for the required S2PI module. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_S2PI_H +#define ARGUS_S2PI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup argus_s2pi S2PI: Serial Peripheral Interface + * @ingroup argus_platform + * + * @brief S2PI: SPI incl. GPIO Hardware Layer Module + * + * @details The S2PI module consists of a standard SPI interface plus a + * single GPIO interrupt line. Furthermore, the SPI pins are + * accessible via GPIO control to allow a software emulation of + * additional protocols using the same pins. + * + * **SPI interface:** + * + * The SPI interface is based on a single function: + * + * #S2PI_TransferFrame. This function transfers a specified number + * of bytes via the interfaces MOSI line and simultaneously reads + * the incoming data on the MOSI line. The read can also be skipped. + * The transfer happen asynchronously, e.g. via a DMA request. After + * finishing the transfer, the provided callback is invoked with + * the status of the transfer and the provided abstract parameter. + * Furthermore, the functions receives a slave parameter that can + * be used to connect multiple slaves, each with its individual + * chip select line. + * + * The interface also provides functionality to change the SPI + * baud rate. An additional abort method is used to cancel the + * ongoing transfer. + * + * **GPIO interface:** + * + * The GPIO interface handles the measurement finished interrupt + * from the device. When the device invokes the interrupt, it pulls + * the interrupt line to low. Thus the interrupt must trigger when + * a transition from high to low occurs on the interrupt line. + * + * The module simply invokes a callback when this interrupt the + * pending. The #S2PI_SetIrqCallback method is used to install the + * callback for a specified slave. Each slave will have its own + * interrupt line. An additional callback parameter can be set that + * would be passed to the callback function. + * + * In addition to the interrupt, all SPI pins need to be accessible + * as GPIO pins through the interface. One basic operation would + * be to cycle the chip select pin which resets the device. + * Additional, the device contains an EEPROM that is connected to + * the SPI pins but requires a different protocol that is not + * compatible to any standard SPI interface. Therefore, the + * interface provides the possibility to switch to GPIO control + * that allows to emulate the EEPROM protocol via software bit + * banging. Two methods are provided to switch forth and back + * between SPI and GPIO control. In GPIO mode, several functions + * are used to read and write the individual GPIO pins. + * + * Note that the GPIO mode is only required to readout the EEPROM + * at initialization of the device, i.e. during execution of the + * #Argus_Init or #Argus_Reinit method. The GPIO mode is not used + * during measurements. + * + * + * @addtogroup argus_s2pi + * @{ + *****************************************************************************/ + +#include "api/argus_def.h" + +/*!*************************************************************************** + * @brief S2PI layer callback function type for the SPI transfer completed event. + * + * @param status The \link #status_t status\endlink of the completed + * transfer (#STATUS_OK on success). + * + * @param param The provided (optional, can be null) callback parameter. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +typedef status_t (*s2pi_callback_t)(status_t status, void *param); + +/*!*************************************************************************** + * @brief S2PI layer callback function type for the GPIO interrupt event. + * + * @param param The provided (optional, can be null) callback parameter. + *****************************************************************************/ +typedef void (*s2pi_irq_callback_t)(void *param); + +/*! The S2PI slave identifier. Basically an user defined enumerable type that + * can be used to identify the slave within the SPI module. */ +typedef int32_t s2pi_slave_t; + +/*! The enumeration of S2PI pins. */ +typedef enum { + /*! The SPI clock pin. */ + S2PI_CLK, + + /*! The SPI chip select pin. */ + S2PI_CS, + + /*! The SPI MOSI pin. */ + S2PI_MOSI, + + /*! The SPI MISO pin. */ + S2PI_MISO, + + /*! The IRQ pin. */ + S2PI_IRQ + +} s2pi_pin_t; + + +/*!*************************************************************************** + * @brief Returns the status of the SPI module. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_IDLE: No SPI transfer or GPIO access is ongoing. + * - #STATUS_BUSY: An SPI transfer is in progress. + * - #STATUS_S2PI_GPIO_MODE: The module is in GPIO mode. + *****************************************************************************/ +status_t S2PI_GetStatus(void); + +/*!*************************************************************************** + * @brief Transfers a single SPI frame asynchronously. + * + * @details Transfers a single SPI frame in asynchronous manner. The Tx data + * buffer is written to the device via the MOSI line. + * Optionally, the data on the MISO line is written to the provided + * Rx data buffer. If null, the read data is dismissed. Note that + * Rx and Tx buffer can be identical. I.e. the same buffer is used + * for writing and reading data. First, a byte is transmitted and + * the received byte overwrites the previously send value. + * + * The transfer of a single frame requires to not toggle the chip + * select line to high in between the data frame. The maximum + * number of bytes transfered in a single SPI transfer is given by + * the data value register of the device, which is 396 data bytes + * plus a single address byte: 397 bytes. + * + * An optional callback is invoked when the asynchronous transfer + * is finished. If the \p callback parameter is a null pointer, + * no callback is provided. Note that the provided buffer must not + * change while the transfer is ongoing. + * + * Use the slave parameter to determine the corresponding slave via the + * given chip select line. + * + * Usually, two distinct interrupts are required to handle the RX and + * TX ready events. The callback must be invoked from whichever + * interrupt comes after the SPI transfer has been finished. Note + * that new SPI transfers are invoked from within the callback function + * (i.e. from within the interrupt service routine of same priority). + * + * @param slave The specified S2PI slave. + * @param txData The 8-bit values to write to the SPI bus MOSI line. + * @param rxData The 8-bit values received from the SPI bus MISO line + * (pass a null pointer if the data don't need to be read). + * @param frameSize The number of 8-bit values to be sent/received. + * @param callback A callback function to be invoked when the transfer is + * finished. Pass a null pointer if no callback is required. + * @param callbackData A pointer to a state that will be passed to the + * callback. Pass a null pointer if not used. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK: Successfully invoked the transfer. + * - #ERROR_INVALID_ARGUMENT: An invalid parameter has been passed. + * - #ERROR_S2PI_INVALID_SLAVE: A wrong slave identifier is provided. + * - #STATUS_BUSY: An SPI transfer is already in progress. The + * transfer was not started. + * - #STATUS_S2PI_GPIO_MODE: The module is in GPIO mode. The transfer + * was not started. + *****************************************************************************/ +status_t S2PI_TransferFrame(s2pi_slave_t slave, + uint8_t const *txData, + uint8_t *rxData, + size_t frameSize, + s2pi_callback_t callback, + void *callbackData); + +/*!*************************************************************************** + * @brief Terminates a currently ongoing asynchronous SPI transfer. + * + * @details When a callback is set for the current ongoing activity, it is + * invoked with the #ERROR_ABORTED error byte. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_Abort(void); + +/*!*************************************************************************** + * @brief Set a callback for the GPIO IRQ for a specified S2PI slave. + * + * @param slave The specified S2PI slave. + * @param callback A callback function to be invoked when the specified + * S2PI slave IRQ occurs. Pass a null pointer to disable + * the callback. + * @param callbackData A pointer to a state that will be passed to the + * callback. Pass a null pointer if not used. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK: Successfully installation of the callback. + * - #ERROR_S2PI_INVALID_SLAVE: A wrong slave identifier is provided. + *****************************************************************************/ +status_t S2PI_SetIrqCallback(s2pi_slave_t slave, s2pi_irq_callback_t callback, void *callbackData); + +/*!*************************************************************************** + * @brief Reads the current status of the IRQ pin. + * + * @details In order to keep a low priority for GPIO IRQs, the state of the + * IRQ pin must be read in order to reliable check for chip timeouts. + * + * The execution of the interrupt service routine for the data-ready + * interrupt from the corresponding GPIO pin might be delayed due to + * priority issues. The delayed execution might disable the timeout + * for the eye-safety checker too late causing false error messages. + * In order to overcome the issue, the state of the IRQ GPIO input + * pin is read before raising a timeout error in order to check if + * the device has already finished but the IRQ is still pending to be + * executed! + + * @param slave The specified S2PI slave. + * @return Returns 1U if the IRQ pin is high (IRQ not pending) and 0U if the + * devices pulls the pin to low state (IRQ pending). + *****************************************************************************/ +uint32_t S2PI_ReadIrqPin(s2pi_slave_t slave); + +/*!*************************************************************************** + * @brief Cycles the chip select line. + * + * @details In order to cancel the integration on the ASIC, a fast toggling + * of the chip select pin of the corresponding SPI slave is required. + * Therefore, this function toggles the CS from high to low and back. + * The SPI instance for the specified S2PI slave must be idle, + * otherwise the status #STATUS_BUSY is returned. + * + * @param slave The specified S2PI slave. + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_CycleCsPin(s2pi_slave_t slave); + + + +/*!***************************************************************************** + * @brief Captures the S2PI pins for GPIO usage. + * + * @details The SPI is disabled (module status: #STATUS_S2PI_GPIO_MODE) and the + * pins are configured for GPIO operation. The GPIO control must be + * release with the #S2PI_ReleaseGpioControl function in order to + * switch back to ordinary SPI functionality. + * + * @note This function is only called during device initialization! + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_CaptureGpioControl(void); + +/*!***************************************************************************** + * @brief Releases the S2PI pins from GPIO usage and switches back to SPI mode. + * + * @details The GPIO pins are configured for SPI operation and the GPIO mode is + * left. Must be called if the pins are captured for GPIO operation via + * the #S2PI_CaptureGpioControl function. + * + * @note This function is only called during device initialization! + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_ReleaseGpioControl(void); + +/*!***************************************************************************** + * @brief Writes the output for a specified SPI pin in GPIO mode. + * + * @details This function writes the value of an SPI pin if the SPI pins are + * captured for GPIO operation via the #S2PI_CaptureGpioControl previously. + * + * @note Since some GPIO peripherals switch the GPIO pins very fast a delay + * must be added after each GBIO access (i.e. right before returning + * from the #S2PI_WriteGpioPin method) in order to decrease the baud + * rate of the software EEPROM protocol. Increase the delay if timing + * issues occur while reading the EERPOM. For example: + * Delay = 10 µsec => Baud Rate < 100 kHz + * + * @note This function is only called during device initialization! + * + * @param slave The specified S2PI slave. + * @param pin The specified S2PI pin. + * @param value The GPIO pin state to write (0 = low, 1 = high). + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_WriteGpioPin(s2pi_slave_t slave, s2pi_pin_t pin, uint32_t value); + +/*!***************************************************************************** + * @brief Reads the input from a specified SPI pin in GPIO mode. + * + * @details This function reads the value of an SPI pin if the SPI pins are + * captured for GPIO operation via the #S2PI_CaptureGpioControl previously. + * + * @note This function is only called during device initialization! + * + * @param slave The specified S2PI slave. + * @param pin The specified S2PI pin. + * @param value The GPIO pin state to read (0 = low, 1 = high). + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t S2PI_ReadGpioPin(s2pi_slave_t slave, s2pi_pin_t pin, uint32_t *value); + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif // ARGUS_S2PI_H diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_timer.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_timer.h new file mode 100644 index 0000000000..0390020aff --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/platform/argus_timer.h @@ -0,0 +1,267 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides an interface for the required timer modules. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_TIMER_H +#define ARGUS_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*!*************************************************************************** + * @defgroup argus_timer Timer: Hardware Timer Interface + * @ingroup argus_platform + * + * @brief Timer implementations for lifetime counting as well as periodic + * callback. + * + * @details The module provides an interface to the timing utilities that + * are required by the AFBR-S50 time-of-flight sensor API. + * + * Two essential features have to be provided by the user code: + * 1. Time Measurement Capability: In order to keep track of outgoing + * signals, the API needs to measure elapsed time. In order to + * provide optimum device performance, the granularity should be + * around 10 to 100 microseconds. + * 2. Periodic Callback: The API provides an automatic starting of + * measurement cycles at a fixed frame rate via a periodic + * interrupt timer. If this feature is not used, implementation + * of the periodic interrupts can be skipped. An weak default + * implementation is provide in the API. + * . + * + * The time measurement feature is simply implemented by the function + * #Timer_GetCounterValue. Whenever the function is called, the + * provided counter values must be written with the values obtained + * by the current time. + * + * The periodic interrupt timer is a simple callback interface. + * After installing the callback function pointer via #Timer_SetCallback, + * the timer can be started by setting interval via #Timer_SetInterval + * or #Timer_Start. From then, the callback is invoked periodically as + * the corresponding interval may specify. The timer is stopped via + * #Timer_Stop or by setting the interval to 0. The interval can be + * updated at any time by updating the interval via the #Timer_SetInterval + * function. To any of these functions, an abstract parameter pointer + * must be passed. This parameter is passed back to the callback any + * time it is invoked. + * + * In order to provide the usage of multiple devices, an mechanism is + * introduced to allow the installation of multiple callback interval + * at the same time. Therefore, the abstract parameter pointer is used + * to identify the corresponding callback interval. For example, there + * are two callbacks for two intervals, t1 and t2, required. The user + * can start two timers by calling the #Timer_Start method twice, but + * with an individual parameter pointer, ptr1 and ptr2, each: + * \code + * Timer_Start(100000, ptr1); // 10 ms callback w/ parameter ptr1 + * Timer_Start(200000, ptr2); // 20 ms callback w/ parameter ptr1 + * \endcode + * + * Note that the implemented timer module must therefore support + * as many different intervals as instances of the AFBR-S50 device are + * used. + * + * @addtogroup argus_timer + * @{ + *****************************************************************************/ + +#include "api/argus_def.h" + +/******************************************************************************* + * Lifetime Counter Timer Interface + ******************************************************************************/ + +/*!*************************************************************************** + * @brief Obtains the lifetime counter value from the timers. + * + * @details The function is required to get the current time relative to any + * point in time, e.g. the startup time. The returned values \p hct and + * \p lct are given in seconds and microseconds respectively. The current + * elapsed time since the reference time is then calculated from: + * + * t_now [µsec] = hct * 1000000 µsec + lct * 1 µsec + * + * Note that the accuracy/granularity of the lifetime counter does + * not need to be 1 µsec. Usually, a granularity of approximately + * 100 µsec is sufficient. However, in case of very high frame rates + * (above 1000 frames per second), it is recommended to implement + * an even lower granularity (somewhere in the 10 µsec regime). + * + * It must be guaranteed, that each call of the #Timer_GetCounterValue + * function must provide a value that is greater or equal, but never lower, + * than the value returned from the previous call. + * + * A hardware based implementation of the lifetime counter functionality + * would be to chain two distinct timers such that counter 2 increases + * its value when counter 1 wraps to 0. The easiest way is to setup + * counter 1 to wrap exactly every second. Counter 1 would than count + * the sub-seconds (i.e. µsec) value (\p lct) and counter 2 the seconds + * (\p hct) value. A 16-bit counter is sufficient in case of counter 1 + * while counter 2 must be a 32-bit version. + * + * In case of a lack of available hardware timers, a software solution + * can be used that requires only a 16-bit timer. In a simple scenario, + * the timer is configured to wrap around every second and increase + * a software counter value in its interrupt service routine (triggered + * with the wrap around event) every time the wrap around occurs. + * + * + * @note The implementation of this function is mandatory for the correct + * execution of the API. + * + * @param hct A pointer to the high counter value bits representing current + * time in seconds. + * + * @param lct A pointer to the low counter value bits representing current + * time in microseconds. Range: 0, .., 999999 µsec + *****************************************************************************/ +void Timer_GetCounterValue(uint32_t *hct, uint32_t *lct); + +/******************************************************************************* + * Periodic Interrupt Timer Interface + ******************************************************************************/ + +/*!*************************************************************************** + * @brief The callback function type for periodic interrupt timer. + * + * @details The function that is invoked every time a specified interval elapses. + * An abstract parameter is passed to the function whenever it is called. + * + * @param param An abstract parameter to be passed to the callback. This is + * also the identifier of the given interval. + *****************************************************************************/ +typedef void (*timer_cb_t)(void *param); + +/*!*************************************************************************** + * @brief Installs an periodic timer callback function. + * + * @details Installs an periodic timer callback function that is invoked whenever + * an interval elapses. The callback is the same for any interval, + * however, the single intervals can be identified by the passed + * parameter. + * Passing a zero-pointer removes and disables the callback. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disable the periodic timer callback + * and thus the automatic starting of measurements from the background. + * + * @param f The timer callback function. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Timer_SetCallback(timer_cb_t f); + +/*!*************************************************************************** + * @brief Sets the timer interval for a specified callback parameter. + * + * @details Sets the callback interval for the specified parameter and starts + * the timer with a new interval. If there is already an interval with + * the given parameter, the timer is restarted with the given interval. + * If the same time interval as already set is passed, nothing happens. + * Passing a interval of 0 disables the timer. + * + * Note that a microsecond granularity for the timer interrupt period is + * not required. Usually a microseconds granularity is sufficient. + * The required granularity depends on the targeted frame rate, e.g. in + * case of more than 1 kHz measurement rate, a granularity of less than + * a microsecond is required to achieve the given frame rate. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disable the periodic timer callback + * and thus the automatic starting of measurements from the background. + * + * @param dt_microseconds The callback interval in microseconds. + * + * @param param An abstract parameter to be passed to the callback. This is + * also the identifier of the given interval. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Timer_SetInterval(uint32_t dt_microseconds, void *param); + +/*!*************************************************************************** + * @brief Starts the timer for a specified callback parameter. + * + * @details Sets the callback interval for the specified parameter and starts + * the timer with a new interval. If there is already an interval with + * the given parameter, the timer is restarted with the given interval. + * Passing a interval of 0 disables the timer. + * + * Note that a microsecond granularity for the timer interrupt period is + * not required. Usually a microseconds granularity is sufficient. + * The required granularity depends on the targeted frame rate, e.g. in + * case of more than 1 kHz measurement rate, a granularity of less than + * a microsecond is required to achieve the given frame rate. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disable the periodic timer callback + * and thus the automatic starting of measurements from the background. + * + * @param dt_microseconds The callback interval in microseconds. + * + * @param param An abstract parameter to be passed to the callback. This is + * also the identifier of the given interval. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Timer_Start(uint32_t dt_microseconds, void *param); + +/*!*************************************************************************** + * @brief Stops the timer for a specified callback parameter. + * + * @details Stops a callback interval for the specified parameter. + * + * @note The implementation of this function is optional for the correct + * execution of the API. If not implemented, a weak implementation + * within the API will be used that disable the periodic timer callback + * and thus the automatic starting of measurements from the background. + * + * @param param An abstract parameter that identifies the interval to be stopped. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Timer_Stop(void *param); + +#ifdef __cplusplus +} +#endif + +/*! @} */ +#endif /* ARGUS_TIMER_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/utility/fp_def.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/utility/fp_def.h new file mode 100644 index 0000000000..06f39681e5 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/utility/fp_def.h @@ -0,0 +1,407 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details Provides definitions and basic macros for fixed point data types. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef FP_DEF_H +#define FP_DEF_H + +/*!*************************************************************************** + * @defgroup fixedpoint Fixed Point Math + * @ingroup argusutil + * @brief A basic math library for fixed point number in the Qx.y fomat. + * @details This module contains common fixed point type definitions as + * well as some basic math algorithms. All types are based on + * integer types. The number are defined with the Q number format. + * + * - For a description of the Q number format refer to: + * https://en.wikipedia.org/wiki/Q_(number_format) + * - Another resource for fixed point math in C might be found at + * http://www.eetimes.com/author.asp?section_id=36&doc_id=1287491 + * . + * @warning This definitions are not portable and work only with + * little-endian systems! + * @addtogroup fixedpoint + * @{ + *****************************************************************************/ + +#include + +/******************************************************************************* + * UQ6.2 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ6.2 + * @details An unsigned fixed point number format based on the 8-bit unsigned + * integer type with 6 integer and 2 fractional bits. + * - Range: 0 .. 63.75 + * - Granularity: 0.25 + *****************************************************************************/ +typedef uint8_t uq6_2_t; + + +/******************************************************************************* + * UQ4.4 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ4.4 + * @details An unsigned fixed point number format based on the 8-bit unsigned + * integer type with 4 integer and 4 fractional bits. + * - Range: 0 .. 15.9375 + * - Granularity: 0.0625 + *****************************************************************************/ +typedef uint8_t uq4_4_t; + +/*! Maximum value of UQ4.4 number format. */ +#define UQ4_4_MAX ((uq4_4_t)UINT8_MAX) + +/*! The 1/one/unity in UQ4.4 number format. */ +#define UQ4_4_ONE ((uq4_4_t)(1U<<4U)) + + +/******************************************************************************* + * UQ2.6 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ2.6 + * @details An unsigned fixed point number format based on the 8-bit unsigned + * integer type with 2 integer and 6 fractional bits. + * - Range: 0 .. 3.984375 + * - Granularity: 0.015625 + *****************************************************************************/ +typedef uint8_t uq2_6_t; + +/*! The 1/one/unity in UQ2.6 number format. */ +#define UQ2_6_ONE ((uq2_6_t)(1U<<6U)) + +/******************************************************************************* + * UQ1.7 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ1.7 + * @details An unsigned fixed point number format based on the 8-bit unsigned + * integer type with 1 integer and 7 fractional bits. + * - Range: 0 .. 1.9921875 + * - Granularity: 0.0078125 + *****************************************************************************/ +typedef uint8_t uq1_7_t; + +/******************************************************************************* + * Q0.7 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q0.7 + * @details An signed fixed point number format based on the 8-bit integer + * type with 0 integer and 7 fractional bits. + * - Range: -1 .. 0.9921875 + * - Granularity: 0.0078125 + *****************************************************************************/ +//typedef int8_t q0_7_t; + +/******************************************************************************* + * UQ0.8 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ0.8 + * @details An unsigned fixed point number format based on the 8-bit unsigned + * integer type with 1 integer and 7 fractional bits. + * - Range: 0 .. 0.99609375 + * - Granularity: 0.00390625 + *****************************************************************************/ +typedef uint8_t uq0_8_t; + +/*! Maximum value of UQ0.8 number format. */ +#define UQ0_8_MAX ((uq0_8_t)UINT8_MAX) + +/******************************************************************************* + * UQ12.4 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ12.4 + * @details An unsigned fixed point number format based on the 16-bit unsigned + * integer type with 12 integer and 4 fractional bits. + * - Range: 0 ... 4095.9375 + * - Granularity: 0.0625 + *****************************************************************************/ +typedef uint16_t uq12_4_t; + +/*! Maximum value of UQ12.4 number format. */ +#define UQ12_4_MAX ((uq12_4_t)UINT16_MAX) + +/*! The 1/one/unity in UQ12.4 number format. */ +#define UQ12_4_ONE ((uq12_4_t)(1U<<4U)) + +/******************************************************************************* + * Q11.4 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q11.4 + * @details An signed fixed point number format based on the 16-bit signed + * integer type with 11 integer and 4 fractional bits. + * - Range: -2048 ... 2047.9375 + * - Granularity: 0.0625 + *****************************************************************************/ +typedef int16_t q11_4_t; + +/*! The 1/one/unity in UQ11.4 number format. */ +#define UQ11_4_ONE ((q11_4_t)(1 << 4)) + +/*! Maximum value of Q11.4 number format. */ +#define Q11_4_MAX ((q11_4_t)INT16_MAX) + +/*! Minimum value of Q11.4 number format. */ +#define Q11_4_MIN ((q11_4_t)INT16_MIN) + +/******************************************************************************* + * UQ10.6 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ10.6 + * @details An unsigned fixed point number format based on the 16-bit unsigned + * integer type with 10 integer and 6 fractional bits. + * - Range: 0 ... 1023.984375 + * - Granularity: 0.015625 + *****************************************************************************/ +typedef uint16_t uq10_6_t; + +/*! Maximum value of UQ10.6 number format. */ +#define UQ10_6_MAX ((uq10_6_t)UINT16_MAX) + +/*! The 1/one/unity in UQ10.6 number format. */ +#define UQ10_6_ONE ((uq10_6_t)(1U << 6U)) + +/******************************************************************************* + * UQ1.15 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ1.15 + * @details An unsigned fixed point number format based on the 16-bit unsigned + * integer type with 1 integer and 15 fractional bits. + * - Range: 0 .. 1.999969 + * - Granularity: 0.000031 + *****************************************************************************/ +typedef uint16_t uq1_15_t; + +/*! Maximum value of UQ1.15 number format. */ +#define UQ1_15_MAX ((uq1_15_t)UINT16_MAX) + +/*! The 1/one/unity in UQ1.15 number format. */ +#define UQ1_15_ONE ((uq1_15_t)(1U << 15U)) + +/******************************************************************************* + * Q0.15 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q0.15 + * @details An signed fixed point number format based on the 16-bit integer + * type with 0 integer and 15 fractional bits. + * - Range: -1 .. 0.999969482 + * - Granularity: 0.000030518 + *****************************************************************************/ +typedef int16_t q0_15_t; + +/******************************************************************************* + * Q2.13 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q2.13 + * @details An signed fixed point number format based on the 16-bit integer + * type with 2 integer and 13 fractional bits. + * - Range: -4 .. 3.99987793 + * - Granularity: 0.00012207 + *****************************************************************************/ +//typedef int16_t q2_13_t; + +/******************************************************************************* + * Q13.2 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q13.2 + * @details An signed fixed point number format based on the 16-bit integer + * type with 13 integer and 2 fractional bits. + * - Range: -8192 .. 8191.75 + * - Granularity: 0.25 + *****************************************************************************/ +//typedef int16_t q13_2_t; + + +/******************************************************************************* + * Q3.12 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q3.12 + * @details An signed fixed point number format based on the 16-bit integer + * type with 3 integer and 12 fractional bits. + * - Range: -8 .. 7.99975586 + * - Granularity: 0.00024414 + *****************************************************************************/ +typedef int16_t q3_12_t; + + +/******************************************************************************* + * UQ0.16 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ0.16 + * @details An unsigned fixed point number format based on the 16-bit unsigned + * integer type with 0 integer and 16 fractional bits. + * - Range: 0 .. 0.9999847412109375 + * - Granularity: 1.52587890625e-5 + *****************************************************************************/ +typedef uint16_t uq0_16_t; + +/*! Maximum value of UQ0.16 number format. */ +#define UQ0_16_MAX ((uq0_16_t)UINT16_MAX) + +/*! The 1/one/unity in UQ0.16 number format. */ +#define UQ0_16_ONE ((uq0_16_t)(1U<<16U)) + +/******************************************************************************* + * UQ28.4 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ28.4 + * @details An unsigned fixed point number format based on the 32-bit unsigned + * integer type with 28 integer and 4 fractional bits. + * - Range: 0 ... 268435455.9375 + * - Granularity: 0.0625 + *****************************************************************************/ +typedef uint32_t uq28_4_t; + +/*! Maximum value of UQ28.4 number format. */ +#define UQ28_4_MAX ((uq28_4_t)UINT32_MAX) + +/*! The 1/one/unity in UQ28.4 number format. */ +#define UQ28_4_ONE ((uq28_4_t)(1U<<4U)) + +/******************************************************************************* + * Q27.4 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q27.4 + * @details An signed fixed point number format based on the 32-bit signed + * integer type with 27 integer and 4 fractional bits. + * - Range: -134217728 ... 134217727.9375 + * - Granularity: 0.0625 + *****************************************************************************/ +typedef int32_t q27_4_t; + +/*! The 1/one/unity in UQ27.4 number format. */ +#define UQ27_4_ONE ((q27_4_t)(1 << 4)) + +/*! Maximum value of Q27.4 number format. */ +#define Q27_4_MAX ((q27_4_t)INT32_MAX) + +/*! Minimum value of Q27.4 number format. */ +#define Q27_4_MIN ((q27_4_t)INT32_MIN) + + +/******************************************************************************* + * UQ16.16 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ16.16 + * @details An unsigned fixed point number format based on the 32-bit unsigned + * integer type with 16 integer and 16 fractional bits. + * - Range: 0 ... 65535.999984741 + * - Granularity: 0.000015259 + *****************************************************************************/ +typedef uint32_t uq16_16_t; + +/*! The 1/one/unity in UQ16.16 number format. */ +#define UQ16_16_ONE ((uq16_16_t)(1U << 16U)) + +/*! Maximum value of UQ16.16 number format. */ +#define UQ16_16_MAX ((uq16_16_t)UINT32_MAX) + +/*! Euler's number, e, in UQ16.16 format. */ +#define UQ16_16_E (0x2B7E1U) + + +/******************************************************************************* + * Q15.16 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q15.16 + * @details An signed fixed point number format based on the 32-bit integer + * type with 15 integer and 16 fractional bits. + * - Range: -32768 .. 32767.99998 + * - Granularity: 1.52588E-05 + *****************************************************************************/ +typedef int32_t q15_16_t; + +/*! The 1/one/unity in Q15.16 number format. */ +#define Q15_16_ONE ((q15_16_t)(1 << 16)) + +/*! Maximum value of Q15.16 number format. */ +#define Q15_16_MAX ((q15_16_t)INT32_MAX) + +/*! Minimum value of Q15.16 number format. */ +#define Q15_16_MIN ((q15_16_t)INT32_MIN) + +/******************************************************************************* + * UQ10.22 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Unsigned fixed point number: UQ10.22 + * @details An unsigned fixed point number format based on the 32-bit unsigned + * integer type with 10 integer and 22 fractional bits. + * - Range: 0 ... 1023.99999976158 + * - Granularity: 2.38418579101562E-07 + *****************************************************************************/ +typedef uint32_t uq10_22_t; + +/******************************************************************************* + * Q9.22 + ******************************************************************************/ +/*!*************************************************************************** + * @brief Signed fixed point number: Q9.22 + * @details An signed fixed point number format based on the 32-bit integer + * type with 9 integer and 22 fractional bits. + * - Range: -512 ... 511.9999998 + * - Granularity: 2.38418579101562E-07 + *****************************************************************************/ +typedef int32_t q9_22_t; + +/*! The 1/one/unity in Q9.22 number format. */ +#define Q9_22_ONE ((q9_22_t)(1 << 22)) + +/*! Maximum value of Q9.22 number format. */ +#define Q9_22_MAX ((q9_22_t)INT32_MAX) + +/*! Minimum value of Q9.22 number format. */ +#define Q9_22_MIN ((q9_22_t)INT32_MIN) + +/*! @} */ +#endif /* FP_DEF_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Inc/utility/time.h b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/utility/time.h new file mode 100644 index 0000000000..ed96f7337a --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/Inc/utility/time.h @@ -0,0 +1,290 @@ +/*************************************************************************//** + * @file + * @brief This file is part of the AFBR-S50 API. + * @details This file provides utility functions for timing necessities. + * + * @copyright + * + * Copyright (c) 2021, Broadcom Inc + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef TIME_H +#define TIME_H + +/*!*************************************************************************** + * @defgroup time Time Utility + * @ingroup argusutil + * @brief Timer utilities for time measurement duties. + * @details This module provides time measurement utility functions like + * delay or time measurement methods, or time math functions. + * @addtogroup time + * @{ + *****************************************************************************/ + +#include +#include + +/*!*************************************************************************** + * @brief A data structure to represent current time. + * + * @details Value is obtained from the PIT time which must be configured as + * lifetime counter. + *****************************************************************************/ +typedef struct { + /*! Seconds. */ + uint32_t sec; + + /*! Microseconds. */ + uint32_t usec; + +} ltc_t; + +/*!*************************************************************************** + * @brief Obtains the elapsed time since MCU startup. + * @param t_now returned current time + *****************************************************************************/ +void Time_GetNow(ltc_t *t_now); + +/*!*************************************************************************** + * @brief Obtains the elapsed microseconds since MCU startup. + * @details Wrap around effect due to uint32_t result format!! + * @param - + * @return Elapsed microseconds since MCU startup as uint32_t. + *****************************************************************************/ +uint32_t Time_GetNowUSec(void); + +/*!*************************************************************************** + * @brief Obtains the elapsed milliseconds since MCU startup. + * @details Wrap around effect due to uint32_t result format!! + * @param - + * @return Elapsed milliseconds since MCU startup as uint32_t. + *****************************************************************************/ +uint32_t Time_GetNowMSec(void); + +/*!*************************************************************************** + * @brief Obtains the elapsed seconds since MCU startup. + * @param - + * @return Elapsed seconds since MCU startup as uint32_t. + *****************************************************************************/ +uint32_t Time_GetNowSec(void); + +/*!*************************************************************************** + * @brief Obtains the elapsed time since a given time point. + * @param t_elapsed Returns the elapsed time since t_start. + * @param t_start Start time point. + *****************************************************************************/ +void Time_GetElapsed(ltc_t *t_elapsed, ltc_t *const t_start); + +/*!*************************************************************************** + * @brief Obtains the elapsed microseconds since a given time point. + * @details Wrap around effect due to uint32_t result format!! + * @param t_start Start time point. + * @return Elapsed microseconds since t_start as uint32_t. + *****************************************************************************/ +uint32_t Time_GetElapsedUSec(ltc_t *const t_start); + +/*!*************************************************************************** + * @brief Obtains the elapsed milliseconds since a given time point. + * @details Wrap around effect due to uint32_t result format!! + * @param t_start Start time point. + * @return Elapsed milliseconds since t_start as uint32_t. + *****************************************************************************/ +uint32_t Time_GetElapsedMSec(ltc_t *const t_start); + +/*!*************************************************************************** + * @brief Obtains the elapsed seconds since a given time point. + * @param t_start Start time point. + * @return Elapsed seconds since t_start as uint32_t. + *****************************************************************************/ +uint32_t Time_GetElapsedSec(ltc_t *const t_start); + +/*!*************************************************************************** + * @brief Obtains the time difference between two given time points. + * @details Result is defined as t_diff = t_end - t_start. + * Note: since no negative time differences are supported, t_end has + * to be later/larger than t_start. Otherwise, the result won't be + * a negative time span but given by max value. + * @param t_diff Returned time difference. + * @param t_start Start time point. + * @param t_end End time point. + *****************************************************************************/ +void Time_Diff(ltc_t *t_diff, ltc_t const *t_start, ltc_t const *t_end); + +/*!*************************************************************************** + * @brief Obtains the time difference between two given time points in + * microseconds. + * @details Result is defined as t_diff = t_end - t_start. + * Refers to Time_Diff() and handles overflow such that to large + * values are limited by 0xFFFFFFFF µs. + * @param t_start Start time point. + * @param t_end End time point. + * @return Time difference in microseconds. + *****************************************************************************/ +uint32_t Time_DiffUSec(ltc_t const *t_start, ltc_t const *t_end); + +/*!*************************************************************************** + * @brief Obtains the time difference between two given time points in + * milliseconds. + * @details Result is defined as t_diff = t_end - t_start. + * Refers to Time_Diff() and handles overflow. + * Wrap around effect due to uint32_t result format!! + * @param t_start Start time point. + * @param t_end End time point. + * @return Time difference in milliseconds. + *****************************************************************************/ +uint32_t Time_DiffMSec(ltc_t const *t_start, ltc_t const *t_end); + +/*!*************************************************************************** + * @brief Obtains the time difference between two given time points in + * seconds. + * @details Result is defined as t_diff = t_end - t_start. + * Refers to Time_Diff() and handles overflow. + * @param t_start Start time point. + * @param t_end End time point. + * @return Time difference in seconds. + *****************************************************************************/ +uint32_t Time_DiffSec(ltc_t const *t_start, ltc_t const *t_end); + +/*!*************************************************************************** + * @brief Time delay for a given time period. + * @param dt Delay time. + *****************************************************************************/ +void Time_Delay(ltc_t const *dt); + +/*!*************************************************************************** + * @brief Time delay for a given time period in microseconds. + * @param dt_usec Delay time in microseconds. + *****************************************************************************/ +void Time_DelayUSec(uint32_t dt_usec); + +/*!*************************************************************************** + * @brief Time delay for a given time period in milliseconds. + * @param dt_msec Delay time in milliseconds. + *****************************************************************************/ +void Time_DelayMSec(uint32_t dt_msec); + +/*!*************************************************************************** + * @brief Time delay for a given time period in seconds. + * @param dt_sec Delay time in seconds. + *****************************************************************************/ +void Time_DelaySec(uint32_t dt_sec); + +/*!*************************************************************************** + * @brief Checks if timeout is reached from a given starting time. + * @details Handles overflow. + * @param t_start Start time. + * @param t_timeout Timeout period. + * @return Timeout elapsed? True/False (boolean value) + *****************************************************************************/ +bool Time_CheckTimeout(ltc_t const *t_start, ltc_t const *t_timeout); + +/*!*************************************************************************** + * @brief Checks if timeout is reached from a given starting time. + * @details Handles overflow. + * @param t_start Start time. + * @param t_timeout_usec Timeout period in microseconds. + * @return Timeout elapsed? True/False (boolean value) + *****************************************************************************/ +bool Time_CheckTimeoutUSec(ltc_t const *t_start, uint32_t const t_timeout_usec); + +/*!*************************************************************************** + * @brief Checks if timeout is reached from a given starting time. + * @details Handles overflow. + * @param t_start Start time. + * @param t_timeout_msec Timeout period in milliseconds. + * @return Timeout elapsed? True/False (boolean value) + *****************************************************************************/ +bool Time_CheckTimeoutMSec(ltc_t const *t_start, uint32_t const t_timeout_msec); + +/*!*************************************************************************** + * @brief Checks if timeout is reached from a given starting time. + * @details Handles overflow. + * @param t_start Start time. + * @param t_timeout_sec Timeout period in seconds. + * @return Timeout elapsed? True/False (boolean value) + *****************************************************************************/ +bool Time_CheckTimeoutSec(ltc_t const *t_start, uint32_t const t_timeout_sec); + +/*!*************************************************************************** + * @brief Adds two ltc_t values. + * @details Result is defined as t = t1 + t2. Results are wrapped around at + * maximum values just like integers. + * @param t Return value: t = t1 + t2. + * @param t1 1st operand. + * @param t2 2nd operand. + *****************************************************************************/ +void Time_Add(ltc_t *t, ltc_t const *t1, ltc_t const *t2); + +/*!*************************************************************************** + * @brief Adds a given time in microseconds to an ltc_t value. + * @param t Return value: t = t1 + t2. + * @param t1 1st operand. + * @param t2_usec 2nd operand in microseconds. + *****************************************************************************/ +void Time_AddUSec(ltc_t *t, ltc_t const *t1, uint32_t t2_usec); + +/*!*************************************************************************** + * @brief Adds a given time in milliseconds to an ltc_t value. + * @param t Return value: t = t1 + t2. + * @param t1 1st operand. + * @param t2_msec 2nd operand in milliseconds. + *****************************************************************************/ +void Time_AddMSec(ltc_t *t, ltc_t const *t1, uint32_t t2_msec); + +/*!*************************************************************************** + * @brief Adds a given time in seconds to an ltc_t value. + * @param t Return value: t = t1 + t2. + * @param t1 1st operand. + * @param t2_sec 2nd operand in seconds. + *****************************************************************************/ +void Time_AddSec(ltc_t *t, ltc_t const *t1, uint32_t t2_sec); + +/*!*************************************************************************** + * @brief Converts ltc_t to microseconds (uint32_t). + * @param t Input ltc_t struct. + * @return Time value in microseconds. + *****************************************************************************/ +uint32_t Time_ToUSec(ltc_t const *t); + +/*!*************************************************************************** + * @brief Converts ltc_t to milliseconds (uint32_t). + * @param t Input ltc_t struct. + * @return Time value in milliseconds. + *****************************************************************************/ +uint32_t Time_ToMSec(ltc_t const *t); + +/*!*************************************************************************** + * @brief Converts ltc_t to seconds (uint32_t). + * @param t Input ltc_t struct. + * @return Time value in seconds. + *****************************************************************************/ +uint32_t Time_ToSec(ltc_t const *t); + +/*! @} */ +#endif /* TIME_H */ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Lib/libafbrs50_m4_fpu.a b/src/drivers/distance_sensor/broadcom/afbrs50/Lib/libafbrs50_m4_fpu.a new file mode 100644 index 0000000000..b99488bb4b Binary files /dev/null and b/src/drivers/distance_sensor/broadcom/afbrs50/Lib/libafbrs50_m4_fpu.a differ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/Lib/libafbrs50_m4_fpu_os.a b/src/drivers/distance_sensor/broadcom/afbrs50/Lib/libafbrs50_m4_fpu_os.a new file mode 100644 index 0000000000..ae1c4f1d89 Binary files /dev/null and b/src/drivers/distance_sensor/broadcom/afbrs50/Lib/libafbrs50_m4_fpu_os.a differ diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/argus_hal_test.c b/src/drivers/distance_sensor/broadcom/afbrs50/argus_hal_test.c new file mode 100644 index 0000000000..520a438bf3 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/argus_hal_test.c @@ -0,0 +1,1174 @@ +/*************************************************************************//** + * @file argus_hal_test.c + * @brief Tests for the AFBR-S50 API hardware abstraction layer. + * + * @copyright + * + * Copyright (c) 2021, Broadcom, Inc. + * 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 of the copyright holder 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 HOLDER 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 Files + ******************************************************************************/ +#include "argus_hal_test.h" + +#include "platform/argus_print.h" +#include "platform/argus_s2pi.h" +#include "platform/argus_timer.h" +#include "platform/argus_nvm.h" +#include "platform/argus_irq.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! An error log message via print(); */ +#define error_log(fmt, ...) print("ERROR: " fmt "\n", ##__VA_ARGS__) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static status_t TimerPlausibilityTest(void); +static status_t TimerWraparoundTest(void); +static status_t SpiConnectionTest(s2pi_slave_t slave); +static status_t SpiInterruptTest(s2pi_slave_t slave); +static status_t GpioModeTest(s2pi_slave_t slave); +static status_t TimerTest(s2pi_slave_t slave); + +static status_t CheckTimerCounterValues(uint32_t hct, uint32_t lct); +static status_t SPITransferSync(s2pi_slave_t slave, uint8_t *data, uint8_t size); +static status_t ConfigureDevice(s2pi_slave_t slave, int8_t rcoTrim); +static status_t TriggerMeasurement(s2pi_slave_t slave, uint16_t samples); +static status_t AwaitDataReady(s2pi_slave_t slave, uint32_t timeout_ms); +static status_t ReadEEPROM(s2pi_slave_t slave, uint8_t *eeprom); +static status_t ReadRcoTrim(s2pi_slave_t slave, int8_t *RcoTrim); +static status_t RunMeasurement(s2pi_slave_t slave, uint16_t samples); + +static void DataReadyCallback(void *param); + +extern uint32_t EEPROM_ReadChipId(uint8_t const *eeprom); +extern argus_module_version_t EEPROM_ReadModule(uint8_t const *eeprom); +extern status_t EEPROM_Read(s2pi_slave_t slave, uint8_t address, uint8_t *data); +extern uint8_t hamming_decode(uint8_t const *code, uint8_t *data); + +/****************************************************************************** + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t Argus_VerifyHALImplementation(s2pi_slave_t spi_slave) +{ + status_t status = STATUS_OK; + + print("########################################################\n"); + print("# Running HAL Verification Test - " HAL_TEST_VERSION "\n"); + print("########################################################\n\n"); + + print("1 > Timer Plausibility Test\n"); + status = TimerPlausibilityTest(); + + if (status != STATUS_OK) { goto summary; } + + print("1 > PASS\n\n"); + + print("2 > Timer Wraparound Test\n"); + status = TimerWraparoundTest(); + + if (status != STATUS_OK) { goto summary; } + + print("2 > PASS\n\n"); + + print("3 > SPI Connection Test\n"); + status = SpiConnectionTest(spi_slave); + + if (status != STATUS_OK) { goto summary; } + + print("3 > PASS\n\n"); + + print("4 > SPI Interrupt Test\n"); + status = SpiInterruptTest(spi_slave); + + if (status != STATUS_OK) { goto summary; } + + print("4 > PASS\n\n"); + + print("5 > GPIO Mode Test\n"); + status = GpioModeTest(spi_slave); + + if (status != STATUS_OK) { goto summary; } + + print("5 > PASS\n\n"); + + print("6 > Timer Test\n"); + status = TimerTest(spi_slave); + + if (status != STATUS_OK) { goto summary; } + + print("6 > PASS\n\n"); + +summary: + print("########################################################\n"); + + if (status != STATUS_OK) { + print("# FAIL: HAL Verification Test finished with error %d!\n", status); + + } else { + print("# PASS: HAL Verification Test finished successfully!\n"); + } + + print("########################################################\n\n"); + return status; +} + +/*!*************************************************************************** + * @brief Checks the validity of timer counter values. + * + * @details This verifies that the counter values returned from the + * #Timer_GetCounterValue function are valid. This means, the low + * counter value \p lct is within 0 and 999999 μs. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_FAIL on failure (check the error log for more information). + *****************************************************************************/ +static status_t CheckTimerCounterValues(uint32_t hct, uint32_t lct) +{ + if (lct > 999999) { + error_log("Timer plausibility check:\n" + "The parameter \"lct\" of Timer_GetCounterValue() must always " + "be within 0 and 999999.\n" + "Current Values: hct = %d, lct = %d", hct, lct); + return ERROR_FAIL; + } + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief Plausibility Test for Timer HAL Implementation. + * + * @details Rudimentary tests the lifetime counter (LTC) implementation. + * This verifies that the LTC is running by checking if the returned + * values of two consecutive calls to the #Timer_GetCounterValue + * function are ascending. An artificial delay using the NOP operation + * is induced such that the timer is not read to fast. + * + * @warning If using an ultra-fast processor with a rather low timer granularity, + * the test may fail! In this case, it could help to increase the delay + * by increasing the for-loop exit criteria. + * + * @warning This test does not test yet verify if the timing is correct at all! + * This it done in later test... + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_FAIL on failure (check the error log for more information). + *****************************************************************************/ +static status_t TimerPlausibilityTest(void) +{ + uint32_t hct0 = 0; + uint32_t lct0 = 0; + uint32_t hct1 = 0; + uint32_t lct1 = 0; + + /* Get some start values */ + Timer_GetCounterValue(&hct0, &lct0); + + /* Check max value is not exceeded for LCT timer (us) */ + status_t status = CheckTimerCounterValues(hct0, lct0); + + if (status < STATUS_OK) { return status; } + + /* Adding a delay. Depending on MCU speed, this takes any time. + * However, the Timer should be able to solve this on any MCU. */ + for (volatile uint32_t i = 0; i < 100000; ++i) { __asm("nop"); } + + /* Get new timer value and verify some time has elapsed. */ + Timer_GetCounterValue(&hct1, &lct1); + + /* Check max value is not exceeded for LCT timer (us) */ + status = CheckTimerCounterValues(hct1, lct1); + + if (status < STATUS_OK) { return status; } + + /* Either the hct value must have been increased or the lct value if the hct + * value is still the same. */ + if (!((hct1 > hct0) || ((hct1 == hct0) && (lct1 > lct0)))) { + error_log("Timer plausibility check: the elapsed time could not be " + "measured with the Timer_GetCounterValue() function; no time " + "has elapsed!\n" + "The delay was induced by the following code:\n" + "for (volatile uint32_t i = 0; i < 100000; ++i) __asm(\"nop\");\n", + "Current Values: hct0 = %d, lct0 = %d, hct1 = %d, lct1 = %d", + hct0, lct0, hct1, lct1); + return ERROR_FAIL; + } + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief Wraparound Test for the Timer HAL Implementation. + * + * @details The LTC values must wrap from 999999 μs to 0 μs and increase the + * seconds counter accordingly. This test verifies the correct wrapping + * by consecutively calling the #Timer_GetCounterValue function until + * at least 2 wraparound events have been occurred. + * + * @note This test requires the timer to basically run and return ascending + * values. Also, if the timer is too slow, this may take very long! + * Usually, the test takes 2 seconds, since 2 wraparound events are + * verified. + * + * @warning This test does not test yet verify if the timing is correct at all! + * This it done in later test... + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_FAIL on failure (check the error log for more information). + *****************************************************************************/ +static status_t TimerWraparoundTest(void) +{ + /* Test parameter configuration: *****************************************/ + const int8_t n = 2; // The number of wraparounds to test. + /*************************************************************************/ + + uint32_t hct0 = 0; + uint32_t lct0 = 0; + uint32_t hct1 = 0; + uint32_t lct1 = 0; + + /* Get some start values. */ + Timer_GetCounterValue(&hct0, &lct0); + + /* Check max value is not exceeded for LCT timer (us) */ + status_t status = CheckTimerCounterValues(hct0, lct0); + + if (status < STATUS_OK) { return status; } + + /* Set end after 2 seconds, i.e. 2 wrap around events. */ + uint32_t hct2 = hct0 + n; + uint32_t lct2 = lct0; + + /* Periodically read timer values. From previous tests we + * already know the timer value is increasing. */ + while (hct0 < hct2 || lct0 < lct2) { + /* add counter a , which is increasing by +1, 1000000 or 1000, + * different MCU different times get stuck for hard code value */ + Timer_GetCounterValue(&hct1, &lct1); + + /* Check max value is not exceeded for LCT timer (us) */ + status = CheckTimerCounterValues(hct0, lct0); + + if (status < STATUS_OK) { return status; } + + /* Testing if calls to Timer_GetCounterValue are equal or increasing. + * Also testing if wraparound is correctly handled. + * Assumption here is that two sequential calls to the get functions are + * only a few µs appart! I.e. if hct wraps, the new lct must be smaller + * than previous one. */ + if (!(((hct1 == hct0 + 1) && (lct1 < lct0)) + || ((hct1 == hct0) && (lct1 >= lct0)))) { + error_log("Timer plausibility check: the wraparound of \"lct\" or " + "\"hct\" parameters of the Timer_GetCounterValue() " + "function was not handled correctly!\n" + "Current Values: hct0 = %d, lct0 = %d, hct1 = %d, lct1 = %d", + hct0, lct0, hct1, lct1); + return ERROR_FAIL; + } + + hct0 = hct1; + lct0 = lct1; + } + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief Helper function for transfer data to SPI in blocking mode. + * + * @details Calls the #S2PI_TransferFrame function and waits until the transfer + * has been finished by checking the #S2PI_GetStatus return code to + * become #STATUS_IDLE (or #STATUS_OK). + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param data The data array to be transfered. + * @param size The size of the data array to be transfered. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if the operation did not finished within a specified + * time (check also timer HAL implementation). + * - The S2PI layer error code if #S2PI_TransferFrame or #S2PI_GetStatus + * return any negative status. + *****************************************************************************/ +static status_t SPITransferSync(s2pi_slave_t slave, uint8_t *data, uint8_t size) +{ + /* Test parameter configuration: *****************************************/ + const uint32_t timeout_ms = 100; // The transfer timeout in ms. + /*************************************************************************/ + + status_t status = S2PI_TransferFrame(slave, data, data, size, 0, 0); + + if (status < STATUS_OK) { + error_log("SPI transfer failed! The call to S2PI_TransferFrame " + "yielded error code: %d", status); + return status; + } + + /* Wait until the transfer is finished using a timeout. + * Note: this already utilizes the timer HAL. So we might + * need to test the timer before the SPI connection test. */ + ltc_t start; + Time_GetNow(&start); + + do { + status = S2PI_GetStatus(); + + if (status < STATUS_OK) { + error_log("SPI transfer failed! The call to S2PI_GetStatus " + "yielded error code: %d", status); + S2PI_Abort(); + return status; + } + + if (Time_CheckTimeoutMSec(&start, timeout_ms)) { + error_log("SPI transfer failed! The operation did not finished " + "within %d ms. This may also be caused by an invalid " + "timer implementation!", timeout_ms); + return ERROR_TIMEOUT; + } + } while (status == STATUS_BUSY); + + return status; +} + +/*!*************************************************************************** + * @brief SPI Connection Test for S2PI HAL Implementation. + * + * @details This test verifies the basic functionality of the SPI interface. + * The test utilizes the devices laser pattern register, which can + * be freely programmed by any 128-bit pattern. Thus, it writes a byte + * sequence and reads back the written values on the consecutive SPI + * access. + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if the operation did not finished within a specified + * time (check also timer HAL implementation). + * - #ERROR_FAIL if the device access failed and the read data did not + * match the expected values. + * - The S2PI layer error code if #S2PI_TransferFrame or #S2PI_GetStatus + * return any negative status. + *****************************************************************************/ +static status_t SpiConnectionTest(s2pi_slave_t slave) +{ + status_t status = STATUS_OK; + uint8_t data[17U] = { 0 }; + + /* Transfer a pattern to the register */ + data[0] = 0x04; // Laser Pattern Register Address + + for (uint8_t i = 1; i < 17U; ++i) { data[i] = i; } + + status = SPITransferSync(slave, data, 17U); + + if (status < STATUS_OK) { + error_log("SPI connection test failed!"); + return status; + } + + /* Clear the laser pattern and read back previous values. */ + data[0] = 0x04; // Laser Pattern Register Address + + for (uint8_t i = 1; i < 17U; ++i) { data[i] = 0; } + + status = SPITransferSync(slave, data, 17U); + + if (status < STATUS_OK) { + error_log("SPI connection test failed!"); + return status; + } + + /* Verify the read pattern. */ + for (uint8_t i = 1; i < 17U; ++i) { + if (data[i] != i) { + error_log("SPI connection test failed!\n" + "Verification of read data is invalid!\n" + "read_data[%d] = %d, but expected was %d", + i, data[i], i); + return ERROR_FAIL; + } + } + + return STATUS_OK; +} + + +/*!*************************************************************************** + * @brief The data ready callback invoked by the API. + * + * @details The callback is invoked by the API when the device GPIO IRQ is + * pending after a measurement has been executed and data is ready to + * be read from the device. + * + * @param param The abstract pointer to the boolean value that determines if + * the callback is invoked. + *****************************************************************************/ +static void DataReadyCallback(void *param) +{ + IRQ_LOCK(); + *((bool *) param) = true; + IRQ_UNLOCK(); +} + +/*!*************************************************************************** + * @brief Configures the device with a bare minimum setup to run the tests. + * + * @details This function applies a number of configuration values to the + * device, such that a pseudo measurement w/o laser output can be + * performed. + * + * A \p rcoTrim parameter can be passed to adjust the actual clock + * setup. + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param rcoTrim The RCO Trimming value added to the nominal RCO register + * value. Pass 0 if no fine tuning is required. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if the SPI operation did not finished within a + * specified time (check also timer HAL implementation). + * - The S2PI layer error code if #S2PI_TransferFrame or #S2PI_GetStatus + * return any negative status. + *****************************************************************************/ +static status_t ConfigureDevice(s2pi_slave_t slave, int8_t rcoTrim) +{ + /* Setup Device and Trigger Measurement. */ + uint16_t v = 0x0010U | (((34 + rcoTrim) & 0x3F) << 6); + uint8_t d1[] = { 0x14, v >> 8, v & 0xFF, 0x21 }; + status_t status = SPITransferSync(slave, d1, sizeof(d1)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d2[] = { 0x16, 0x7F, 0xFF, 0x7F, 0xE9 }; + status = SPITransferSync(slave, d2, sizeof(d2)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d3[] = { 0x18, 0x00, 0x00, 0x03 }; + status = SPITransferSync(slave, d3, sizeof(d3)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d4[] = { 0x10, 0x12 }; + status = SPITransferSync(slave, d4, sizeof(d4)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d5[] = { 0x12, 0x00, 0x2B }; + status = SPITransferSync(slave, d5, sizeof(d5)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d6[] = { 0x08, 0x04, 0x84, 0x10 }; + status = SPITransferSync(slave, d6, sizeof(d6)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d7[] = { 0x0A, 0xFE, 0x51, 0x0F, 0x05 }; + status = SPITransferSync(slave, d7, sizeof(d7)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d8[] = { 0x0C, 0x00, 0x00, 0x00 }; + status = SPITransferSync(slave, d8, sizeof(d8)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d9[] = { 0x1E, 0x00, 0x00, 0x00 }; + status = SPITransferSync(slave, d9, sizeof(d9)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d10[] = { 0x20, 0x01, 0xFF, 0xFF }; + status = SPITransferSync(slave, d10, sizeof(d10)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + uint8_t d11[] = { 0x22, 0xFF, 0xFF, 0x04 }; + status = SPITransferSync(slave, d11, sizeof(d11)); + + if (status < STATUS_OK) { + error_log("Device configuration failed!"); + return status; + } + + return status; +} + +/*!*************************************************************************** + * @brief Triggers a measurement on the device with specified sample count. + * + * @details The function triggers a measurement cycle on the device. A + * \p sample count can be specified to setup individual number of + * digital averaging. + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param samples The specified number of averaging samples for the measurement. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if the operation did not finished within a specified + * time (check also timer HAL implementation). + * - The S2PI layer error code if #S2PI_TransferFrame or #S2PI_GetStatus + * return any negative status. + *****************************************************************************/ +static status_t TriggerMeasurement(s2pi_slave_t slave, uint16_t samples) +{ + // samples is zero based, i.e. writing 0 yields 1 sample + samples = samples > 0 ? samples - 1 : samples; + uint16_t v = 0x8000U | ((samples & 0x03FFU) << 5U); + uint8_t d[] = { 0x1C, v >> 8, v & 0xFFU }; + status_t status = SPITransferSync(slave, d, sizeof(d)); + + if (status < STATUS_OK) { + error_log("Trigger measurement failed!"); + return status; + } + + return status; +} + +/*!*************************************************************************** + * @brief Waits for the data ready interrupt to be pending. + * + * @details The function polls the current interrupt pending state of the data + * ready interrupt from the device, i.e. reads the IRQ GPIO pin until + * it is pulled to low by the device. + * + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param timeout_ms The timeout to cancel waiting for the IRQ. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if either the SPI operation did not finished + * or the IRQ was not detected within a specified time (check also + * timer HAL implementation). + * - The S2PI layer error code if #S2PI_TransferFrame, #S2PI_GetStatus + * or #S2PI_SetIrqCallback return any negative status. + *****************************************************************************/ +static status_t AwaitDataReady(s2pi_slave_t slave, uint32_t timeout_ms) +{ + ltc_t start; + Time_GetNow(&start); + + while (S2PI_ReadIrqPin(slave)) { + if (Time_CheckTimeoutMSec(&start, timeout_ms)) { + error_log("SPI interrupt test failed! The S2PI_ReadIrqPin did not " + "determine an pending interrupt within %d ms.", timeout_ms); + return ERROR_TIMEOUT; + } + } + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief SPI Interrupt Test for S2PI HAL Implementation. + * + * @details This test verifies the correct implementation of the device + * integration finished interrupt callback. Therefore it configures + * the device with a minimal setup to run a pseudo measurement that + * does not emit any laser light. + * + * Note that this test does verify the GPIO interrupt that occurs + * whenever the device has finished the integration/measurement and + * new data is waiting to be read from the device. This does not test + * the interrupt that is triggered when the SPI transfer has finished. + * + * The data ready interrupt implies two S2PI layer functions that + * are tested in this test: The #S2PI_SetIrqCallback function installs + * a callback function that is invoked whenever the IRQ occurs. + * The IRQ can be delayed due to higher priority task, e.g. from the + * user code. It is essential for the laser safety timeout algorithm + * to determine the device ready signal as fast as possible, another + * method is implemented to read if the IRQ is pending but the + * callback has not been reset yet. This is what the #S2PI_ReadIrqPin + * function is for. + * + * + * @warning The test assumes the device is in a fresh power on state and no + * additional reset is required. If the test fail, one may want to + * power cycle the device and try again. + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if either the SPI operation did not finished + * or the IRQ was not detected within a specified time (check also + * timer HAL implementation). + * - #ERROR_FAIL if the IRQ pin readout failed and the no or invalid + * interrupt was detected. + * - The S2PI layer error code if #S2PI_TransferFrame, #S2PI_GetStatus + * or #S2PI_SetIrqCallback return any negative status. + *****************************************************************************/ +static status_t SpiInterruptTest(s2pi_slave_t slave) +{ + /* Test parameter configuration: *****************************************/ + const uint32_t timeout_ms = 300; // timeout for measurement, might be increased.. + /*************************************************************************/ + + /* Install IRQ callback. */ + volatile bool isDataReady = false; + status_t status = S2PI_SetIrqCallback(slave, DataReadyCallback, (void *)&isDataReady); + + if (status < STATUS_OK) { + error_log("SPI interrupt test failed! The call to S2PI_SetIrqCallback " + "yielded error code: %d", status); + return status; + } + + /* Check if IRQ is not yet pending. */ + if (S2PI_ReadIrqPin(slave) == 0) { + error_log("SPI interrupt test failed! The S2PI_ReadIrqPin did " + "return 0 but no interrupt is pending since no " + "measurements are executed yet!"); + return ERROR_FAIL; + }; + + /* Setup Device. */ + status = ConfigureDevice(slave, 0); + + if (status < STATUS_OK) { + error_log("SPI interrupt test failed!"); + return status; + } + + /* Trigger Measurement. */ + status = TriggerMeasurement(slave, 0); + + if (status < STATUS_OK) { + error_log("SPI interrupt test failed!"); + return status; + } + + ltc_t start; + Time_GetNow(&start); + + /* Wait for Interrupt using the S2PI_ReadIrqPin method. */ + status = AwaitDataReady(slave, timeout_ms); + + if (status < STATUS_OK) { + error_log("SPI interrupt test failed!"); + return status; + } + + /* Wait for Interrupt using the callback method. */ + while (!isDataReady) { + if (Time_CheckTimeoutMSec(&start, timeout_ms)) { + error_log("SPI interrupt test failed! The IRQ callback was not " + "invoked within %d ms.", timeout_ms); + return ERROR_TIMEOUT; + } + } + + /* Remove callback. */ + status = S2PI_SetIrqCallback(slave, 0, 0); + + if (status < STATUS_OK) { + error_log("SPI interrupt test failed! The call to S2PI_SetIrqCallback " + "with null pointers yielded error code: %d", status); + return status; + } + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief Reads the EEPROM bytewise and applies Hamming weight. + * @details The EEPROM bytes are consecutevly read from the device via GPIO mode. + * The #EEPROM_Read function is an internal API function that enables + * the GPIO mode from the S2PI module and reads the data via a software + * bit-banging protocol. Finally it disables the GPIO mode and returns + * to SPI mode. + * + * The calls to S2PI HAL module is as follows: + * 1. S2PI_CaptureGpioControl + * 2. multiple calls to S2PI_WriteGpioPin and S2PI_ReadGpioPin + * 3. S2PI_ReleaseGpioControl + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param eeprom The 16 byte array to be filled with EEPROM data. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #STATUS_ARGUS_EEPROM_BIT_ERROR if the Hamming weight fails. + * interrupt was detected. + * - The S2PI layer error code if #S2PI_CaptureGpioControl, + * #S2PI_ReleaseGpioControl, #S2PI_WriteGpioPin or + * #S2PI_ReadGpioPin return any negative status. + *****************************************************************************/ +static status_t ReadEEPROM(s2pi_slave_t slave, uint8_t *eeprom) +{ + /* Enable EEPROM: */ + uint8_t d1[] = { 0x12, 0x00, 0x4B }; + status_t status = SPITransferSync(slave, d1, sizeof(d1)); + + if (status < STATUS_OK) { + error_log("EEPROM readout failed (enable EEPROM), " + "error code: %d", status); + return status; + } + + uint8_t data[16] = { 0 }; + + /* Readout Data */ + for (uint8_t address = 0; address < 16; address++) { + status = EEPROM_Read(slave, address, &data[address]); + + if (status != STATUS_OK) { + error_log("EEPROM readout failed @ address 0x%02x, " + "error code: %d!", address, status); + return status; + } + } + + /* Disable EEPROM: */ + uint8_t d2[] = { 0x12, 0x00, 0x2B }; + status = SPITransferSync(slave, d2, sizeof(d2)); + + if (status < STATUS_OK) { + error_log("EEPROM readout failed (enable EEPROM), " + "error code: %d", status); + return status; + } + + /* Apply Hamming Code */ + uint8_t err = hamming_decode(data, eeprom); + + if (err != 0) { + error_log("EEPROM readout failed! Failed to decoding " + "Hamming weight (error: %d)!", err); + return STATUS_ARGUS_EEPROM_BIT_ERROR; + } + + /* Add remaining bit to the end. */ + eeprom[15] = data[15] & 0x80U; + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief GPIO Mode Test for S2PI HAL Implementation. + * + * @details This test verifies the GPIO mode of the S2PI HAL module. This is + * done by leveraging the EEPROM readout sequence that accesses the + * devices EEPROM via a software protocol that depends on the GPIO + * mode. + * + * This the requires several steps, most of them are already verified + * in previous tests: + * - Basic device configuration and enable EEPROM. + * - Read EERPOM via GPIO mode and apply Hamming weight + * - Repeat several times (to eliminate random readout issues). + * - Decode the EEPROM (using EEPROM_Decode in argus_cal_eeprom.c) + * - Check if Module Number and Chip ID is not 0 + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_FAIL if the GPIO test fails. + * - #STATUS_ARGUS_EEPROM_BIT_ERROR if the Hamming weight fails. + * - The S2PI layer error code if #S2PI_CaptureGpioControl, + * #S2PI_ReleaseGpioControl, #S2PI_WriteGpioPin or + * #S2PI_ReadGpioPin return any negative status. + *****************************************************************************/ +static status_t GpioModeTest(s2pi_slave_t slave) +{ + /* Read EEPROM 3 times and verify. */ + uint8_t eeprom1[16] = { 0 }; + uint8_t eeprom2[16] = { 0 }; + uint8_t eeprom3[16] = { 0 }; + + status_t status = ReadEEPROM(slave, eeprom1); + + if (status < STATUS_OK) { + error_log("GPIO mode test failed (1st attempt)!"); + return status; + } + + status = ReadEEPROM(slave, eeprom2); + + if (status < STATUS_OK) { + error_log("GPIO mode test failed (2nd attempt)!"); + return status; + } + + status = ReadEEPROM(slave, eeprom3); + + if (status < STATUS_OK) { + error_log("GPIO mode test failed (3rd attempt)!"); + return status; + } + + /* Verify EEPROM data. */ + if ((memcmp(eeprom1, eeprom2, 16) != 0) || + (memcmp(eeprom1, eeprom3, 16) != 0)) { + error_log("GPIO Mode test failed (data comparison)!\n" + "The data from 3 distinct EEPROM readout does not match!"); + return ERROR_FAIL; + } + + /* Check EEPROM data for reasonable chip and module number (i.e. not 0) */ + uint32_t chipID = EEPROM_ReadChipId(eeprom1); + argus_module_version_t module = EEPROM_ReadModule(eeprom1); + + if (chipID == 0 || module == 0) { + error_log("GPIO Mode test failed (data verification)!\n" + "Invalid EEPROM data: Module = %d; Chip ID = %d!", module, chipID); + return ERROR_FAIL; + } + + print("EEPROM Readout succeeded!\n"); + print("- Module: %d\n", module); + print("- Device ID: %d\n", chipID); + + return STATUS_OK; +} + +/*!*************************************************************************** + * @brief Reads the RCO_TRIM value from the devices EEPROM. + * + * @details The function reads the devices EEPROM via GPIO mode and extracts + * the RCO_TRIM value from the EEPROM map. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param rcotrim The read RCO_TRIM value will be returned via this pointer. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #STATUS_ARGUS_EEPROM_BIT_ERROR if the Hamming weight fails. + * - #ERROR_ARGUS_UNKNOWN_MODULE if the EEPROM module number is invalid. + * - The S2PI layer error code if #S2PI_CaptureGpioControl, + * #S2PI_ReleaseGpioControl, #S2PI_WriteGpioPin or + * #S2PI_ReadGpioPin return any negative status. + *****************************************************************************/ +static status_t ReadRcoTrim(s2pi_slave_t slave, int8_t *rcotrim) +{ + /* Read EEPROM */ + uint8_t eeprom[16] = { 0 }; + status_t status = ReadEEPROM(slave, eeprom); + + if (status != STATUS_OK) { return status; } + + argus_module_version_t module = EEPROM_ReadModule(eeprom); + + switch (module) { + case AFBR_S50MV85G_V1: + case AFBR_S50MV85G_V2: + case AFBR_S50MV85G_V3: + case AFBR_S50LV85D_V1: + case AFBR_S50MV68B_V1: + case AFBR_S50MV85I_V1: + case AFBR_S50SV85K_V1: + + /* Read RCO Trim Value from EEPROM Map 1/2/3: */ + *rcotrim = ((int8_t) eeprom[0]) >> 3; + break; + + case MODULE_NONE: /* Uncalibrated module; use all 0 data. */ + default: + + error_log("EEPROM Readout failed! Unknown module number: %d", module); + return ERROR_ARGUS_UNKNOWN_MODULE; + } + + return status; +} + +/*!*************************************************************************** + * @brief Triggers a measurement on the device and waits for the data ready + * interrupt. + * + * @details The function triggers a measurement cycle on the device and waits + * until the measurement has been finished. A \p sample count can be + * specified to setup individual number of digital averaging. + * + * @warning The test utilizes already the timer HAL in order to implement a + * rudimentary timeout. However, at this time, only some basic + * plausibility checks are performed on the timer HAL. I.e. if there + * is an issue in the time HAL, e.g. too fast or too slow time + * counting, the test may fail with an #ERROR_TIMEOUT. In this case, + * one also needs to verify the timer HAL, especially the + * #Timer_GetCounterValue function. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * @param samples The specified number of averaging samples for the measurement. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_TIMEOUT if either the SPI operation did not finished + * or the IRQ was not detected within a specified time (check also + * timer HAL implementation). + * - The S2PI layer error code if #S2PI_TransferFrame, #S2PI_GetStatus + * or #S2PI_SetIrqCallback return any negative status. + *****************************************************************************/ +static status_t RunMeasurement(s2pi_slave_t slave, uint16_t samples) +{ + status_t status = TriggerMeasurement(slave, samples); + + if (status < STATUS_OK) { + error_log("Speed test failed!\n" + "Call to TransferFrame returned code: %d", + status); + return status; + } + + /* Wait until the transfer is finished using a timeout. */ + status = AwaitDataReady(slave, 300); + + if (status < STATUS_OK) { + error_log("Speed test failed!\n" + "SPI Read IRQ pin didn't raised, timeout activated at 200ms, error code: %d", + status); + return status; + } + + return status; +} + +/*!*************************************************************************** + * @brief Test for Timer HAL Implementation by comparing timings to the device. + * + * @details The test verifies the timer HAL implementation by comparing the + * timings to the AFBR-S50 device as a reference. + * Therefore several measurement are executed on the device, each with + * a different averaging sample count. The elapsed time increases + * linearly with the number of averaging samples. In order to remove + * the time for software/setup, a linear regression fit is applied to + * the measurement results and only the slope is considered for the + * result. A delta of 102.4 microseconds per sample is expected. + * If the measured delta per sample is within an specified error range, + * the timer implementation is considered correct. + * + * @param slave The S2PI slave parameter passed to the S2PI HAL functions. + * + * @return Returns the \link #status_t status\endlink: + * - #STATUS_OK on success. + * - #ERROR_FAIL if the timer test fails. + * - #STATUS_ARGUS_EEPROM_BIT_ERROR if the EEPROM Hamming weight fails. + * - #ERROR_ARGUS_UNKNOWN_MODULE if the EEPROM module number is invalid. + * - #ERROR_TIMEOUT if either the SPI operation did not finished + * or the IRQ was not detected within a specified time (check also + * timer HAL implementation). + * - The S2PI layer error code if #S2PI_TransferFrame, #S2PI_GetStatus, + * #S2PI_SetIrqCallback, #S2PI_CaptureGpioControl, + * #S2PI_ReleaseGpioControl, #S2PI_WriteGpioPin or #S2PI_ReadGpioPin + * return any negative status. + *****************************************************************************/ +static status_t TimerTest(s2pi_slave_t slave) +{ + /* Test parameter configuration: *****************************************/ + const int8_t n = 10; // The number of measurements. + const uint32_t ds = 100; // The step size in averaging samples. + const float exp_slope = 102.4; // Expected slope is 102.4 μs / phase / sample + const float rel_slope_error = 3e-2; // Relative slope tolerance is 3%. + /*************************************************************************/ + + /* Read RCOTrim value from EEPROM*/ + int8_t RcoTrim = 0; + status_t status = ReadRcoTrim(slave, &RcoTrim); + + if (status < STATUS_OK) { + error_log("Timer test failed!\n" + "EEPROM Read test returned code: %d", status); + return status; + } + + print("RCOTrim = %d\n", RcoTrim); + + /* Configure the device with calibrated RCO to 24MHz. */ + status = ConfigureDevice(slave, RcoTrim); + + if (status < STATUS_OK) { + error_log("Timer test failed!\n" + "Configuration test returned code: %d", status); + return status; + } + + + /* Run multiple measurements and calculate a linear regression. + * Note: this uses float types for simplicity. */ + float xsum = 0; + float ysum = 0; + float x2sum = 0; + float xysum = 0; + + print("+-------+---------+------------+\n"); + print("| count | samples | elapsed us |\n"); + print("+-------+---------+------------+\n"); + + for (uint8_t i = 1; i <= n; ++i) { + ltc_t start; + Time_GetNow(&start); + + int samples = ds * i; + status = RunMeasurement(slave, samples); + + if (status < STATUS_OK) { + error_log("Timer test failed!\n" + "Run measurement returned code: %d", + status); + return status; + } + + uint32_t elapsed_usec = Time_GetElapsedUSec(&start); + + xsum += (float) samples; + ysum += (float) elapsed_usec; + x2sum += (float) samples * samples; + xysum += (float) samples * elapsed_usec; + + print("| %5d | %7d | %10d |\n", i, samples, elapsed_usec); + } + + print("+-------+---------+------------+\n"); + + + const float slope = (n * xysum - xsum * ysum) / (n * x2sum - xsum * xsum); + const float intercept = (ysum * x2sum - xsum * xysum) / (n * x2sum - xsum * xsum); + print("Linear Regression: y(x) = %dE-7 sec * x + %dE-7 sec\n", + (int)(10 * slope), (int)(10 * intercept)); + + /* Check the error of the slope. */ + const float max_slope = exp_slope * (1.f + rel_slope_error); + const float min_slope = exp_slope * (1.f - rel_slope_error); + + if (slope > max_slope || slope < min_slope) { + error_log("Time test failed!\n" + "The measured time slope does not match the expected value! " + "(actual: %dE-7, expected: %dE-7, min: %dE-7, max: %dE-7)\n", + (int)(10 * slope), (int)(10 * exp_slope), + (int)(10 * min_slope), (int)(10 * max_slope)); + return ERROR_FAIL; + } + + return STATUS_OK; +} + diff --git a/src/drivers/distance_sensor/broadcom/afbrs50/argus_hal_test.h b/src/drivers/distance_sensor/broadcom/afbrs50/argus_hal_test.h new file mode 100644 index 0000000000..1ac16fcaa5 --- /dev/null +++ b/src/drivers/distance_sensor/broadcom/afbrs50/argus_hal_test.h @@ -0,0 +1,166 @@ +/*************************************************************************//** + * @file argus_hal_test.c + * @brief Tests for the AFBR-S50 API hardware abstraction layer. + * + * @copyright + * + * Copyright (c) 2021, Broadcom, Inc. + * 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 of the copyright holder 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 HOLDER 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. + *****************************************************************************/ + +#ifndef ARGUS_HAL_TEST_H +#define ARGUS_HAL_TEST_H + +__BEGIN_DECLS + +/*!*************************************************************************** + * @addtogroup argustest + * @{ + *****************************************************************************/ + +#include "argus.h" + +/*!*************************************************************************** + * @brief Version number of the HAL Self Test. + * + * @details Changes: + * + * - v1.0: + * - Initial release. + * . + * - v1.1: + * - Added additional print output. + * - Increased tolerance for timer test to 3%. + * - Fixed callback issue by disabling it after IRQ test. + * . + *****************************************************************************/ +#define HAL_TEST_VERSION "v1.1" + +/*!*************************************************************************** + * @brief Executes a series of tests in order to verify the HAL implementation. + * + * @details A series of automated tests are executed in order to verify the + * implementation of the HAL required by the API. + * + * The following tests are executed: + * + * 1) Timer Plausibility Test: + * + * Rudimentary tests of the lifetime counter (LTC) implementation. + * This verifies that the LTC is running by checking if the returned + * values of two consecutive calls to the #Timer_GetCounterValue + * function are ascending. An artificial delay using the NOP operation + * is induced such that the timer is not read to fast. + * + * 2) Timer Wraparound Test: + * + * The LTC values must wrap from 999999 μs to 0 μs and increase the + * seconds counter accordingly. This test verifies the correct wrapping + * by consecutively calling the #Timer_GetCounterValue function until + * at least 2 wraparound events have been occurred. + * + * 3) SPI Connection Test: + * + * This test verifies the basic functionality of the SPI interface. + * The test utilizes the devices laser pattern register, which can + * be freely programmed by any 128-bit pattern. Thus, it writes a byte + * sequence and reads back the written values on the consecutive SPI + * access. + * + * 4) SPI Interrupt Test: + * + * This test verifies the correct implementation of the device + * integration finished interrupt callback. Therefore it configures + * the device with a minimal setup to run a pseudo measurement that + * does not emit any laser light. + * + * Note that this test does verify the GPIO interrupt that occurs + * whenever the device has finished the integration/measurement and + * new data is waiting to be read from the device. This does not test + * the interrupt that is triggered when the SPI transfer has finished. + * + * The data ready interrupt implies two S2PI layer functions that + * are tested in this test: The #S2PI_SetIrqCallback function installs + * a callback function that is invoked whenever the IRQ occurs. + * The IRQ can be delayed due to higher priority task, e.g. from the + * user code. It is essential for the laser safety timeout algorithm + * to determine the device ready signal as fast as possible, another + * method is implemented to read if the IRQ is pending but the + * callback has not been reset yet. This is what the #S2PI_ReadIrqPin + * function is for. + * + * 5) GPIO Mode Test: + * + * This test verifies the GPIO mode of the S2PI HAL module. This is + * done by leveraging the EEPROM readout sequence that accesses the + * devices EEPROM via a software protocol that depends on the GPIO + * mode. + * + * This the requires several steps, most of them are already verified + * in previous tests: + * - Basic device configuration and enable EEPROM. + * - Read EERPOM via GPIO mode and apply Hamming weight + * - Repeat several times (to eliminate random readout issues). + * - Decode the EEPROM (using EEPROM_Decode in argus_cal_eeprom.c) + * - Check if Module Number and Chip ID is not 0 + * + * 6) Timer Test: + * + * The test verifies the timer HAL implementation by comparing the + * timings to the AFBR-S50 device as a reference. + * Therefore several measurement are executed on the device, each with + * a different averaging sample count. The elapsed time increases + * linearly with the number of averaging samples. In order to remove + * the time for software/setup, a linear regression fit is applied to + * the measurement results and only the slope is considered for the + * result. A delta of 102.4 microseconds per sample is expected. + * If the measured delta per sample is within an specified error range, + * the timer implementation is considered correct. + * + * ------------------------------------------------------------------- + * + * Each test will write an error description via the print (i.e. UART) + * function that shows what went wrong. Also an corresponding status is + * returned in case no print functionality is available. + * + * + * @param spi_slave The SPI hardware slave, i.e. the specified CS and IRQ + * lines. This is actually just a number that is passed + * to the SPI interface to distinct for multiple SPI slave + * devices. Note that the slave must be not equal to 0, + * since is reserved for error handling. + * + * @return Returns the \link #status_t status\endlink (#STATUS_OK on success). + *****************************************************************************/ +status_t Argus_VerifyHALImplementation(s2pi_slave_t spi_slave); + +__END_DECLS + +/*! @} */ +#endif /* ARGUS_CAL_API_H */ diff --git a/src/drivers/drv_sensor.h b/src/drivers/drv_sensor.h index 7f6833741f..c4c9e739c8 100644 --- a/src/drivers/drv_sensor.h +++ b/src/drivers/drv_sensor.h @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (c) 2012-2020 PX4 Development Team. All rights reserved. + * Copyright (c) 2012-2021 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -163,23 +163,23 @@ #define DRV_MAG_DEVTYPE_UAVCAN 0x88 #define DRV_DIST_DEVTYPE_UAVCAN 0x89 -#define DRV_ADC_DEVTYPE_ADS1115 0x90 -#define DRV_DIST_DEVTYPE_VL53L1X 0x91 -#define DRV_DIST_DEVTYPE_CM8JL65 0x92 -#define DRV_DIST_DEVTYPE_LEDDARONE 0x93 -#define DRV_DIST_DEVTYPE_MAVLINK 0x94 -#define DRV_DIST_DEVTYPE_PGA460 0x95 -#define DRV_DIST_DEVTYPE_PX4FLOW 0x96 -#define DRV_DIST_DEVTYPE_TFMINI 0x97 -#define DRV_DIST_DEVTYPE_ULANDING 0x98 +#define DRV_ADC_DEVTYPE_ADS1115 0x90 -#define DRV_GPIO_DEVTYPE_MCP23009 0x99 - -#define DRV_DIST_DEVTYPE_SIM 0x9a -#define DRV_DIST_DEVTYPE_SRF05 0x9b -#define DRV_DIST_DEVTYPE_GY_US42 0x9c -#define DRV_BAT_DEVTYPE_BATMON_SMBUS 0x9d +#define DRV_DIST_DEVTYPE_VL53L1X 0x91 +#define DRV_DIST_DEVTYPE_CM8JL65 0x92 +#define DRV_DIST_DEVTYPE_LEDDARONE 0x93 +#define DRV_DIST_DEVTYPE_MAVLINK 0x94 +#define DRV_DIST_DEVTYPE_PGA460 0x95 +#define DRV_DIST_DEVTYPE_PX4FLOW 0x96 +#define DRV_DIST_DEVTYPE_TFMINI 0x97 +#define DRV_DIST_DEVTYPE_ULANDING 0x98 +#define DRV_DIST_DEVTYPE_AFBRS50 0x99 +#define DRV_DIST_DEVTYPE_SIM 0x9A +#define DRV_DIST_DEVTYPE_SRF05 0x9B +#define DRV_DIST_DEVTYPE_GY_US42 0x9C +#define DRV_BAT_DEVTYPE_BATMON_SMBUS 0x9d +#define DRV_GPIO_DEVTYPE_MCP23009 0x9F #define DRV_GPS_DEVTYPE_ASHTECH 0xA0 #define DRV_GPS_DEVTYPE_EMLID_REACH 0xA1 diff --git a/src/lib/drivers/rangefinder/PX4Rangefinder.hpp b/src/lib/drivers/rangefinder/PX4Rangefinder.hpp index f666594a6e..6c6b87c0eb 100644 --- a/src/lib/drivers/rangefinder/PX4Rangefinder.hpp +++ b/src/lib/drivers/rangefinder/PX4Rangefinder.hpp @@ -48,7 +48,7 @@ public: // Set the MAV_DISTANCE_SENSOR type (LASER, ULTRASOUND, INFRARED, RADAR) void set_rangefinder_type(uint8_t rangefinder_type) { _distance_sensor_pub.get().type = rangefinder_type; }; - void set_device_id(const uint8_t device_id) { _distance_sensor_pub.get().device_id = device_id; }; + void set_device_id(const uint32_t device_id) { _distance_sensor_pub.get().device_id = device_id; }; void set_device_type(const uint8_t device_type); void set_fov(const float fov) { set_hfov(fov); set_vfov(fov); }