Tool/software:
Hi TI Exeperts :
Good day ~ For out_of_box_6843_aop demo, I want to print out the result right after
Tool/software:
Hi TI Exeperts :
Good day ~ For out_of_box_6843_aop demo, I want to print out the result right after
Hello,
Thanks for posting this question over E2E. Please allow us a day for our software expert to respond.
I have replace objectdetection.c with objdetrangehwa.c and modified the main.c and objdetrangehwa.c .
(DPC_ObjectDetection_execute function) as attached
I also by-passed CLI by using the profile.cfg as follow in the code :
char *hardCodedConfigCommands[] = { "sensorStop", "flushCfg", "dfeDataOutputMode 1", "channelCfg 15 7 0", "adcCfg 2 1", "adcbufCfg -1 0 1 1 1", "lowPower 0 0", "profileCfg 0 60 7 3 24 0 0 166 1 256 12500 0 0 158", "chirpCfg 0 0 0 0 0 0 0 1", "chirpCfg 1 1 0 0 0 0 0 4", "chirpCfg 2 2 0 0 0 0 0 2", "frameCfg 0 2 32 0 100 1 0", "guiMonitor -1 1 1 1 0 0 1", "cfarCfg -1 0 2 8 4 3 0 15.0 0", "cfarCfg -1 1 0 4 2 3 1 15.0 0", "multiObjBeamForming -1 1 0.5", "calibDcRangeSig -1 0 -5 8 256", "clutterRemoval -1 0", "compRangeBiasAndRxChanPhase 0.0392068 0.85352 -0.42142 -0.85583 0.31876 0.83612 -0.23291 -0.89639 0.44327 0.40002 -0.59879 -0.44089 0.54626 0.45618 -0.49176 -0.39868 0.62875 0.27008 -0.71771 -0.33118 0.65073 0.36008 -0.58435 -0.28723 0.71649", "measureRangeBiasAndRxChanPhase 0 1. 0.2", "aoaFovCfg -1 -90 90 -90 90", "cfarFovCfg -1 0 0.25 9.0", "cfarFovCfg -1 1 -20.16 20.16", "extendedMaxVelocity -1 0", "CQRxSatMonitor 0 3 4 63 0", "CQSigImgMonitor 0 127 4", "analogMonitor 0 0", "lvdsStreamCfg -1 0 0 0", "calibData 0 0 0", "sensorStart", "!!!END_OF_HARD_CODED_COMMANDS" };
Compilation is OK. But raise an exception when executing DPC_ObjDetRangeHwa_GenRangeWindow from
DPC_ObjDetRangeHwa_rangeConfig in objdetrangehwa.c
Wondering how to modify the code in order to start the sensor ?
Or is there a suggested better way to print out the range FFT result right after DPU_RangeProcHWA_process
by using CLI_write function ?
main.c
/** * @file main.c * * @brief * This is the main file which implements the millimeter wave Demo * * \par * NOTE: * (C) Copyright 2018 Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of Texas Instruments Incorporated 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. */ /** @mainpage Millimeter Wave (mmw) Demo for XWR64XX/XWR68xx/XWR68XXAOP * * @section intro_sec Introduction * * @image html toplevel.png * * The millimeter wave demo shows some of the capabilities of the XWR64XX/XWR68xx/XWR68XXAOP SoC * using the drivers in the mmWave SDK (Software Development Kit). * It allows user to specify the chirping profile and displays the detected * objects and other information in real-time. * * Following is a high level description of the features of this demo: * - Be able to specify desired chirping profile through command line interface (CLI) * on a UART port or through the TI Gallery App - **mmWave Demo Visualizer** - * that allows user to provide a variety of profile configurations via the UART input port * and displays the streamed detected output from another UART port in real-time, * as seen in picture above. * - Some sample profile configurations have been provided in the demo directory that can be * used with CLI directly or via **mmWave Demo Visualizer** under * @verbatim mmw/profiles @endverbatim directory. * - Do 1D, 2D, CFAR, Azimuth and Elevation processing and stream out velocity * and three spatial coordinates (x,y,z) of the detected objects in real-time. * The demo can also be configured to do 2D only detection (velocity and x,y coordinates). * - Various display options besides object detection like azimuth heat map and * Doppler-range heat map. * * @section limit Limitations * - Because of UART speed limit (< 1 Mbps), the frame time is more restrictive. * For example, for the azimuth and Doppler heat maps for 256 FFT range and * 16 point FFT Doppler, it takes about 200 ms to transmit. * - For most boards, a range bias of few centimeters has been observed. User can estimate * the range bias on their board and correct using the calibration procedure * described in @ref Calibration_section. * * @section systemFlow System Execution Flow * The millimeter wave demo runs on R4F (MSS). Following diagram shows the system * execution flow * * @image html system_flow.png "System Execution Flow" * * @section tasks Software Tasks * The demo consists of the following (SYSBIOS) tasks: * - @ref MmwDemo_initTask. This task is created/launched by @ref main and is a * one-time active task whose main functionality is to initialize drivers (\<driver\>_init), * MMWave module (MMWave_init), DPM module (DPM_init), open UART and data * path related drivers (EDMA, HWA), and create/launch the following tasks * (the @ref CLI_task is launched indirectly by calling @ref CLI_open). * - @ref CLI_task. This command line interface task provides a simplified 'shell' interface * which allows the configuration of the BSS via the mmWave interface (MMWave_config). * It parses input CLI configuration commands like chirp profile and GUI configuration. * When sensor start CLI command is parsed, all actions related to starting sensor and * starting the processing the data path are taken. * When sensor stop CLI command is parsed, all actions related to stopping the sensor and * stopping the processing of the data path are taken * - @ref MmwDemo_mmWaveCtrlTask. This task is used to provide an execution * context for the mmWave control, it calls in an endless loop the MMWave_execute API. * - @ref MmwDemo_DPC_ObjectDetection_dpmTask. This task is used to provide an execution * context for DPM (Data Path Manager) execution, it calls in an endless loop * the DPM_execute API. In this context, all of the registered object detection * DPC (Data Path Chain) APIs like configuration, control and execute will * take place. In this task. When the DPC's execute API produces the detected objects and other * results, they are transmitted out of the UART port for display using the visualizer. * * @section datapath Data Path * @image html datapath_overall.png "Top Level Data Path Processing Chain" * \n * \n * @image html datapath_overall_timing.png "Top Level Data Path Timing" * * The data path processing consists of taking ADC samples as input and producing * detected objects (point-cloud and other information) to be shipped out of * UART port to the PC. The algorithm processing is realized using * the DPM registered Object Detection DPC. The details of the processing in DPC * can be seen from the following doxygen documentation: * @verbatim ti/datapath/dpc/objectdetection/objdethwa/docs/doxygen/html/index.html @endverbatim * * @subsection output Output information sent to host * Output packets with the detection information are sent out every frame * through the UART. Each packet consists of the header @ref MmwDemo_output_message_header_t * and the number of TLV items containing various data information with * types enumerated in @ref MmwDemo_output_message_type_e. The numerical values * of the types can be found in @ref mmw_output.h. Each TLV * item consists of type, length (@ref MmwDemo_output_message_tl_t) and payload information. * The structure of the output packet is illustrated in the following figure. * Since the length of the packet depends on the number of detected objects * it can vary from frame to frame. The end of the packet is padded so that * the total packet length is always multiple of 32 Bytes. * * @image html output_packet_uart.png "Output packet structure sent to UART" * * The following subsections describe the structure of each TLV. * * @subsubsection tlv1 List of detected objects * Type: (@ref MMWDEMO_OUTPUT_MSG_DETECTED_POINTS) * * Length: (Number of detected objects) x (size of @ref DPIF_PointCloudCartesian_t) * * Value: Array of detected objects. The information of each detected object * is as per the structure @ref DPIF_PointCloudCartesian_t. When the number of * detected objects is zero, this TLV item is not sent. The maximum number of * objects that can be detected in a sub-frame/frame is @ref DPC_OBJDET_MAX_NUM_OBJECTS. * * The orientation of x,y and z axes relative to the sensor is as per the * following figure. * (Note: The antenna arrangement in the figure is shown for standard EVM * (see @ref gAntDef_default) as an example but the figure is applicable for any antenna arrangement.) * * @image html coordinate_geometry.png "Coordinate Geometry" * * The whole detected objects TLV structure is illustrated in figure below. * * @image html detected_objects_tlv.png "Detected objects TLV" * * @subsubsection tlv2 Range profile * Type: (@ref MMWDEMO_OUTPUT_MSG_RANGE_PROFILE) * * Length: (Range FFT size) x (size of uint16_t) * * Value: Array of profile points at 0th Doppler (stationary objects). * The points represent the sum of log2 magnitudes of received antennas * expressed in Q9 format. * * @subsubsection tlv3 Noise floor profile * Type: (@ref MMWDEMO_OUTPUT_MSG_NOISE_PROFILE) * * Length: (Range FFT size) x (size of uint16_t) * * Value: This is the same format as range profile but the profile * is at the maximum Doppler bin (maximum speed * objects). In general for stationary scene, there would be no objects or clutter at * maximum speed so the range profile at such speed represents the * receiver noise floor. * * @subsubsection tlv4 Azimuth static heatmap * Type: (@ref MMWDEMO_OUTPUT_MSG_AZIMUT_STATIC_HEAT_MAP) * * Length: (Range FFT size) x (Number of "azimuth" virtual antennas) (size of @ref cmplx16ImRe_t_) * * Value: Array @ref DPU_AoAProcHWA_HW_Resources::azimuthStaticHeatMap. The antenna data * are complex symbols, with imaginary first and real second in the following order:\n * @verbatim Imag(ant 0, range 0), Real(ant 0, range 0),...,Imag(ant N-1, range 0),Real(ant N-1, range 0) ... Imag(ant 0, range R-1), Real(ant 0, range R-1),...,Imag(ant N-1, range R-1),Real(ant N-1, range R-1) @endverbatim * Note that the number of virtual antennas is equal to the number of "azimuth" * virtual antennas. The antenna symbols are arranged in the order * as they occur at the input to azimuth FFT. * Based on this data the static azimuth heat map could be constructed by the GUI * running on the host. * * @subsubsection tlv4e Azimuth/Elevation static heatmap * Type: (@ref MMWDEMO_OUTPUT_MSG_AZIMUT_ELEVATION_STATIC_HEAT_MAP) * * Length: (Range FFT size) x (Number of all virtual antennas) (size of @ref cmplx16ImRe_t_) * * Value: Array @ref DPU_AoAProcHWA_HW_Resources::azimuthStaticHeatMap. The antenna data * are complex symbols, with imaginary first and real second in the following order:\n * @verbatim Imag(ant 0, range 0), Real(ant 0, range 0),...,Imag(ant N-1, range 0),Real(ant N-1, range 0) ... Imag(ant 0, range R-1), Real(ant 0, range R-1),...,Imag(ant N-1, range R-1),Real(ant N-1, range R-1) @endverbatim * Note that the number of virtual antennas is equal to the total number of * active virtual antennas. The antenna symbols are arranged in the order as * they occur in the radar cube matrix. * This TLV is sent by AOP version of MMW demo, that uses AOA2D DPU. * Based on this data the static azimuth or elevation heat map could be constructed by the GUI * running on the host. * * @subsubsection tlv5 Range/Doppler heatmap * Type: (@ref MMWDEMO_OUTPUT_MSG_RANGE_DOPPLER_HEAT_MAP) * * Length: (Range FFT size) x (Doppler FFT size) (size of uint16_t) * * Value: Detection matrix @ref DPIF_DetMatrix::data. * The order is : \n * @verbatim X(range bin 0, Doppler bin 0),...,X(range bin 0, Doppler bin D-1), ... X(range bin R-1, Doppler bin 0),...,X(range bin R-1, Doppler bin D-1) @endverbatim * * @subsubsection tlv6 Stats information * Type: (@ref MMWDEMO_OUTPUT_MSG_STATS ) * * Length: (size of @ref MmwDemo_output_message_stats_t) * * Value: Timing information as per @ref MmwDemo_output_message_stats_t. * See timing diagram below related to the stats. * * @image html processing_timing.png "Processing timing" * * Note: * -# The @ref MmwDemo_output_message_stats_t::interChirpProcessingMargin is not * computed (it is always set to 0). This is because there is no CPU involvement * in the 1D processing (only HWA and EDMA are involved), and it is not possible to * know how much margin is there in chirp processing without CPU being notified * at every chirp when processing begins (chirp event) and when the HWA-EDMA * computation ends. The CPU is intentionally kept free during 1D processing * because a real application may use this time for doing some post-processing * algorithm execution. * -# While the * @ref MmwDemo_output_message_stats_t::interFrameProcessingTime reported * will be of the current sub-frame/frame, * the @ref MmwDemo_output_message_stats_t::interFrameProcessingMargin and * @ref MmwDemo_output_message_stats_t::transmitOutputTime * will be of the previous sub-frame (of the same * @ref MmwDemo_output_message_header_t::subFrameNumber as that of the * current sub-frame) or of the previous frame. * -# The @ref MmwDemo_output_message_stats_t::interFrameProcessingMargin excludes * the UART transmission time (available as * @ref MmwDemo_output_message_stats_t::transmitOutputTime). This is done * intentionally to inform the user of a genuine inter-frame processing margin * without being influenced by a slow transport like UART, this transport time * can be significantly longer for example when streaming out debug information like * heat maps. Also, in a real product deployment, higher speed interfaces (e.g LVDS) * are likely to be used instead of UART. User can calculate the margin * that includes transport overhead (say to determine the max frame rate * that a particular demo configuration will allow) using the stats * because they also contain the UART transmission time. * * The CLI command \"guMonitor\" specifies which TLV element will * be sent out within the output packet. The arguments of the CLI command are stored * in the structure @ref MmwDemo_GuiMonSel_t. * * @subsubsection tlv7 Side information of detected objects * Type: (@ref MMWDEMO_OUTPUT_MSG_DETECTED_POINTS_SIDE_INFO) * * Length: (Number of detected objects) x (size of @ref DPIF_PointCloudSideInfo_t) * * Value: Array of detected objects side information. The side information * of each detected object is as per the structure @ref DPIF_PointCloudSideInfo_t). * When the number of detected objects is zero, this TLV item is not sent. * * @subsection tlv9 Temperature Stats * Type: (@ref MMWDEMO_OUTPUT_MSG_TEMPERATURE_STATS) * * Length: (size of @ref MmwDemo_temperatureStats_t) * * Value: Structure of detailed temperature report as obtained from Radar front end. * @ref MmwDemo_temperatureStats_t::tempReportValid is set to return value of * rlRfGetTemperatureReport. If @ref MmwDemo_temperatureStats_t::tempReportValid is 0, * values in @ref MmwDemo_temperatureStats_t::temperatureReport are valid else they should * be ignored. This TLV is sent along with Stats TLV described in @ref tlv6 * * @subsection Calibration_section Range Bias and Rx Channel Gain/Phase Measurement and Compensation * * Because of imperfections in antenna layouts on the board, RF delays in SOC, etc, * there is need to calibrate the sensor to compensate for bias in the range estimation and * receive channel gain and phase imperfections. The following figure illustrates * the calibration procedure. * * @anchor Figure_calibration_ladder_diagram * @image html calibration_ladder_diagram.png "Calibration procedure ladder diagram" * * The calibration procedure includes the following steps: * -# Set a strong target like corner reflector at the distance of X meter * (X less than 50 cm is not recommended) at boresight. * -# Set the following command * in the configuration profile in .../profiles/profile_calibration.cfg, * to reflect the position X as follows: * @verbatim measureRangeBiasAndRxChanPhase 1 X D @endverbatim * where D (in meters) is the distance of window around X where the peak will be searched. * The purpose of the search window is to allow the test environment from not being overly constrained * say because it may not be possible to clear it of all reflectors that may be stronger than the one used * for calibration. The window size is recommended to be at least the distance equivalent of a few range bins. * One range bin for the calibration profile (profile_calibration.cfg) is about 5 cm. * The first argument "1" is to enable the measurement. The stated configuration * profile (.cfg) must be used otherwise the calibration may not work as expected * (this profile ensures all transmit and receive antennas are engaged among * other things needed for calibration). * -# Start the sensor with the configuration file. * -# In the configuration file, the measurement is enabled because of which * the DPC will be configured to perform the measurement and generate * the measurement result (@ref DPU_AoAProc_compRxChannelBiasCfg_t) in its * result structure (@ref DPC_ObjectDetection_ExecuteResult_t::compRxChanBiasMeasurement), * the measurement results are written out on the CLI port (@ref MmwDemo_measurementResultOutput) * in the format below: * @verbatim compRangeBiasAndRxChanPhase <rangeBias> <Re(0,0)> <Im(0,0)> <Re(0,1)> <Im(0,1)> ... <Re(0,R-1)> <Im(0,R-1)> <Re(1,0)> <Im(1,0)> ... <Re(T-1,R-1)> <Im(T-1,R-1)> @endverbatim For details of how DPC performs the measurement, see the DPC documentation. * -# The command printed out on the CLI now can be copied and pasted in any * configuration file for correction purposes. This configuration will be * passed to the DPC for the purpose of applying compensation during angle * computation, the details of this can be seen in the DPC documentation. * If compensation is not desired, * the following command should be given (depending on the EVM and antenna arrangement) * @verbatim For ISK EVM: compRangeBiasAndRxChanPhase 0.0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 For AOP EVM compRangeBiasAndRxChanPhase 0.0 1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0 -1 0 @endverbatim * Above sets the range bias to 0 and * the phase coefficients to unity so that there is no correction. Note * the two commands must always be given in any configuration file, typically * the measure commmand will be disabled when the correction command is the * desired one. * * @section LVDSStreamingNotes Streaming data over LVDS * * The LVDS streaming feature enables the streaming of HW data (a combination of ADC/CP/CQ data) * and/or user specific SW data through LVDS interface. * The streaming is done mostly by the CBUFF and EDMA peripherals with minimal CPU intervention. * The streaming is configured through the @ref MmwDemo_LvdsStreamCfg_t CLI command which * allows control of HSI header, enable/disable of HW and SW data and data format choice for the HW data. * The choices for data formats for HW data are: * - @ref MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_DISABLED * - @ref MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_ADC * - @ref MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_CP_ADC_CQ * * In order to see the high-level data format details corresponding to the above * data format configurations, refer to the corresponding slides in ti\drivers\cbuff\docs\CBUFF_Transfers.pptx * * When HW data LVDS streaming is enabled, the ADC/CP/CQ data is streamed per * chirp on every chirp event. When SW data * streaming is enabled, it is streamed during inter-frame period after the * list of detected objects for that frame is computed. * The SW data streamed every frame/sub-frame is composed of the following in time: * -# HSI header (@ref HSIHeader_t): refer to HSI module for details. * -# User data header: @ref MmwDemo_LVDSUserDataHeader * -# User data payloads: * -# Point-cloud information as a list : @ref DPIF_PointCloudCartesian_t x number of detected objects * -# Point-cloud side information as a list : @ref DPIF_PointCloudSideInfo_t x number of detected objects * * The format of the SW data streamed is shown in the following figure: * @image html lvds_sw_data_format.png "LVDS SW Data format" * * Note: * -# Only single-chirp formats are allowed, multi-chirp is not supported. * -# When number of objects detected in frame/sub-frame is 0, there is no * transmission beyond the user data header. * -# For HW data, the inter-chirp duration should be sufficient to stream out the desired amount * of data. For example, if the HW data-format is ADC and HSI header is enabled, * then the total amount of data generated per chirp * is:\n * (numAdcSamples * numRxChannels * 4 (size of complex sample) + * 52 [sizeof(HSIDataCardHeader_t) + sizeof(HSISDKHeader_t)] ) * rounded up to multiples of 256 [=sizeof(HSIHeader_t)] bytes.\n * The chirp time Tc in us = idle time + ramp end time in the profile configuration. * For n-lane LVDS with each lane at a maximum of B Mbps,\n * maximum number of bytes that can be send per chirp = Tc * n * B / 8 which * should be greater than the total amount of data generated per chirp i.e\n * Tc * n * B / 8 >= round-up(numAdcSamples * numRxChannels * 4 + 52, 256). \n * E.g if n = 2, B = 600 Mbps, idle time = 7 us, ramp end time = 44 us, numAdcSamples = 512, * numRxChannels = 4, then 7650 >= 8448 is violated so this configuration will not work. * If the idle-time is doubled in the above example, then we have 8700 > 8448, so * this configuration will work. * -# For SW data, the number of bytes to transmit each sub-frame/frame is:\n * 52 [sizeof(HSIDataCardHeader_t) + sizeof(HSISDKHeader_t)] + * sizeof(MmwDemo_LVDSUserDataHeader_t) [=8] + \n * number of detected objects (Nd) * { sizeof(DPIF_PointCloudCartesian_t) [=16] + sizeof(DPIF_PointCloudSideInfo_t) [=4] } * rounded up to multiples of 256 [=sizeof(HSIHeader_t)] bytes.\n * or X = round-up(60 + Nd * 20, 256). So the time to transmit this data will be \n * X * 8 / (n*B) us. The maximum number of objects (Ndmax) that can be * detected is defined in the DPC (@ref DPC_OBJDET_MAX_NUM_OBJECTS). So if * Ndmax = 500, then time to transmit SW data is 68 us. Because we parallelize * this transmission with the much slower UART transmission, and because UART transmission * is also sending at least the same amount of information as the LVDS, the * LVDS transmission time will not add any burdens on the processing budget * beyond the overhead of reconfiguring and activating the CBUFF session * (this overhead is likely bigger than the time to transmit). * -# The total amount of data to be transmitted in a HW or SW packet must be greater than the * minimum required by CBUFF, which is 64 bytes or 32 CBUFF Units (this is the definition * CBUFF_MIN_TRANSFER_SIZE_CBUFF_UNITS in the CBUFF driver implementation). * If this threshold condition is violated, the CBUFF driver will return an error during * configuration and the demo will generate a fatal exception as a result. * When HSI header is enabled, the total transfer size is ensured to be at least * 256 bytes, which satisfies the minimum. If HSI header is disabled, for the HW session, * this means that numAdcSamples * numRxChannels * 4 >= 64. Although mmwavelink * allows minimum number of ADC samples to be 2, the demo is supported * for numAdcSamples >= 64. So HSI header is not required to be enabled for HW only case. * But if SW session is enabled, without the HSI header, the bytes in each * packet will be 8 + Nd * 20. So for frames/sub-frames where Nd < 3, the * demo will generate exception. Therefore HSI header must be enabled if SW is enabled, * this is checked in the CLI command validation. * * @subsection lvdsImpl Implementation Notes * * -# The LVDS implementation is mostly present in mmw_lvds_stream.h and * mmw_lvds_stream.c with calls in mss_main.c. Additionally HSI * clock initialization is done at first time sensor start using @ref MmwDemo_mssSetHsiClk. * -# EDMA channel resources for CBUFF/LVDS are in the global resource file * (mmw_res.h, see @ref resourceAlloc) along with other EDMA resource allocation. * The user data header and two user payloads are configured as three user buffers in the CBUFF driver. * Hence SW allocation for EDMA provides for three sets of EDMA resources as seen in * the SW part (swSessionEDMAChannelTable[.]) of @ref MmwDemo_LVDSStream_EDMAInit. * The maximum number of HW EDMA resources are needed for the * data-format @ref MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_CP_ADC_CQ, * which as seen in the corresponding slide in ti\drivers\cbuff\docs\CBUFF_Transfers.pptx is * 12 channels (+ shadows) including the 1st special CBUFF EDMA event channel * which CBUFF IP generates to the EDMA, hence the HW part * (hwwSessionEDMAChannelTable[.]) of @ref MmwDemo_LVDSStream_EDMAInit * has 11 table entries. * -# Although the CBUFF driver is configured for two sessions (hw and sw), * at any time only one can be active. So depending on the LVDS CLI configuration * and whether advanced frame or not, there is logic to activate/deactivate * HW and SW sessions as necessary. * -# The CBUFF session (HW/SW) configure-create and delete * depends on whether or not re-configuration is required after the * first time configuration. * -# For HW session, re-configuration is done during sub-frame switching to * re-configure for the next sub-frame but when there is no advanced frame * (number of sub-frames = 1), the HW configuration does not need to * change so HW session does not need to be re-created. * -# For SW session, even though the user buffer start addresses and sizes of * headers remains same, the number of detected objects which determines the * sizes of some user buffers changes from one sub-frame/frame to another sub-frame/frame. * Therefore SW session needs to be recreated every sub-frame/frame. * -# User may modify the application software to transmit different information than point-cloud * in the SW data e.g radar cube data (output of range DPU). However the CBUFF also has * a maximum link list entry size limit of 0x3FFF CBUFF units or 32766 bytes. * This means it is the limit for each user buffer entry * [there are maximum of 3 entries -1st used for user data header, 2nd * for point-cloud and 3rd for point-cloud side information]. During session creation, * if this limit is exceeded, the CBUFF will return an error (and demo will in turn * generate an exception). A single physical buffer of say size 50000 bytes * may be split across two user buffers by providing one user buffer with * (address, size) = (start address, 25000) and 2nd user buffer with * (address, size) = (start address + 25000, 25000), beyond * this two (or three if user data header is also replaced) limit, * the user will need to create and activate (and wait for completion) * the SW session multiple times to accomplish the transmission. * * The following figure shows a timing diagram for the LVDS streaming * (the figure is not to scale as actual durations will vary based on configuration). * * @image html lvdstiming.png "LVDS timing diagram" * * @section bypassCLI How to bypass CLI * * Re-implement the file mmw_cli.c as follows: * * -# @ref MmwDemo_CLIInit should just create a task with input taskPriority. * Lets say the task is called "MmwDemo_sensorConfig_task". * -# All other functions are not needed * -# Implement the MmwDemo_sensorConfig_task as follows: * - Fill gMmwMCB.cfg.openCfg * - Fill gMmwMCB.cfg.ctrlCfg * - Add profiles and chirps using @ref MMWave_addProfile and @ref MMWave_addChirp functions * - Call @ref MmwDemo_CfgUpdate for every offset in @ref configStoreOffsets * (MMWDEMO_xxx_OFFSET in mmw.h) * - Fill gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg * - Call @ref MmwDemo_openSensor * - Call @ref MmwDemo_startSensor (One can use helper function * @ref MmwDemo_isAllCfgInPendingState to know if all dynamic config was provided) * * @section resourceAlloc Hardware Resource Allocation * The Object Detection DPC needs to configure the DPUs hardware resources (HWA, EDMA). * Even though the hardware resources currently are only required to be allocated * for this one and only DPC in the system, the resource partitioning is shown to be in * the ownership of the demo. This is to illustrate the general * case of resource allocation across more than one DPCs and/or demo's own * processing that is post-DPC processing. This partitioning * can be seen in the mmw_res.h file. This file is passed as a compiler command line * define @verbatim "--define=APP_RESOURCE_FILE="<ti/demo/xwr64xx/mmw/mmw_res.h>" @endverbatim in mmw.mak * when building the DPC sources as part of building the demo application and * is referred in object detection DPC sources where needed as * @verbatim #include APP_RESOURCE_FILE @endverbatim * * @section memoryUsage Memory Usage * @subsection memUsageSummary Memory usage summary * The table below shows the usage of various memories available on the device across * the demo application and other SDK components. The table is generated using the demo's * map file and applying some mapping rules to it to generate a condensed summary. * For the mapping rules, please refer to <a href="../../demo_mss_mapping.txt">demo_mss_mapping.txt</a>. * The numeric values shown here represent bytes. * Refer to the <a href="../../xwr64xx_mmw_demo_mss_mem_analysis_detailed.txt">xwr64xx_mmw_demo_mss_mem_analysis_detailed.txt</a> * for detailed analysis of the memory usage across drivers and control/alg components and to * <a href="../../demo_mss_mapping_detailed.txt">demo_mss_mapping_detailed.txt</a> for detailed mapping rules . * * \include xwr64xx_mmw_demo_mss_mem_analysis.txt * * * @section error Note on Error Codes * * ------------------------------ * When demo runs into error conditions, an error code will be generated and printed out. * Error code is defined as a negative interger. It comes from the following categories: * - Drivers * - Control modules * - Data Processing Chain * - Data Processing Unit * - Demo * * The error code is defined as (Module error code base - Module specific error code).\n * The base error code for the above modules can be found in @ref mmwave_error.h\n * The base error code for DPC and DPU can be found in @ref dp_error.h * * Module specific error code is specified in the module's header file. * Examples: * - UART driver error code is defined in uart.h * - DPC error code is defined in the dpc used in demo (ti/datapath/dpc/objectdetection/objdethwa) * * @subsection mmwave_error mmWave module Error Code * Error code from mmWave module is encoded in the following manner: * * Bits(31::16) | Bits(15::2) | Bits (1::0) * :-------------|:----------------|:-------------: * mmwave error | Subsystem error | error level * * - mmwave error is defined in mmwave.h \n * - Subsystem error is returned from sub-system such as mmwavelink and mailbox driver. \n * - Error level is referred as WARNING leve and ERROR level. * - mmWave exposes an API - MMWave_decodeError() that can be used in demo to decode error code * * @subsection mmwave_error_example Example * - Here is an example on how to parse the error code - "-40111"\n * -# The error code is from module with error base "-40000", which indicates it is DPC error.\n * -# By referring to @ref dp_error.h, base "-40100" is from HWA based objectdetection DPC.\n * -# Then find the error code in objectdetection.h for error(-11) as DPC_OBJECTDETECTION_ENOMEM__L3_RAM_RADAR_CUBE * * - Another example is with mmWave control module: - "mmWave Config failed [Error code: -3109 Subsystem: 71]"\n * -# The above message indicates the error is from module(-3100 ->mmwave) with error -9(MMWAVE_ECHIRPCFG)\n * -# The subsystem(mmwavelink) error is 71(RL_RET_CODE_CHIRP_TX_ENA_1INVAL_IN) which can be found in mmwavelink.h * */ /************************************************************************** *************************** Include Files ******************************** **************************************************************************/ /* Standard Include Files. */ #include <stdint.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include <stdio.h> #include <math.h> /* BIOS/XDC Include Files. */ #include <xdc/std.h> #include <xdc/cfg/global.h> #include <xdc/runtime/IHeap.h> #include <xdc/runtime/System.h> #include <xdc/runtime/Error.h> #include <xdc/runtime/Memory.h> #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Event.h> #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Clock.h> #include <ti/sysbios/heaps/HeapBuf.h> #include <ti/sysbios/heaps/HeapMem.h> #include <ti/sysbios/knl/Event.h> #include <ti/sysbios/family/arm/v7a/Pmu.h> #include <ti/sysbios/family/arm/v7r/vim/Hwi.h> #include <ti/sysbios/utils/Load.h> /* mmWave SDK Include Files: */ #include <ti/common/sys_common.h> #include <ti/common/mmwave_sdk_version.h> #include <ti/drivers/soc/soc.h> #include <ti/drivers/esm/esm.h> #include <ti/drivers/pinmux/pinmux.h> #include <ti/drivers/crc/crc.h> #include <ti/drivers/gpio/gpio.h> #include <ti/drivers/mailbox/mailbox.h> #include <ti/control/mmwave/mmwave.h> #include <ti/control/dpm/dpm.h> //#include <ti/datapath/dpc/objectdetection/objdethwa/objectdetection.h> #include <ti/datapath/dpc/objectdetection/objdetrangehwa/objdetrangehwa.h> #include <ti/drivers/osal/DebugP.h> #include <ti/drivers/uart/UART.h> #include <ti/utils/cli/cli.h> #include <ti/utils/mathutils/mathutils.h> #include <ti/utils/cycleprofiler/cycle_profiler.h> #include <ti/demo/utils/mmwdemo_rfparser.h> #include <ti/demo/xwr64xx/mmw/mmw_output.h> /* Demo Include Files */ #include <ti/demo/xwr64xx/mmw/mmw.h> #include <ti/demo/xwr64xx/mmw/data_path.h> #include <ti/demo/xwr64xx/mmw/mmw_config.h> #include <ti/demo/xwr64xx/mmw/mmw_res.h> #include <ti/board/antenna_geometry.h> #include <ti/demo/utils/mmwdemo_flash.h> /** * @brief Task Priority settings: * Mmwave task is at higher priority because of potential async messages from BSS * that need quick action in real-time. * * CLI task must be at a lower priority than object detection * dpm task priority because the dynamic CLI command handling in the objection detection * dpm task assumes CLI task is held back during this processing. The alternative * is to use a semaphore between the two tasks. */ #define MMWDEMO_CLI_TASK_PRIORITY 3 #define MMWDEMO_DPC_OBJDET_DPM_TASK_PRIORITY 4 #define MMWDEMO_MMWAVE_CTRL_TASK_PRIORITY 5 #if (MMWDEMO_CLI_TASK_PRIORITY >= MMWDEMO_DPC_OBJDET_DPM_TASK_PRIORITY) #error CLI task priority must be < Object Detection DPM task priority #endif /* These address offsets are in bytes, when configure address offset in hardware, these values will be converted to number of 128bits Buffer at offset 0x0U is reserved by BSS, hence offset starts from 0x800 */ #define MMW_DEMO_CQ_SIGIMG_ADDR_OFFSET 0x800U #define MMW_DEMO_CQ_RXSAT_ADDR_OFFSET 0x1000U /* CQ data is at 16 bytes alignment for mulitple chirps */ #define MMW_DEMO_CQ_DATA_ALIGNMENT 16U /*! L3 RAM buffer for object detection DPC */ uint8_t gMmwL3[SOC_L3RAM_SIZE]; #pragma DATA_SECTION(gMmwL3, ".l3ram"); /*! TCM RAM buffer for object detection DPC */ #define MMWDEMO_OBJDET_TCM_SIZE (49U * 1024U) uint8_t gDPC_ObjDetTCM[MMWDEMO_OBJDET_TCM_SIZE]; #pragma DATA_SECTION(gDPC_ObjDetTCM, ".DPC_objDetTcmbHeap"); /************************************************************************** *************************** Global Definitions *************************** **************************************************************************/ /** * @brief * Global Variable for tracking information required by the mmw Demo */ MmwDemo_MCB gMmwMCB; /** * @brief * Global Variable for LDO BYPASS config, PLease consult your * board/EVM user guide before changing the values here */ rlRfLdoBypassCfg_t gRFLdoBypassCfg = { .ldoBypassEnable = 0, /* 1.0V RF supply 1 and 1.0V RF supply 2 */ .supplyMonIrDrop = 0, /* IR drop of 3% */ .ioSupplyIndicator = 0, /* 3.3 V IO supply */ }; /* Calibration Data Save/Restore defines */ #define MMWDEMO_CALIB_FLASH_SIZE 4096 #define MMWDEMO_CALIB_STORE_MAGIC (0x7CB28DF9U) MmwDemo_calibData gCalibDataStorage; #pragma DATA_ALIGN(gCalibDataStorage, 8); /************************************************************************** *************************** Extern Definitions *************************** **************************************************************************/ extern void MmwDemo_CLIInit(uint8_t taskPriority); /************************************************************************** ************************* Millimeter Wave Demo Functions ********************** **************************************************************************/ void MmwDemo_mmWaveCtrlTask(UArg arg0, UArg arg1); void MmwDemo_dataPathInit(MmwDemo_DataPathObj *obj); int32_t MmwDemo_dataPathConfig(void); void MmwDemo_dataPathOpen(MmwDemo_DataPathObj *obj); void MmwDemo_dataPathStart (void); void MmwDemo_dataPathStop (MmwDemo_DataPathObj *obj); void MmwDemo_transmitProcessedOutput(UART_Handle uartHandle, DPC_ObjectDetection_ExecuteResult *result, MmwDemo_output_message_stats *timingInfo); void MmwDemo_initTask(UArg arg0, UArg arg1); void MmwDemo_dataPathTask(UArg arg0, UArg arg1); int32_t MmwDemo_eventCallbackFxn(uint16_t msgId, uint16_t sbId, uint16_t sbLen, uint8_t *payload); /* external sleep function when in idle (used in .cfg file) */ void MmwDemo_sleep(void); /* Calibration save/restore APIs */ static int32_t MmwDemo_calibInit(void); static int32_t MmwDemo_calibSave(MmwDemo_calibDataHeader *ptrCalibDataHdr, MmwDemo_calibData *ptrCalibrationData); static int32_t MmwDemo_calibRestore(MmwDemo_calibData *calibrationData); /** * @b Description * @n * Send assert information through CLI. */ void _MmwDemo_debugAssert(int32_t expression, const char *file, int32_t line) { if (!expression) { CLI_write ("Exception: %s, line %d.\n", file, line); } } /** * @b Description * @n * Utility function to set the pending state of configuration. * * @param[in] subFrameCfg Pointer to Sub-frame specific configuration * @param[in] offset Configuration structure offset that uniquely identifies the * configuration to set to the pending state. * * @retval None */ static void MmwDemo_setSubFramePendingState(MmwDemo_SubFrameCfg *subFrameCfg, uint32_t offset) { switch (offset) { case MMWDEMO_GUIMONSEL_OFFSET: subFrameCfg->objDetDynCfg.isPrepareRangeAzimuthHeatMapPending = 1; break; case MMWDEMO_CFARCFGRANGE_OFFSET: subFrameCfg->objDetDynCfg.isCfarCfgRangePending = 1; break; case MMWDEMO_CFARCFGDOPPLER_OFFSET: subFrameCfg->objDetDynCfg.isCfarCfgDopplerPending = 1; break; case MMWDEMO_FOVRANGE_OFFSET: subFrameCfg->objDetDynCfg.isFovRangePending = 1; break; case MMWDEMO_FOVDOPPLER_OFFSET: subFrameCfg->objDetDynCfg.isFovDopplerPending = 1; break; case MMWDEMO_FOVAOA_OFFSET: subFrameCfg->objDetDynCfg.isFovAoaCfgPending = 1; break; case MMWDEMO_MULTIOBJBEAMFORMING_OFFSET: subFrameCfg->objDetDynCfg.isMultiObjBeamFormingCfgPending = 1; break; case MMWDEMO_CALIBDCRANGESIG_OFFSET: subFrameCfg->objDetDynCfg.isCalibDcRangeSigCfg = 1; break; case MMWDEMO_STATICCLUTTERREMOFVAL_OFFSET: subFrameCfg->objDetDynCfg.isStaticClutterRemovalCfgPending = 1; break; case MMWDEMO_EXTMAXVEL_OFFSET: subFrameCfg->objDetDynCfg.isExtMaxVelCfgPending = 1; break; case MMWDEMO_ADCBUFCFG_OFFSET: subFrameCfg->isAdcBufCfgPending = 1; break; case MMWDEMO_LVDSSTREAMCFG_OFFSET: subFrameCfg->isLvdsStreamCfgPending = 1; break; default: MmwDemo_debugAssert(0); break; } } /** * @b Description * @n * Utility function to find out if all common configuration is pending * * @param[in] cfg Pointer to Common configuration * * @retval 1 if all common configuration is pending, else return 0. */ static uint8_t MmwDemo_isDynObjDetCommonCfgPendingState(MmwDemo_DPC_ObjDet_CommonCfg *cfg) { uint8_t retVal; retVal = (cfg->isCompRxChannelBiasCfgPending == 1) && (cfg->isMeasureRxChannelBiasCfgPending == 1); return(retVal); } /** * @b Description * @n * Utility function to find out if all sub-frame specific dynamic * configuration is pending * * @param[in] cfg Pointer to sub-frame specific configuration * * @retval 1 if all sub-frame specific dynamic configuration is pending, else return 0 */ static uint8_t MmwDemo_isDynObjDetCfgPendingState(MmwDemo_DPC_ObjDet_DynCfg *cfg) { uint8_t retVal; retVal = (cfg->isCalibDcRangeSigCfg == 1) && (cfg->isCfarCfgDopplerPending == 1) && (cfg->isCfarCfgRangePending == 1) && (cfg->isFovDopplerPending == 1) && (cfg->isFovRangePending == 1) && (cfg->isMultiObjBeamFormingCfgPending == 1) && (cfg->isPrepareRangeAzimuthHeatMapPending == 1) && (cfg->isStaticClutterRemovalCfgPending == 1) && (cfg->isFovAoaCfgPending == 1) && (cfg->isExtMaxVelCfgPending == 1); return(retVal); } /** * @b Description * @n * Utility function to find out if all common configuration is in non-pending (cleared) * state. * * @param[in] cfg Pointer to common specific configuration * * @retval 1 if all common configuration is in non-pending state, else return 0 */ static uint8_t MmwDemo_isDynObjDetCommonCfgInNonPendingState(MmwDemo_DPC_ObjDet_CommonCfg *cfg) { uint8_t retVal; retVal = (cfg->isCompRxChannelBiasCfgPending == 0) && (cfg->isMeasureRxChannelBiasCfgPending == 0); return(retVal); } /** * @b Description * @n * Utility function to find out if all sub-frame specific dynamic configuration * is in non-pending (cleared) state. * * @param[in] cfg Pointer to common specific configuration * * @retval 1 if all sub-frame specific dynamic configuration is in non-pending * state, else return 0 */ static uint8_t MmwDemo_isDynObjDetCfgInNonPendingState(MmwDemo_DPC_ObjDet_DynCfg *cfg) { uint8_t retVal; retVal = (cfg->isCalibDcRangeSigCfg == 0) && (cfg->isCfarCfgDopplerPending == 0) && (cfg->isCfarCfgRangePending == 0) && (cfg->isFovDopplerPending == 0) && (cfg->isFovRangePending == 0) && (cfg->isMultiObjBeamFormingCfgPending == 0) && (cfg->isPrepareRangeAzimuthHeatMapPending == 0) && (cfg->isStaticClutterRemovalCfgPending == 0) && (cfg->isFovAoaCfgPending == 0) && (cfg->isExtMaxVelCfgPending == 0); return(retVal); } /** * @b Description * @n * Resets (clears) all pending common configuration of Object Detection DPC * * @param[in] cfg Object Detection DPC common configuration * * @retval * Not Applicable. */ static void MmwDemo_resetDynObjDetCommonCfgPendingState(MmwDemo_DPC_ObjDet_CommonCfg *cfg) { cfg->isCompRxChannelBiasCfgPending = 0; cfg->isMeasureRxChannelBiasCfgPending = 0; } /** * @b Description * @n * Resets (clears) all pending sub-frame specific dynamic configuration * of Object Detection DPC * * @param[in] cfg Object Detection DPC sub-frame dynamic configuration * * @retval * Not Applicable. */ static void MmwDemo_resetDynObjDetCfgPendingState(MmwDemo_DPC_ObjDet_DynCfg *cfg) { cfg->isCalibDcRangeSigCfg = 0; cfg->isCfarCfgDopplerPending = 0; cfg->isCfarCfgRangePending = 0; cfg->isFovDopplerPending = 0; cfg->isFovRangePending = 0; cfg->isMultiObjBeamFormingCfgPending = 0; cfg->isPrepareRangeAzimuthHeatMapPending = 0; cfg->isStaticClutterRemovalCfgPending = 0; cfg->isFovAoaCfgPending = 0; cfg->isExtMaxVelCfgPending = 0; } /** * @b Description * @n * Resets (clears) all pending static (non-dynamic) configuration * */ void MmwDemo_resetStaticCfgPendingState(void) { uint8_t indx; for(indx = 0; indx < gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames; indx++) { gMmwMCB.subFrameCfg[indx].isAdcBufCfgPending = 0; gMmwMCB.subFrameCfg[indx].isLvdsStreamCfgPending = 0; } gMmwMCB.isAnaMonCfgPending = 0; } /** * @b Description * @n * Utility function to find out if all configuration (common and sub-frame * specific dynamic config) is in pending state. * * @retval 1 if all configuration (common and sub-frame specific dynamic config) * is in pending state, else return 0 */ uint8_t MmwDemo_isAllCfgInPendingState(void) { uint8_t indx, flag = 1; for(indx = 0; indx < gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames; indx++) { flag = flag && MmwDemo_isDynObjDetCfgPendingState(&gMmwMCB.subFrameCfg[indx].objDetDynCfg); flag = flag && (gMmwMCB.subFrameCfg[indx].isAdcBufCfgPending == 1); flag = flag && (gMmwMCB.subFrameCfg[indx].isLvdsStreamCfgPending == 1); } flag = flag && MmwDemo_isDynObjDetCommonCfgPendingState(&gMmwMCB.dataPathObj.objDetCommonCfg); flag = flag && (gMmwMCB.isAnaMonCfgPending == 1); return(flag); } /** * @b Description * @n * Utility function to find out if all configuration (common and sub-frame * specific dynamic config) is in non-pending (cleared) state. * * @retval 1 if all configuration (common and sub-frame specific dynamic config) * is in non-pending state, else return 0 */ uint8_t MmwDemo_isAllCfgInNonPendingState(void) { uint8_t indx, flag = 1; for(indx = 0; indx < gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames; indx++) { flag = flag && MmwDemo_isDynObjDetCfgInNonPendingState(&gMmwMCB.subFrameCfg[indx].objDetDynCfg); flag = flag && (gMmwMCB.subFrameCfg[indx].isAdcBufCfgPending == 0); flag = flag && (gMmwMCB.subFrameCfg[indx].isLvdsStreamCfgPending == 0); } flag = flag && (MmwDemo_isDynObjDetCommonCfgInNonPendingState(&gMmwMCB.dataPathObj.objDetCommonCfg) && flag); flag = flag && (gMmwMCB.isAnaMonCfgPending == 0); return(flag); } /** * @b Description * @n * Utility function to apply configuration to specified sub-frame * * @param[in] srcPtr Pointer to configuration * @param[in] offset Offset of configuration within the parent structure * @param[in] size Size of configuration * @param[in] subFrameNum Sub-frame Number (0 based) to apply to, broadcast to * all sub-frames if special code MMWDEMO_SUBFRAME_NUM_FRAME_LEVEL_CONFIG * * @retval * Success - 0 * @retval * Error - <0 */ void MmwDemo_CfgUpdate(void *srcPtr, uint32_t offset, uint32_t size, int8_t subFrameNum) { /* if subFrameNum undefined, broadcast to all sub-frames */ if(subFrameNum == MMWDEMO_SUBFRAME_NUM_FRAME_LEVEL_CONFIG) { uint8_t indx; for(indx = 0; indx < RL_MAX_SUBFRAMES; indx++) { memcpy((void *)((uint32_t) &gMmwMCB.subFrameCfg[indx] + offset), srcPtr, size); MmwDemo_setSubFramePendingState(&gMmwMCB.subFrameCfg[indx], offset); } } else { /* Apply configuration to specific subframe (or to position zero for the legacy case where there is no advanced frame config) */ memcpy((void *)((uint32_t) &gMmwMCB.subFrameCfg[subFrameNum] + offset), srcPtr, size); MmwDemo_setSubFramePendingState(&gMmwMCB.subFrameCfg[subFrameNum], offset); } } /** * @b Description * @n * mmw demo helper Function to issue MMWave_stop. The DPM_stop will be called * in the BSS frame done call back case. * * @retval None */ void MmwDemo_MMWave_stop(void) { int32_t errCode; DebugP_log0("App: Issuing MMWave_stop\n"); /* Stop the mmWave module: */ if (MMWave_stop (gMmwMCB.ctrlHandle, &errCode) < 0) { MMWave_ErrorLevel errorLevel; int16_t mmWaveErrorCode; int16_t subsysErrorCode; /* Error/Warning: Unable to stop the mmWave module */ MMWave_decodeError (errCode, &errorLevel, &mmWaveErrorCode, &subsysErrorCode); if (errorLevel == MMWave_ErrorLevel_ERROR) { /* Error: Display the error message: */ System_printf ("Error: mmWave Stop failed [Error code: %d Subsystem: %d]\n", mmWaveErrorCode, subsysErrorCode); /* Not expected */ MmwDemo_debugAssert(0); } else { /* Warning: This is treated as a successful stop. */ System_printf ("mmWave Stop error ignored [Error code: %d Subsystem: %d]\n", mmWaveErrorCode, subsysErrorCode); } } } /** * @b Description * @n * Epilog processing after sensor has stopped * * @retval None */ void MmwDemo_sensorStopEpilog(void) { Task_Stat stat; Hwi_StackInfo stackInfo; Bool stackOverflow; /* Print task statistics, note data path has completely stopped due to * end of frame, so we can do non-real time processing like prints on * console */ System_printf("Data Path Stopped (last frame processing done)\n"); System_printf("Task Stack Usage (Note: CLI and sensor Management Task not reported) ==========\n"); System_printf("%20s %12s %12s %12s\n", "Task Name", "Size", "Used", "Free"); Task_stat(gMmwMCB.taskHandles.initTask, &stat); System_printf("%20s %12d %12d %12d\n", "Init", stat.stackSize, stat.used, stat.stackSize - stat.used); Task_stat(gMmwMCB.taskHandles.mmwaveCtrl, &stat); System_printf("%20s %12d %12d %12d\n", "Mmwave Control", stat.stackSize, stat.used, stat.stackSize - stat.used); Task_stat(gMmwMCB.taskHandles.objDetDpmTask, &stat); System_printf("%20s %12d %12d %12d\n", "ObjDet DPM", stat.stackSize, stat.used, stat.stackSize - stat.used); System_printf("HWI Stack (same as System Stack) Usage ============\n"); stackOverflow = Hwi_getStackInfo(&stackInfo, TRUE); if (stackOverflow == TRUE) { System_printf("HWI Stack overflowed\n"); MmwDemo_debugAssert(0); } else { System_printf("%20s %12s %12s %12s\n", " ", "Size", "Used", "Free"); System_printf("%20s %12d %12d %12d\n", " ", stackInfo.hwiStackSize, stackInfo.hwiStackPeak, stackInfo.hwiStackSize - stackInfo.hwiStackPeak); } } /** * @b Description * @n * Function to Setup the HSI Clock. Required for LVDS streaming. * * @retval * 0 - Success. * <0 - Failed with errors */ int32_t MmwDemo_mssSetHsiClk(void) { rlDevHsiClk_t hsiClkgs; int32_t retVal; /************************************************************************************* * Setup the HSI Clock through the mmWave Link: *************************************************************************************/ memset ((void*)&hsiClkgs, 0, sizeof(rlDevHsiClk_t)); /* Setup the HSI Clock as per the Radar Interface Document: * - This is set to 600Mhz DDR Mode */ hsiClkgs.hsiClk = 0x9; /* Setup the HSI in the radar link: */ retVal = rlDeviceSetHsiClk(RL_DEVICE_MAP_CASCADED_1, &hsiClkgs); if (retVal != RL_RET_CODE_OK) { /* Error: Unable to set the HSI clock */ System_printf ("Error: Setting up the HSI Clock Failed [Error %d]\n", retVal); return -1; } /*The delay below is needed only if the DCA1000EVM is being used to capture the data traces. This is needed because the DCA1000EVM FPGA needs the delay to lock to the bit clock before they can start capturing the data correctly. */ Task_sleep(HSI_DCA_MIN_DELAY_MSEC); return 0; } /** * @b Description * @n * mmw demo helper Function to do one time sensor initialization. * User need to fill gMmwMCB.cfg.openCfg before calling this function * * @param[in] isFirstTimeOpen if true then issues MMwave_open * * @retval 0 if no error, -1 if error */ int32_t MmwDemo_openSensor(bool isFirstTimeOpen) { int32_t errCode; MMWave_ErrorLevel errorLevel; int16_t mmWaveErrorCode; int16_t subsysErrorCode; int32_t retVal; MMWave_CalibrationData calibrationDataCfg; MMWave_CalibrationData *ptrCalibrationDataCfg; /* Open mmWave module, this is only done once */ if (isFirstTimeOpen == true) { System_printf ("Debug: Sending rlRfSetLdoBypassConfig with %d %d %d\n", gRFLdoBypassCfg.ldoBypassEnable, gRFLdoBypassCfg.supplyMonIrDrop, gRFLdoBypassCfg.ioSupplyIndicator); retVal = rlRfSetLdoBypassConfig(RL_DEVICE_MAP_INTERNAL_BSS, (rlRfLdoBypassCfg_t*)&gRFLdoBypassCfg); if(retVal != 0) { System_printf("Error: rlRfSetLdoBypassConfig retVal=%d\n", retVal); return -1; } /* Setup the calibration frequency */ gMmwMCB.cfg.openCfg.freqLimitLow = 600U; gMmwMCB.cfg.openCfg.freqLimitHigh = 640U; /* start/stop async events */ gMmwMCB.cfg.openCfg.disableFrameStartAsyncEvent = false; gMmwMCB.cfg.openCfg.disableFrameStopAsyncEvent = false; /* No custom calibration: */ gMmwMCB.cfg.openCfg.useCustomCalibration = false; gMmwMCB.cfg.openCfg.customCalibrationEnableMask = 0x0; /* calibration monitoring base time unit * setting it to one frame duration as the demo doesnt support any * monitoring related functionality */ gMmwMCB.cfg.openCfg.calibMonTimeUnit = 1; if( (gMmwMCB.calibCfg.saveEnable != 0) && (gMmwMCB.calibCfg.restoreEnable != 0) ) { /* Error: only one can be enabled at at time */ System_printf ("Error: MmwDemo failed with both save and restore enabled.\n"); return -1; } if(gMmwMCB.calibCfg.restoreEnable != 0) { if(MmwDemo_calibRestore(&gCalibDataStorage) < 0) { /* Error: only one can be enable at at time */ System_printf ("Error: MmwDemo failed restoring calibration data from flash.\n"); return -1; } /* Boot calibration during restore: Disable calibration for: - Rx gain, - Rx IQMM, - Tx phase shifer, - Tx Power The above calibration data will be restored from flash. Since they are calibrated in a control way to avoid interfaerence and spec violations. In this demo, other bit fields(except the above) are enabled as indicated in customCalibrationEnableMask to perform boot time calibration. The boot time calibration will overwrite the restored calibration data from flash. However other bit fields can be disabled and calibration data can be restored from flash as well. Note: In this demo, calibration masks are enabled for all bit fields when "saving" the data. */ gMmwMCB.cfg.openCfg.useCustomCalibration = true; gMmwMCB.cfg.openCfg.customCalibrationEnableMask = 0x1F0U; calibrationDataCfg.ptrCalibData = &gCalibDataStorage.calibData; calibrationDataCfg.ptrPhaseShiftCalibData = &gCalibDataStorage.phaseShiftCalibData; ptrCalibrationDataCfg = &calibrationDataCfg; } else { ptrCalibrationDataCfg = NULL; } /* Open the mmWave module: */ if (MMWave_open (gMmwMCB.ctrlHandle, &gMmwMCB.cfg.openCfg, ptrCalibrationDataCfg, &errCode) < 0) { /* Error: decode and Report the error */ MMWave_decodeError (errCode, &errorLevel, &mmWaveErrorCode, &subsysErrorCode); System_printf ("Error: mmWave Open failed [Error code: %d Subsystem: %d]\n", mmWaveErrorCode, subsysErrorCode); return -1; } /* Save calibration data in flash */ if(gMmwMCB.calibCfg.saveEnable != 0) { retVal = rlRfCalibDataStore(RL_DEVICE_MAP_INTERNAL_BSS, &gCalibDataStorage.calibData); if(retVal != RL_RET_CODE_OK) { /* Error: Calibration data restore failed */ System_printf("MSS demo failed rlRfCalibDataStore with Error[%d]\n", retVal); return -1; } #if (defined(SOC_XWR18XX) || defined(SOC_XWR68XX)) /* update txIndex in all chunks to get data from all Tx. This should be done regardless of num TX channels enabled in MMWave_OpenCfg_t::chCfg or number of Tx application is interested in. Data for all existing Tx channels should be retrieved from RadarSS and in the order as shown below. RadarSS will return non-zero phase shift values for all the channels enabled via MMWave_OpenCfg_t::chCfg and zero phase shift values for channels disabled in MMWave_OpenCfg_t::chCfg */ gCalibDataStorage.phaseShiftCalibData.PhShiftcalibChunk[0].txIndex = 0; gCalibDataStorage.phaseShiftCalibData.PhShiftcalibChunk[1].txIndex = 1; gCalibDataStorage.phaseShiftCalibData.PhShiftcalibChunk[2].txIndex = 2; /* Basic validation passed: Restore the phase shift calibration data */ retVal = rlRfPhShiftCalibDataStore(RL_DEVICE_MAP_INTERNAL_BSS, &(gCalibDataStorage.phaseShiftCalibData)); if (retVal != RL_RET_CODE_OK) { /* Error: Phase shift Calibration data restore failed */ System_printf("MSS demo failed rlRfPhShiftCalibDataStore with Error[%d]\n", retVal); return retVal; } #endif /* Save data in flash */ retVal = MmwDemo_calibSave(&gMmwMCB.calibCfg.calibDataHdr, &gCalibDataStorage); if(retVal < 0) { return retVal; } } /*Set up HSI clock*/ if(MmwDemo_mssSetHsiClk() < 0) { System_printf ("Error: MmwDemo_mssSetHsiClk failed.\n"); return -1; } } return 0; } /** * @b Description * @n * mmw demo helper Function to configure sensor. * User need to fill gMmwMCB.cfg.ctrlCfg and add profiles/chirp to mmWave * before calling this function * * @retval 0 if no error, error code otherwise */ int32_t MmwDemo_configSensor(void) { int32_t errCode = 0; /* Configure the mmWave module: */ if (MMWave_config (gMmwMCB.ctrlHandle, &gMmwMCB.cfg.ctrlCfg, &errCode) < 0) { MMWave_ErrorLevel errorLevel; int16_t mmWaveErrorCode; int16_t subsysErrorCode; /* Error: Report the error */ MMWave_decodeError (errCode, &errorLevel, &mmWaveErrorCode, &subsysErrorCode); System_printf ("Error: mmWave Config failed [Error code: %d Subsystem: %d]\n", mmWaveErrorCode, subsysErrorCode); goto exit; } else { errCode = MmwDemo_dataPathConfig(); goto exit; } exit: return errCode; } /** * @b Description * @n * mmw demo helper Function to start sensor. * * @retval 0 if no error, -1 if error */ int32_t MmwDemo_startSensor(void) { int32_t errCode; MMWave_CalibrationCfg calibrationCfg; /***************************************************************************** * Data path :: start data path first - this will pend for DPC to ack *****************************************************************************/ MmwDemo_dataPathStart(); /***************************************************************************** * RF :: now start the RF and the real time ticking *****************************************************************************/ /* Initialize the calibration configuration: */ memset ((void *)&calibrationCfg, 0, sizeof(MMWave_CalibrationCfg)); /* Populate the calibration configuration: */ calibrationCfg.dfeDataOutputMode = gMmwMCB.cfg.ctrlCfg.dfeDataOutputMode; calibrationCfg.u.chirpCalibrationCfg.enableCalibration = true; calibrationCfg.u.chirpCalibrationCfg.enablePeriodicity = true; calibrationCfg.u.chirpCalibrationCfg.periodicTimeInFrames = 10U; DebugP_log0("App: MMWave_start Issued\n"); System_printf("Starting Sensor (issuing MMWave_start)\n"); /* Start the mmWave module: The configuration has been applied successfully. */ if (MMWave_start(gMmwMCB.ctrlHandle, &calibrationCfg, &errCode) < 0) { MMWave_ErrorLevel errorLevel; int16_t mmWaveErrorCode; int16_t subsysErrorCode; /* Error/Warning: Unable to start the mmWave module */ MMWave_decodeError (errCode, &errorLevel, &mmWaveErrorCode, &subsysErrorCode); System_printf ("Error: mmWave Start failed [mmWave Error: %d Subsys: %d]\n", mmWaveErrorCode, subsysErrorCode); /* datapath has already been moved to start state; so either we initiate a cleanup of start sequence or assert here and re-start from the beginning. For now, choosing the latter path */ MmwDemo_debugAssert(0); return -1; } /***************************************************************************** * The sensor has been started successfully. Switch on the LED *****************************************************************************/ GPIO_write (gMmwMCB.cfg.platformCfg.SensorStatusGPIO, 1U); gMmwMCB.sensorStartCount++; return 0; } /** * @b Description * @n * Utility function to convert the CFAR threshold * from a CLI encoded dB value to a linear value * as expected by the CFAR DPU * * @param[in] codedCfarVal CFAR threshold in dB as encoded in the CLI * @param[in] numVirtualAntennas Number of virtual antennas * * @retval * CFAR threshold in linear format */ static uint16_t MmwDemo_convertCfarToLinear(uint16_t codedCfarVal, uint8_t numVirtualAntennas) { uint16_t linearVal; float dbVal, linVal; /* dbVal is a float value from 0-100dB. It needs to be converted to linear scale.. First, recover float dbVal that was encoded in CLI. */ dbVal = (float)(codedCfarVal / MMWDEMO_CFAR_THRESHOLD_ENCODING_FACTOR); /* Now convert it to linear value according to the following: linear_value = dB_value * (256 / 6) * (numVirtualAntennas / (2^ ceil(log2(numVirtualAntennas)))) . */ linVal = dbVal * (256.0 / 6.0) * ((float)numVirtualAntennas / (float)(1 << mathUtils_ceilLog2(numVirtualAntennas))); linearVal = (uint16_t) linVal; return (linearVal); } /** * @b Description * @n * Stops the RF and datapath for the sensor. Blocks until both operation are not complete * Prints epilog at the end * * @retval None */ void MmwDemo_stopSensor() { int32_t errCode; MmwDemo_MMWave_stop(); /* Wait until DPM_stop is completed */ Semaphore_pend(gMmwMCB.DPMstopSemHandle, BIOS_WAIT_FOREVER); /* Delete any active streaming session */ if(gMmwMCB.lvdsStream.hwSessionHandle != NULL) { /* Evaluate need to deactivate h/w session: * One sub-frame case: * if h/w only enabled, deactivation never happened, hence need to deactivate * if h/w and s/w both enabled, then s/w would leave h/w activated when it is done * so need to deactivate * (only s/w enabled cannot be the case here because we are checking for non-null h/w session) * Multi sub-frame case: * Given stop, we must have re-configured the next sub-frame by now which is next of the * last sub-frame i.e we must have re-configured sub-frame 0. So if sub-frame 0 had * h/w enabled, then it is left in active state and need to deactivate. For all * other cases, h/w was already deactivated when done. */ if ((gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames == 1) || ((gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames > 1) && (gMmwMCB.subFrameCfg[0].lvdsStreamCfg.dataFmt != MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_DISABLED)) ) { if (CBUFF_deactivateSession(gMmwMCB.lvdsStream.hwSessionHandle, &errCode) < 0) { System_printf("CBUFF_deactivateSession failed with errorCode = %d\n", errCode); MmwDemo_debugAssert(0); } } MmwDemo_LVDSStreamDeleteHwSession(); } /* Delete s/w session if it exists. S/w session never needs to be deactivated in stop because * it always (unconditionally) deactivates itself upon completion. */ if(gMmwMCB.lvdsStream.swSessionHandle != NULL) { MmwDemo_LVDSStreamDeleteSwSession(); } MmwDemo_sensorStopEpilog(); /* The sensor has been stopped successfully. Switch off the LED */ GPIO_write (gMmwMCB.cfg.platformCfg.SensorStatusGPIO, 0U); gMmwMCB.sensorStopCount++; /* print for user */ System_printf("Sensor has been stopped: startCount: %d stopCount %d\n", gMmwMCB.sensorStartCount,gMmwMCB.sensorStopCount); } /** * @b Description * @n * This function is called at the init time from @ref MmwDemo_initTask. * It initializes drivers: ADCBUF, HWA, EDMA, and semaphores used * by @ref MmwDemo_dataPathTask * @retval * Not Applicable. */ void MmwDemo_dataPathInit(MmwDemo_DataPathObj *obj) { MmwDemo_dataPathObjInit(obj); /* Initialize HWA */ MmwDemo_hwaInit(obj); /* Initialize EDMA */ MmwDemo_edmaInit(obj); } /** * @b Description * @n * Opens HWA, EDMA and ADCBUF drivers * * @param[in] obj pointer to data path object * * @retval * Not Applicable. */ void MmwDemo_dataPathOpen(MmwDemo_DataPathObj *obj) { MmwDemo_hwaOpen(obj, gMmwMCB.socHandle); MmwDemo_edmaOpen(obj); obj->adcbufHandle = MmwDemo_ADCBufOpen(gMmwMCB.socHandle); } /** * @b Description * @n * Function to configure CQ. * * @param[in] subFrameCfg Pointer to sub-frame config * @param[in] numChirpsPerChirpEvent number of chirps per chirp event * @param[in] validProfileIdx valid profile index * * @retval * 0 if no error, else error (there will be system prints for these). */ static int32_t MmwDemo_configCQ(MmwDemo_SubFrameCfg *subFrameCfg, uint8_t numChirpsPerChirpEvent, uint8_t validProfileIdx) { MmwDemo_AnaMonitorCfg* ptrAnaMonitorCfg; ADCBuf_CQConf cqConfig; rlRxSatMonConf_t* ptrSatMonCfg; rlSigImgMonConf_t* ptrSigImgMonCfg; int32_t retVal; uint16_t cqChirpSize; /* Get analog monitor configuration */ ptrAnaMonitorCfg = &gMmwMCB.anaMonCfg; /* Config mmwaveLink to enable Saturation monitor - CQ2 */ ptrSatMonCfg = &gMmwMCB.cqSatMonCfg[validProfileIdx]; if (ptrAnaMonitorCfg->rxSatMonEn) { if (ptrSatMonCfg->profileIndx != validProfileIdx) { System_printf ("Error: Saturation monitoring (globally) enabled but not configured for profile(%d)\n", validProfileIdx); MmwDemo_debugAssert(0); } retVal = mmwDemo_cfgRxSaturationMonitor(ptrSatMonCfg); if(retVal != 0) { System_printf ("Error: rlRfRxIfSatMonConfig returns error = %d for profile(%d)\n", retVal, ptrSatMonCfg->profileIndx); goto exit; } } /* Config mmwaveLink to enable Saturation monitor - CQ1 */ ptrSigImgMonCfg = &gMmwMCB.cqSigImgMonCfg[validProfileIdx]; if (ptrAnaMonitorCfg->sigImgMonEn) { if (ptrSigImgMonCfg->profileIndx != validProfileIdx) { System_printf ("Error: Sig/Image monitoring (globally) enabled but not configured for profile(%d)\n", validProfileIdx); MmwDemo_debugAssert(0); } retVal = mmwDemo_cfgRxSigImgMonitor(ptrSigImgMonCfg); if(retVal != 0) { System_printf ("Error: rlRfRxSigImgMonConfig returns error = %d for profile(%d)\n", retVal, ptrSigImgMonCfg->profileIndx); goto exit; } } retVal = mmwDemo_cfgAnalogMonitor(ptrAnaMonitorCfg); if (retVal != 0) { System_printf ("Error: rlRfAnaMonConfig returns error = %d\n", retVal); goto exit; } if(ptrAnaMonitorCfg->rxSatMonEn || ptrAnaMonitorCfg->sigImgMonEn) { /* CQ driver config */ memset((void *)&cqConfig, 0, sizeof(ADCBuf_CQConf)); cqConfig.cqDataWidth = 0; /* 16bit for mmw demo */ cqConfig.cq1AddrOffset = MMW_DEMO_CQ_SIGIMG_ADDR_OFFSET; /* CQ1 starts from the beginning of the buffer */ cqConfig.cq2AddrOffset = MMW_DEMO_CQ_RXSAT_ADDR_OFFSET; /* Address should be 16 bytes aligned */ retVal = ADCBuf_control(gMmwMCB.dataPathObj.adcbufHandle, ADCBufMMWave_CMD_CONF_CQ, (void *)&cqConfig); if (retVal < 0) { System_printf ("Error: MMWDemoDSS Unable to configure the CQ\n"); MmwDemo_debugAssert(0); } } if (ptrAnaMonitorCfg->sigImgMonEn) { /* This is for 16bit format in mmw demo, signal/image band data has 2 bytes/slice For other format, please check DFP interface document */ cqChirpSize = (ptrSigImgMonCfg->numSlices + 1) * sizeof(uint16_t); cqChirpSize = MATHUTILS_ROUND_UP_UNSIGNED(cqChirpSize, MMW_DEMO_CQ_DATA_ALIGNMENT); subFrameCfg->sigImgMonTotalSize = cqChirpSize * numChirpsPerChirpEvent; } if (ptrAnaMonitorCfg->rxSatMonEn) { /* This is for 16bit format in mmw demo, saturation data has one byte/slice For other format, please check DFP interface document */ cqChirpSize = (ptrSatMonCfg->numSlices + 1) * sizeof(uint8_t); cqChirpSize = MATHUTILS_ROUND_UP_UNSIGNED(cqChirpSize, MMW_DEMO_CQ_DATA_ALIGNMENT); subFrameCfg->satMonTotalSize = cqChirpSize * numChirpsPerChirpEvent; } exit: return(retVal); } /** * @b Description * @n * The function is used to configure the data path based on the chirp profile. * After this function is executed, the data path processing will ready to go * when the ADC buffer starts receiving samples corresponding to the chirps. * * @retval * 0 if no error, error code otherwise. */ int32_t MmwDemo_dataPathConfig (void) { int32_t errCode; MMWave_CtrlCfg *ptrCtrlCfg; MmwDemo_DataPathObj *dataPathObj = &gMmwMCB.dataPathObj; MmwDemo_SubFrameCfg *subFrameCfg; int8_t subFrameIndx; MmwDemo_RFParserOutParams RFparserOutParams; /* Get data path object and control configuration */ ptrCtrlCfg = &gMmwMCB.cfg.ctrlCfg; gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames = MmwDemo_RFParser_getNumSubFrames(ptrCtrlCfg); DebugP_log0("App: Issuing Pre-start Common Config IOCTL\n"); gMmwMCB.rfFreqScaleFactor = SOC_getDeviceRFFreqScaleFactor(gMmwMCB.socHandle, &errCode); if (errCode < 0) { System_printf ("Error: Unable to get RF scale factor [Error:%d]\n", errCode); goto exit; } /* Copy antenna geometry definition */ #if defined(XWR68XX_AOP_ANTENNA_PATTERN) extern ANTDEF_AntGeometry gAntDef_IWR6843AOP; dataPathObj->objDetCommonCfg.preStartCommonCfg.antDef = gAntDef_IWR6843AOP; #else extern ANTDEF_AntGeometry gAntDef_default; dataPathObj->objDetCommonCfg.preStartCommonCfg.antDef = gAntDef_default; #endif /* DPC pre-start common config */ errCode = DPM_ioctl (dataPathObj->objDetDpmHandle, DPC_OBJDETRANGEHWA_IOCTL__STATIC_PRE_START_COMMON_CFG, &dataPathObj->objDetCommonCfg.preStartCommonCfg, sizeof (DPC_ObjectDetectionRangeHWA_PreStartCommonCfg)); if (errCode < 0) { System_printf ("Error: Unable to send DPC_OBJDET_IOCTL__STATIC_PRE_START_COMMON_CFG [Error:%d]\n", errCode); goto exit; } MmwDemo_resetDynObjDetCommonCfgPendingState(&dataPathObj->objDetCommonCfg); /* Reason for reverse loop is that when sensor is started, the first sub-frame * will be active and the ADC configuration needs to be done for that sub-frame * before starting (ADC buf hardware does not have notion of sub-frame, it will * be reconfigured every sub-frame). This cannot be alternatively done by calling * the MmwDemo_ADCBufConfig function only for the first sub-frame because this is * a utility API that computes the rxChanOffset that is part of ADC dataProperty * which will be used by range DPU and therefore this computation is required for * all sub-frames. */ for(subFrameIndx = gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames -1; subFrameIndx >= 0; subFrameIndx--) { subFrameCfg = &gMmwMCB.subFrameCfg[subFrameIndx]; /***************************************************************************** * Data path :: Algorithm Configuration *****************************************************************************/ /* Parse the profile and chirp configs and get the valid number of TX Antennas */ errCode = MmwDemo_RFParser_parseConfig(&RFparserOutParams, subFrameIndx, &gMmwMCB.cfg.openCfg, ptrCtrlCfg, &subFrameCfg->adcBufCfg, gMmwMCB.rfFreqScaleFactor, false/* no BPM in 64xx demo */); /* if number of doppler chirps is too low, interpolate to be able to detect * better with CFAR tuning. E.g. a 2-pt FFT will be problematic in terms * of distinguishing direction of motion */ if (RFparserOutParams.numDopplerChirps <= 4) { RFparserOutParams.dopplerStep = RFparserOutParams.dopplerStep / (8 / RFparserOutParams.numDopplerBins); RFparserOutParams.numDopplerBins = 8; } if (errCode != 0) { System_printf ("Error: MmwDemo_RFParser_parseConfig [Error:%d]\n", errCode); goto exit; } { DPC_ObjectDetection_PreStartCfg objDetPreStartCfg; DPC_ObjectDetection_StaticCfg *staticCfg = &objDetPreStartCfg.staticCfg; subFrameCfg->numRangeBins = RFparserOutParams.numRangeBins; /* Workaround for range DPU limitation for FFT size 1024 and 12 virtual antennas case*/ if ((RFparserOutParams.numVirtualAntennas == 12) && (RFparserOutParams.numRangeBins == 1024)) { subFrameCfg->numRangeBins = 1022; RFparserOutParams.numRangeBins = 1022; } subFrameCfg->numDopplerBins = RFparserOutParams.numDopplerBins; subFrameCfg->numChirpsPerChirpEvent = RFparserOutParams.numChirpsPerChirpEvent; subFrameCfg->adcBufChanDataSize = RFparserOutParams.adcBufChanDataSize; subFrameCfg->objDetDynCfg.dynCfg.prepareRangeAzimuthHeatMap = subFrameCfg->guiMonSel.rangeAzimuthHeatMap; subFrameCfg->numAdcSamples = RFparserOutParams.numAdcSamples; subFrameCfg->numVirtualAntennas = RFparserOutParams.numVirtualAntennas; subFrameCfg->numChirpsPerSubFrame = RFparserOutParams.numChirpsPerFrame; errCode = MmwDemo_ADCBufConfig(gMmwMCB.dataPathObj.adcbufHandle, gMmwMCB.cfg.openCfg.chCfg.rxChannelEn, subFrameCfg->numChirpsPerChirpEvent, subFrameCfg->adcBufChanDataSize, &subFrameCfg->adcBufCfg, &staticCfg->ADCBufData.dataProperty.rxChanOffset[0]); if ( errCode < 0) { System_printf("Error: ADCBuf config failed with error [%d]\n", errCode); goto exit; } errCode = MmwDemo_configCQ(subFrameCfg, RFparserOutParams.numChirpsPerChirpEvent, RFparserOutParams.validProfileIdx); if (errCode < 0) { goto exit; } /* DPC pre-start config */ { int32_t i; objDetPreStartCfg.subFrameNum = subFrameIndx; /* Fill static configuration */ staticCfg->ADCBufData.data = (void *)SOC_XWR68XX_MSS_ADCBUF_BASE_ADDRESS; staticCfg->ADCBufData.dataProperty.adcBits = 2; /* 16-bit */ /* only complex format supported */ MmwDemo_debugAssert(subFrameCfg->adcBufCfg.adcFmt == 0); if (subFrameCfg->adcBufCfg.iqSwapSel == 1) { staticCfg->ADCBufData.dataProperty.dataFmt = DPIF_DATAFORMAT_COMPLEX16_IMRE; } else { staticCfg->ADCBufData.dataProperty.dataFmt = DPIF_DATAFORMAT_COMPLEX16_REIM; } if (subFrameCfg->adcBufCfg.chInterleave == 0) { staticCfg->ADCBufData.dataProperty.interleave = DPIF_RXCHAN_INTERLEAVE_MODE; } else { staticCfg->ADCBufData.dataProperty.interleave = DPIF_RXCHAN_NON_INTERLEAVE_MODE; } staticCfg->ADCBufData.dataProperty.numAdcSamples = RFparserOutParams.numAdcSamples; staticCfg->ADCBufData.dataProperty.numChirpsPerChirpEvent = RFparserOutParams.numChirpsPerChirpEvent; staticCfg->ADCBufData.dataProperty.numRxAntennas = RFparserOutParams.numRxAntennas; staticCfg->ADCBufData.dataSize = RFparserOutParams.numRxAntennas * RFparserOutParams.numAdcSamples * sizeof(cmplx16ImRe_t); staticCfg->dopplerStep = RFparserOutParams.dopplerStep; staticCfg->isValidProfileHasOneTxPerChirp = RFparserOutParams.validProfileHasOneTxPerChirp; staticCfg->numChirpsPerFrame = RFparserOutParams.numChirpsPerFrame; staticCfg->numDopplerBins = RFparserOutParams.numDopplerBins; staticCfg->numDopplerChirps = RFparserOutParams.numDopplerChirps; staticCfg->numRangeBins = RFparserOutParams.numRangeBins; staticCfg->numTxAntennas = RFparserOutParams.numTxAntennas; staticCfg->numVirtualAntAzim = RFparserOutParams.numVirtualAntAzim; staticCfg->numVirtualAntElev = RFparserOutParams.numVirtualAntElev; staticCfg->numVirtualAntennas = RFparserOutParams.numVirtualAntennas; staticCfg->rangeStep = RFparserOutParams.rangeStep; staticCfg->centerFreq = RFparserOutParams.centerFreq; /* Current 64xx/68xx SOC has higher receive level as compared to 18xx and hence using higher value for * fftOutputDivShift to avoid overflow when converting from 24-bit to 16-bit * TODO: Future RadarSS firmware should be evaluated to assess if these settings are correct */ if (RFparserOutParams.numRangeBins >= 1022) { staticCfg->rangeFFTtuning.fftOutputDivShift = 1; /* scale only 2 stages */ staticCfg->rangeFFTtuning.numLastButterflyStagesToScale = 2; } else if (RFparserOutParams.numRangeBins==512) { staticCfg->rangeFFTtuning.fftOutputDivShift = 2; /* scale last stage */ staticCfg->rangeFFTtuning.numLastButterflyStagesToScale = 1; } else { staticCfg->rangeFFTtuning.fftOutputDivShift = 3; /* no scaling needed as ADC data is 16-bit and we have 8 bits to grow */ staticCfg->rangeFFTtuning.numLastButterflyStagesToScale = 0; } for (i = 0; i < RFparserOutParams.numRxAntennas; i++) { staticCfg->rxAntOrder[i] = RFparserOutParams.rxAntOrder[i]; } for (i = 0; i < RFparserOutParams.numTxAntennas; i++) { staticCfg->txAntOrder[i] = RFparserOutParams.txAntOrder[i]; } /* Convert CFAR threshold value */ subFrameCfg->objDetDynCfg.dynCfg.cfarCfgRange.thresholdScale = MmwDemo_convertCfarToLinear(subFrameCfg->objDetDynCfg.dynCfg.cfarCfgRange.thresholdScale, staticCfg->numVirtualAntennas); subFrameCfg->objDetDynCfg.dynCfg.cfarCfgDoppler.thresholdScale = MmwDemo_convertCfarToLinear(subFrameCfg->objDetDynCfg.dynCfg.cfarCfgDoppler.thresholdScale, staticCfg->numVirtualAntennas); /* Fill dynamic configuration */ objDetPreStartCfg.dynCfg = subFrameCfg->objDetDynCfg.dynCfg; DebugP_log1("App: Issuing Pre-start Config IOCTL (subFrameIndx = %d)\n", subFrameIndx); /* send pre-start config */ errCode = DPM_ioctl (dataPathObj->objDetDpmHandle, DPC_OBJDETRANGEHWA_IOCTL__STATIC_PRE_START_CFG, &objDetPreStartCfg, sizeof (DPC_ObjectDetectionRangeHWA_PreStartCfg)); MmwDemo_resetDynObjDetCfgPendingState(&subFrameCfg->objDetDynCfg); if (errCode < 0) { System_printf ("Error: Unable to send DPC_OBJDET_IOCTL__STATIC_PRE_START_CFG [Error:%d]\n", errCode); goto exit; } } } } exit: return errCode; } /** * @b Description * @n * The function is used to start the data path manager and * underlying processing chain. It will wait for the processing chain to ack * * @retval * Not Applicable. */ void MmwDemo_dataPathStart (void) { int32_t errCode; DebugP_log0("App: Issuing DPM_start\n"); /* Configure HW LVDS stream for the first sub-frame that will start upon * start of frame */ if (gMmwMCB.subFrameCfg[0].lvdsStreamCfg.dataFmt != MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_DISABLED) { MmwDemo_configLVDSHwData(0); } /* Start the DPM Profile: */ if ((errCode = DPM_start(gMmwMCB.dataPathObj.objDetDpmHandle)) < 0) { /* Error: Unable to start the profile */ System_printf("Error: Unable to start the DPM [Error: %d]\n", errCode); MmwDemo_debugAssert(0); } /* wait until start completed */ Semaphore_pend(gMmwMCB.DPMstartSemHandle, BIOS_WAIT_FOREVER); DebugP_log0("App: DPM_start Done (post Semaphore_pend on reportFxn reporting start)\n"); } /** * @b Description * @n * The function is used to Stop data path. * * @retval * Not Applicable. */ void MmwDemo_dataPathStop (MmwDemo_DataPathObj *obj) { int32_t retVal; DebugP_log0("App: Issuing DPM_stop\n"); retVal = DPM_stop (obj->objDetDpmHandle); if (retVal < 0) { System_printf ("DPM_stop failed[Error code %d]\n", retVal); MmwDemo_debugAssert(0); } } /** * @b Description * @n * The task is used to provide an execution context for the mmWave * control task * * @retval * Not Applicable. */ void MmwDemo_mmWaveCtrlTask(UArg arg0, UArg arg1) { int32_t errCode; while (1) { /* Execute the mmWave control module: */ if (MMWave_execute (gMmwMCB.ctrlHandle, &errCode) < 0) { //System_printf ("Error: mmWave control execution failed [Error code %d]\n", errCode); MmwDemo_debugAssert (0); } } } /** * @b Description * @n * Registered event function to mmwave which is invoked when an event from the * BSS is received. * * @param[in] msgId * Message Identifier * @param[in] sbId * Subblock identifier * @param[in] sbLen * Length of the subblock * @param[in] payload * Pointer to the payload buffer * * @retval * Always return 0 */ int32_t MmwDemo_eventCallbackFxn(uint16_t msgId, uint16_t sbId, uint16_t sbLen, uint8_t *payload) { uint16_t asyncSB = RL_GET_SBID_FROM_UNIQ_SBID(sbId); /* Process the received message: */ switch (msgId) { case RL_RF_ASYNC_EVENT_MSG: { /* Received Asychronous Message: */ switch (asyncSB) { case RL_RF_AE_CPUFAULT_SB: { MmwDemo_debugAssert(0); break; } case RL_RF_AE_ESMFAULT_SB: { MmwDemo_debugAssert(0); break; } case RL_RF_AE_ANALOG_FAULT_SB: { MmwDemo_debugAssert(0); break; } case RL_RF_AE_INITCALIBSTATUS_SB: { rlRfInitComplete_t* ptrRFInitCompleteMessage; uint32_t calibrationStatus; /* Get the RF-Init completion message: */ ptrRFInitCompleteMessage = (rlRfInitComplete_t*)payload; calibrationStatus = ptrRFInitCompleteMessage->calibStatus & 0x1FFFU; /* Display the calibration status: */ CLI_write ("Debug: Init Calibration Status = 0x%x\n", calibrationStatus); break; } case RL_RF_AE_FRAME_TRIGGER_RDY_SB: { gMmwMCB.stats.frameTriggerReady++; break; } case RL_RF_AE_MON_TIMING_FAIL_REPORT_SB: { gMmwMCB.stats.failedTimingReports++; break; } case RL_RF_AE_RUN_TIME_CALIB_REPORT_SB: { gMmwMCB.stats.calibrationReports++; break; } case RL_RF_AE_FRAME_END_SB: { gMmwMCB.stats.sensorStopped++; DebugP_log0("App: BSS stop (frame end) received\n"); MmwDemo_dataPathStop(&gMmwMCB.dataPathObj); break; } default: { System_printf ("Error: Asynchronous Event SB Id %d not handled\n", asyncSB); break; } } break; } /* Async Event from MMWL */ case RL_MMWL_ASYNC_EVENT_MSG: { switch (asyncSB) { case RL_MMWL_AE_MISMATCH_REPORT: { /* link reports protocol error in the async report from BSS */ MmwDemo_debugAssert(0); break; } case RL_MMWL_AE_INTERNALERR_REPORT: { /* link reports internal error during BSS communication */ MmwDemo_debugAssert(0); break; } } break; } default: { System_printf ("Error: Asynchronous message %d is NOT handled\n", msgId); break; } } return 0; } /** * @b Description * @n * DPM Registered Report Handler. The DPM Module uses this registered function to notify * the application about DPM reports. * * @param[in] reportType * Report Type * @param[in] instanceId * Instance Identifier which generated the report * @param[in] errCode * Error code if any. * @param[in] arg0 * Argument 0 interpreted with the report type * @param[in] arg1 * Argument 1 interpreted with the report type * * @retval * Not Applicable. */ static void MmwDemo_DPC_ObjectDetection_reportFxn ( DPM_Report reportType, uint32_t instanceId, int32_t errCode, uint32_t arg0, uint32_t arg1 ) { /* Only errors are logged on the console: */ if (errCode != 0) { /* Error: Detected log on the console and die all errors are FATAL currently. */ System_printf ("Error: DPM Report %d received with error:%d arg0:0x%x arg1:0x%x\n", reportType, errCode, arg0, arg1); DebugP_assert (0); } /* Processing further is based on the reports received: This is the control of the profile * state machine: */ switch (reportType) { case DPM_Report_IOCTL: { /***************************************************************** * DPC has been configured without an error: * - This is an indication that the profile configuration commands * went through without any issues. *****************************************************************/ DebugP_log1("App: DPM Report IOCTL, command = %d\n", arg0); if (arg0 == DPC_OBJDET_IOCTL__STATIC_PRE_START_CFG) { DPC_ObjectDetection_PreStartCfg *cfg; DPC_ObjectDetection_DPC_IOCTL_preStartCfg_memUsage *memUsage; Memory_Stats stats; Memory_getStats(NULL, &stats); /* Get memory usage from preStartCfg */ cfg = (DPC_ObjectDetection_PreStartCfg*)arg1; memUsage = &cfg->memUsage; System_printf(" ========== Memory Stats ==========\n"); System_printf("%20s %12s %12s %12s %12s\n", " ", "Size", "Used", "Free", "DPCUsed"); System_printf("%20s %12d %12d %12d %12d\n", "System Heap(TCM)", memUsage->SystemHeapTotal, memUsage->SystemHeapUsed, memUsage->SystemHeapTotal - memUsage->SystemHeapUsed, memUsage->SystemHeapDPCUsed); System_printf("%20s %12d %12d %12d\n", "L3", sizeof(gMmwL3), memUsage->L3RamUsage, sizeof(gMmwL3) - memUsage->L3RamUsage); System_printf("%20s %12d %12d %12d\n", "TCM", sizeof(gDPC_ObjDetTCM), memUsage->CoreLocalRamUsage, sizeof(gDPC_ObjDetTCM) - memUsage->CoreLocalRamUsage); } break; } case DPM_Report_DPC_STARTED: { /***************************************************************** * DPC has been started without an error: * - notify sensor management task that DPC is started. *****************************************************************/ DebugP_log0("App: DPM Report DPC Started\n"); Semaphore_post(gMmwMCB.DPMstartSemHandle); break; } case DPM_Report_NOTIFY_DPC_RESULT: { /* we cannot be getting this because we are operating in Local domain, * it is only meant for remote/distributed domain. */ MmwDemo_debugAssert(0); break; } case DPM_Report_DPC_ASSERT: { DPM_DPCAssert* ptrAssert; /***************************************************************** * DPC Fault has been detected: * - This implies that the DPC has crashed. * - The argument0 points to the DPC assertion information *****************************************************************/ ptrAssert = (DPM_DPCAssert*)arg0; CLI_write("Obj Det DPC Exception: %s, line %d.\n", ptrAssert->fileName, ptrAssert->lineNum); break; } case DPM_Report_DPC_STOPPED: { /***************************************************************** * DPC has been stopped without an error: * - This implies that the DPC can either be reconfigured or * restarted. *****************************************************************/ DebugP_log0("App: DPM Report DPC Stopped\n"); Semaphore_post(gMmwMCB.DPMstopSemHandle); break; } case DPM_Report_DPC_INFO: { /* ObjDetHwa DPC does not support this IOCTL */ break; } default: { DebugP_assert (0); break; } } return; } void MmwDemo_measurementResultOutput(DPU_AoAProc_compRxChannelBiasCfg *compRxChanCfg) { CLI_write ("compRangeBiasAndRxChanPhase"); CLI_write (" %.7f", compRxChanCfg->rangeBias); int32_t i; for (i = 0; i < SYS_COMMON_NUM_TX_ANTENNAS*SYS_COMMON_NUM_RX_CHANNEL; i++) { CLI_write (" %.5f", (float) compRxChanCfg->rxChPhaseComp[i].real/32768.); CLI_write (" %.5f", (float) compRxChanCfg->rxChPhaseComp[i].imag/32768.); } CLI_write ("\n"); } /** * @b Description * @n * Utility function to get temperature report from front end and * save it in global structure. * * @retval None */ void MmwDemo_getTemperatureReport() { /* Get Temerature report */ gMmwMCB.temperatureStats.tempReportValid = rlRfGetTemperatureReport(RL_DEVICE_MAP_INTERNAL_BSS, (rlRfTempData_t*)&gMmwMCB.temperatureStats.temperatureReport); } /** @brief Transmits detection data over UART * * The following data is transmitted: * 1. Header (size = 32bytes), including "Magic word", (size = 8 bytes) * and including the number of TLV items * TLV Items: * 2. If detectedObjects flag is 1 or 2, DPIF_PointCloudCartesian structure containing * X,Y,Z location and velocity for detected objects, * size = sizeof(DPIF_PointCloudCartesian) * number of detected objects * 3. If detectedObjects flag is 1, DPIF_PointCloudSideInfo structure containing SNR * and noise for detected objects, * size = sizeof(DPIF_PointCloudCartesian) * number of detected objects * 4. If logMagRange flag is set, rangeProfile, * size = number of range bins * sizeof(uint16_t) * 5. If noiseProfile flag is set, noiseProfile, * size = number of range bins * sizeof(uint16_t) * 6. If rangeAzimuthHeatMap flag is set, the zero Doppler column of the * range cubed matrix, size = number of Rx Azimuth virtual antennas * * number of chirps per frame * sizeof(uint32_t) * 7. If rangeDopplerHeatMap flag is set, the log magnitude range-Doppler matrix, * size = number of range bins * number of Doppler bins * sizeof(uint16_t) * 8. If statsInfo flag is set, the stats information * @param[in] uartHandle UART driver handle * @param[in] result Pointer to result from object detection DPC processing * @param[in] timingInfo Pointer to sub-frame object stats that contains timing info */ void MmwDemo_transmitProcessedOutput(UART_Handle uartHandle, DPC_ObjectDetection_ExecuteResult *result, MmwDemo_output_message_stats *timingInfo) { MmwDemo_output_message_header header; MmwDemo_GuiMonSel *pGuiMonSel; MmwDemo_SubFrameCfg *subFrameCfg; uint32_t tlvIdx = 0; uint32_t i; uint32_t numPaddingBytes; uint32_t packetLen; uint8_t padding[MMWDEMO_OUTPUT_MSG_SEGMENT_LEN]; uint16_t *detMatrix = (uint16_t *)result->detMatrix.data; MmwDemo_output_message_tl tl[MMWDEMO_OUTPUT_MSG_MAX]; /* Get subframe configuration */ subFrameCfg = &gMmwMCB.subFrameCfg[result->subFrameIdx]; /* Get Gui Monitor configuration */ pGuiMonSel = &subFrameCfg->guiMonSel; /* Clear message header */ memset((void *)&header, 0, sizeof(MmwDemo_output_message_header)); /* Header: */ header.platform = 0xA6843; header.magicWord[0] = 0x0102; header.magicWord[1] = 0x0304; header.magicWord[2] = 0x0506; header.magicWord[3] = 0x0708; header.numDetectedObj = result->numObjOut; header.version = MMWAVE_SDK_VERSION_BUILD | //DEBUG_VERSION (MMWAVE_SDK_VERSION_BUGFIX << 8) | (MMWAVE_SDK_VERSION_MINOR << 16) | (MMWAVE_SDK_VERSION_MAJOR << 24); packetLen = sizeof(MmwDemo_output_message_header); if ((pGuiMonSel->detectedObjects == 1) || (pGuiMonSel->detectedObjects == 2) && (result->numObjOut > 0)) { tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_DETECTED_POINTS; tl[tlvIdx].length = sizeof(DPIF_PointCloudCartesian) * result->numObjOut; packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } /* Side info */ if ((pGuiMonSel->detectedObjects == 1) && (result->numObjOut > 0)) { tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_DETECTED_POINTS_SIDE_INFO; tl[tlvIdx].length = sizeof(DPIF_PointCloudSideInfo) * result->numObjOut; packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } if (pGuiMonSel->logMagRange) { tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_RANGE_PROFILE; tl[tlvIdx].length = sizeof(uint16_t) * subFrameCfg->numRangeBins; packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } if (pGuiMonSel->noiseProfile) { tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_NOISE_PROFILE; tl[tlvIdx].length = sizeof(uint16_t) * subFrameCfg->numRangeBins; packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } if (pGuiMonSel->rangeAzimuthHeatMap) { #if defined(USE_2D_AOA_DPU) tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_AZIMUT_ELEVATION_STATIC_HEAT_MAP; #else tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_AZIMUT_STATIC_HEAT_MAP; #endif tl[tlvIdx].length = result->azimuthStaticHeatMapSize * sizeof(cmplx16ImRe_t); packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } if (pGuiMonSel->rangeDopplerHeatMap) { tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_RANGE_DOPPLER_HEAT_MAP; tl[tlvIdx].length = subFrameCfg->numRangeBins * subFrameCfg->numDopplerBins * sizeof(uint16_t); packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } if (pGuiMonSel->statsInfo) { tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_STATS; tl[tlvIdx].length = sizeof(MmwDemo_output_message_stats); packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; MmwDemo_getTemperatureReport(); tl[tlvIdx].type = MMWDEMO_OUTPUT_MSG_TEMPERATURE_STATS; tl[tlvIdx].length = sizeof(MmwDemo_temperatureStats); packetLen += sizeof(MmwDemo_output_message_tl) + tl[tlvIdx].length; tlvIdx++; } /* Fill header */ header.numTLVs = tlvIdx; /* Round up packet length to multiple of MMWDEMO_OUTPUT_MSG_SEGMENT_LEN */ header.totalPacketLen = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN * ((packetLen + (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1))/MMWDEMO_OUTPUT_MSG_SEGMENT_LEN); header.timeCpuCycles = Pmu_getCount(0); header.frameNumber = result->stats->frameStartIntCounter; header.subFrameNumber = result->subFrameIdx; UART_writePolling (uartHandle, (uint8_t*)&header, sizeof(MmwDemo_output_message_header)); tlvIdx = 0; /* Send detected Objects */ if ((pGuiMonSel->detectedObjects == 1) || (pGuiMonSel->detectedObjects == 2) && (result->numObjOut > 0)) { UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); /*Send array of objects */ UART_writePolling (uartHandle, (uint8_t*)result->objOut, sizeof(DPIF_PointCloudCartesian) * result->numObjOut); tlvIdx++; } /* Send detected Objects Side Info */ if ((pGuiMonSel->detectedObjects == 1) && (result->numObjOut > 0)) { UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); /*Send array of objects */ UART_writePolling (uartHandle, (uint8_t*)result->objOutSideInfo, sizeof(DPIF_PointCloudSideInfo) * result->numObjOut); tlvIdx++; } /* Send Range profile */ if (pGuiMonSel->logMagRange) { UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); for(i = 0; i < subFrameCfg->numRangeBins; i++) { UART_writePolling (uartHandle, (uint8_t*)&detMatrix[i * subFrameCfg->numDopplerBins], sizeof(uint16_t)); } tlvIdx++; } /* Send noise profile */ if (pGuiMonSel->noiseProfile) { uint32_t maxDopIdx = subFrameCfg->numDopplerBins/2 -1; UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); for(i = 0; i < subFrameCfg->numRangeBins; i++) { UART_writePolling (uartHandle, (uint8_t*)&detMatrix[i * subFrameCfg->numDopplerBins + maxDopIdx], sizeof(uint16_t)); } tlvIdx++; } /* Send data for static azimuth heatmap */ if (pGuiMonSel->rangeAzimuthHeatMap) { UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); UART_writePolling (uartHandle, (uint8_t *) result->azimuthStaticHeatMap, result->azimuthStaticHeatMapSize * sizeof(cmplx16ImRe_t)); tlvIdx++; } /* Send data for range/Doppler heatmap */ if (pGuiMonSel->rangeDopplerHeatMap == 1) { UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); UART_writePolling (uartHandle, (uint8_t*)detMatrix, tl[tlvIdx].length); tlvIdx++; } /* Send stats information */ if (pGuiMonSel->statsInfo == 1) { UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); UART_writePolling (uartHandle, (uint8_t*)timingInfo, tl[tlvIdx].length); tlvIdx++; UART_writePolling (uartHandle, (uint8_t*)&tl[tlvIdx], sizeof(MmwDemo_output_message_tl)); UART_writePolling (uartHandle, (uint8_t*)&gMmwMCB.temperatureStats, tl[tlvIdx].length); tlvIdx++; } /* Send padding bytes */ numPaddingBytes = MMWDEMO_OUTPUT_MSG_SEGMENT_LEN - (packetLen & (MMWDEMO_OUTPUT_MSG_SEGMENT_LEN-1)); if (numPaddingBytes<MMWDEMO_OUTPUT_MSG_SEGMENT_LEN) { UART_writePolling (uartHandle, (uint8_t*)padding, numPaddingBytes); } } /** * @b Description * @n * Utility function to get next sub-frame index * * @param[in] currentIndx Current sub-frame index * @param[in] numSubFrames Number of sub-frames * * @retval * Index of next sub-frame. */ // static uint8_t MmwDemo_getNextSubFrameIndx(uint8_t currentIndx, uint8_t numSubFrames) // { // uint8_t nextIndx; // if (currentIndx == (numSubFrames - 1)) // { // nextIndx = 0; // } // else // { // nextIndx = currentIndx + 1; // } // return(nextIndx); // } /** * @b Description * @n * Utility function to get previous sub-frame index * * @param[in] currentIndx Current sub-frame index * @param[in] numSubFrames Number of sub-frames * * @retval * Index of previous sub-frame */ // static uint8_t MmwDemo_getPrevSubFrameIndx(uint8_t currentIndx, uint8_t numSubFrames) // { // uint8_t prevIndx; // if (currentIndx == 0) // { // prevIndx = numSubFrames - 1; // } // else // { // prevIndx = currentIndx - 1; // } // return(prevIndx); // } /** * @b Description * @n * Processes any pending dynamic configuration commands for the specified * sub-frame by fanning out to the respective DPUs using IOCTL interface, and * resets (clears) the pending state after processing. * * @param[in] subFrameIndx Sub-frame index of desired sub-frame to process * * @retval * Success - 0 * @retval * Error - <0 */ // static int32_t MmwDemo_processPendingDynamicCfgCommands(uint8_t subFrameIndx) // { // int32_t retVal = 0; // MmwDemo_DPC_ObjDet_CommonCfg *commonCfg = &gMmwMCB.dataPathObj.objDetCommonCfg; // MmwDemo_DPC_ObjDet_DynCfg *subFrameCfg = &gMmwMCB.subFrameCfg[subFrameIndx].objDetDynCfg; // uint8_t numVirtualAntennas = gMmwMCB.subFrameCfg[subFrameIndx].numVirtualAntennas; // /* perform globals ones if first sub-frame */ // if (subFrameIndx == 0) // { // if (commonCfg->isMeasureRxChannelBiasCfgPending == 1) // { // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_MEASURE_RANGE_BIAS_AND_RX_CHAN_PHASE, // &commonCfg->preStartCommonCfg.measureRxChannelBiasCfg, // sizeof (DPC_ObjectDetection_MeasureRxChannelBiasCfg)); // if (retVal != 0) // { // goto exit; // } // commonCfg->isMeasureRxChannelBiasCfgPending = 0; // } // if (commonCfg->isCompRxChannelBiasCfgPending == 1) // { // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_COMP_RANGE_BIAS_AND_RX_CHAN_PHASE, // &commonCfg->preStartCommonCfg.compRxChanCfg, // sizeof (DPU_AoAProc_compRxChannelBiasCfg)); // if (retVal != 0) // { // goto exit; // } // commonCfg->isCompRxChannelBiasCfgPending = 0; // } // } // /* Perform sub-frame specific ones */ // if (subFrameCfg->isCalibDcRangeSigCfg == 1) // { // DPC_ObjectDetection_CalibDcRangeSigCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.calibDcRangeSigCfg; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_CALIB_DC_RANGE_SIG_CFG, // &cfg, // sizeof (DPC_ObjectDetection_CalibDcRangeSigCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isCalibDcRangeSigCfg = 0; // } // if (subFrameCfg->isCfarCfgDopplerPending == 1) // { // DPC_ObjectDetection_CfarCfg cfg; // cfg.subFrameNum = subFrameIndx; // /* Update with correct threshold value based on number of virtual antennas */ // subFrameCfg->dynCfg.cfarCfgDoppler.thresholdScale = // MmwDemo_convertCfarToLinear(subFrameCfg->dynCfg.cfarCfgDoppler.thresholdScale, // numVirtualAntennas); // cfg.cfg = subFrameCfg->dynCfg.cfarCfgDoppler; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_CFAR_DOPPLER_CFG, // &cfg, // sizeof (DPC_ObjectDetection_CfarCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isCfarCfgDopplerPending = 0; // } // if (subFrameCfg->isCfarCfgRangePending == 1) // { // DPC_ObjectDetection_CfarCfg cfg; // cfg.subFrameNum = subFrameIndx; // /* Update with correct threshold value based on number of virtual antennas */ // subFrameCfg->dynCfg.cfarCfgRange.thresholdScale = // MmwDemo_convertCfarToLinear(subFrameCfg->dynCfg.cfarCfgRange.thresholdScale, // numVirtualAntennas); // cfg.cfg = subFrameCfg->dynCfg.cfarCfgRange; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_CFAR_RANGE_CFG, // &cfg, // sizeof (DPC_ObjectDetection_CfarCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isCfarCfgRangePending = 0; // } // if (subFrameCfg->isFovDopplerPending == 1) // { // DPC_ObjectDetection_fovDopplerCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.fovDoppler; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_FOV_DOPPLER, // &cfg, // sizeof (DPC_ObjectDetection_fovDopplerCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isFovDopplerPending = 0; // } // if (subFrameCfg->isFovRangePending == 1) // { // DPC_ObjectDetection_fovRangeCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.fovRange; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_FOV_RANGE, // &cfg, // sizeof (DPC_ObjectDetection_fovRangeCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isFovRangePending = 0; // } // if (subFrameCfg->isMultiObjBeamFormingCfgPending == 1) // { // DPC_ObjectDetection_MultiObjBeamFormingCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.multiObjBeamFormingCfg; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_MULTI_OBJ_BEAM_FORM_CFG, // &cfg, // sizeof (DPC_ObjectDetection_MultiObjBeamFormingCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isMultiObjBeamFormingCfgPending = 0; // } // if (subFrameCfg->isPrepareRangeAzimuthHeatMapPending == 1) // { // DPC_ObjectDetection_RangeAzimuthHeatMapCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.prepareRangeAzimuthHeatMap = subFrameCfg->dynCfg.prepareRangeAzimuthHeatMap; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_RANGE_AZIMUTH_HEAT_MAP, // &cfg, // sizeof (DPC_ObjectDetection_RangeAzimuthHeatMapCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isPrepareRangeAzimuthHeatMapPending = 0; // } // if (subFrameCfg->isStaticClutterRemovalCfgPending == 1) // { // DPC_ObjectDetection_StaticClutterRemovalCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.staticClutterRemovalCfg; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_STATICCLUTTER_REMOVAL_CFG, // &cfg, // sizeof (DPC_ObjectDetection_StaticClutterRemovalCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isStaticClutterRemovalCfgPending = 0; // } // if (subFrameCfg->isFovAoaCfgPending == 1) // { // DPC_ObjectDetection_fovAoaCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.fovAoaCfg; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_FOV_AOA, // &cfg, // sizeof (DPC_ObjectDetection_fovAoaCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isFovAoaCfgPending = 0; // } // if (subFrameCfg->isExtMaxVelCfgPending == 1) // { // DPC_ObjectDetection_extMaxVelCfg cfg; // cfg.subFrameNum = subFrameIndx; // cfg.cfg = subFrameCfg->dynCfg.extMaxVelCfg; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_EXT_MAX_VELOCITY, // &cfg, // sizeof (DPC_ObjectDetection_extMaxVelCfg)); // if (retVal != 0) // { // goto exit; // } // subFrameCfg->isExtMaxVelCfgPending = 0; // } // exit: // return(retVal); // } /** * @b Description * @n * Transmit user data over LVDS interface. * * @param[in] subFrameIndx Sub-frame index * @param[in] dpcResults pointer to DPC result * */ void MmwDemo_transferLVDSUserData(uint8_t subFrameIndx, DPC_ObjectDetection_ExecuteResult *dpcResults) { int32_t errCode; /* Delete previous SW session if it exists. SW session is being reconfigured every frame because number of detected objects may change from frame to frame which implies that the size of the streamed data may change. */ if(gMmwMCB.lvdsStream.swSessionHandle != NULL) { MmwDemo_LVDSStreamDeleteSwSession(); } /* Configure SW session for this subframe */ if (MmwDemo_LVDSStreamSwConfig(dpcResults->numObjOut, dpcResults->objOut, dpcResults->objOutSideInfo) < 0) { System_printf("Failed LVDS stream SW configuration for sub-frame %d\n", subFrameIndx); MmwDemo_debugAssert(0); return; } /* Populate user data header that will be streamed out*/ gMmwMCB.lvdsStream.userDataHeader.frameNum = dpcResults->stats->frameStartIntCounter; gMmwMCB.lvdsStream.userDataHeader.detObjNum = dpcResults->numObjOut; gMmwMCB.lvdsStream.userDataHeader.subFrameNum = (uint16_t) dpcResults->subFrameIdx; /* If SW LVDS stream is enabled, start the session here. User data will immediately start to stream over LVDS.*/ if(CBUFF_activateSession (gMmwMCB.lvdsStream.swSessionHandle, &errCode) < 0) { System_printf("Failed to activate CBUFF session for LVDS stream SW. errCode=%d\n",errCode); MmwDemo_debugAssert(0); return; } } /** * @b Description * @n * DPM Execution Task. DPM execute results are processed here: * a) Transmits results through UART port. * b) Updates book-keeping code for timing info. * c) Notifies DPC that results have been exported (using DPC IOCTL command) * * @retval * Not Applicable. */ static void MmwDemo_DPC_ObjectDetection_dpmTask(UArg arg0, UArg arg1) { int32_t retVal; DPM_Buffer resultBuffer; //DPC_ObjectDetection_ExecuteResultExportedInfo exportInfo; //DPC_ObjectDetection_ExecuteResult *result; DPIF_RadarCube *result; while (1) { /* Execute the DPM module: */ retVal = DPM_execute (gMmwMCB.dataPathObj.objDetDpmHandle, &resultBuffer); if (retVal < 0) { System_printf ("Error: DPM execution failed [Error code %d]\n", retVal); MmwDemo_debugAssert (0); } else { if (resultBuffer.size[0] == sizeof(DPIF_RadarCube)) { result = (DPIF_RadarCube *)resultBuffer.ptrBuffer[0]; CLI_write("%.7f\n",result->data); CLI_write("%.7f\n",result->dataSize); CLI_write("%.7f\n",result->datafmt); } } // else // { // if (resultBuffer.size[0] == sizeof(DPC_ObjectDetection_ExecuteResult)) // { // volatile uint32_t startTime, currentInterFrameProcessingEndTime; // MmwDemo_SubFrameStats *currSubFrameStats, *prevSubFrameStats; // uint16_t dummyRxChanOffset[SYS_COMMON_NUM_RX_CHANNEL]; // uint8_t numSubFrames; // uint8_t nextSubFrameIndx, prevSubFrameIndx, currSubFrameIndx; // result = (DPC_ObjectDetection_ExecuteResult *)resultBuffer.ptrBuffer[0]; // currSubFrameIndx = result->subFrameIdx; // currSubFrameStats = &gMmwMCB.subFrameStats[currSubFrameIndx]; // currentInterFrameProcessingEndTime = Cycleprofiler_getTimeStamp(); // currSubFrameStats->outputStats.interFrameProcessingTime = // (currentInterFrameProcessingEndTime - result->stats->interFrameStartTimeStamp)/R4F_CLOCK_MHZ; // numSubFrames = gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.numSubFrames; // /* Update the processing end margin, note this is of the previous sub-frame // * and should work even when there is only 1 sub-frame (or non-advanced mode) // * as long as end time stamp is updated after using it. Note that // * "result->stats->subFramePreparationCycles" is of the previous sub-frame's // * preparation for the next (which is the current here) because sub-frame // * preparation happens when DPC processes the results exported IOCTL which // * is issued after all the result handling here. However, we also store // * this after using for debug purposes (to be able to see all sub-frames switching cycles // * in real-time) // */ // prevSubFrameIndx = MmwDemo_getPrevSubFrameIndx(currSubFrameIndx, numSubFrames); // prevSubFrameStats = &gMmwMCB.subFrameStats[prevSubFrameIndx]; // prevSubFrameStats->outputStats.interFrameProcessingMargin = // (result->stats->frameStartTimeStamp - prevSubFrameStats->interFrameProcessingEndTime)/R4F_CLOCK_MHZ - // (result->stats->subFramePreparationCycles/R4F_CLOCK_MHZ + prevSubFrameStats->subFramePreparationTime) - // prevSubFrameStats->pendingConfigProcTime; // /* Below is only for debug purposes */ // prevSubFrameStats->objDetSubFramePreparationTime = result->stats->subFramePreparationCycles/R4F_CLOCK_MHZ; // /* This must be after above prevSubFrame processing */ // currSubFrameStats->interFrameProcessingEndTime = currentInterFrameProcessingEndTime; // startTime = Cycleprofiler_getTimeStamp(); // /* Send out of CLI the range bias and phase config measurement if it was enabled. */ // if (gMmwMCB.dataPathObj.objDetCommonCfg.preStartCommonCfg.measureRxChannelBiasCfg.enabled == 1) // { // if (result->compRxChanBiasMeasurement != NULL) // { // MmwDemo_measurementResultOutput(result->compRxChanBiasMeasurement); // } // else // { // /* DPC is not ready to ship the measurement results */ // } // } // if (gMmwMCB.subFrameCfg[currSubFrameIndx].lvdsStreamCfg.dataFmt != // MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_DISABLED) // { // /* check Edma errors (which are considered fatal) for the current sub-frame's // * h/w session that is expected to be completed by now */ // MmwDemo_checkEdmaErrors(MMW_LVDS_STREAM_EDMA_INSTANCE); // /* Pend for completion of h/w session, generally this will not wait // * because of time spent doing inter-frame processing is expected to // * be bigger than the transmission of the h/w session */ // Semaphore_pend(gMmwMCB.lvdsStream.hwFrameDoneSemHandle, BIOS_WAIT_FOREVER); // } // /* Transfer data on LVDS if s/w session is enabled for the current sub-frame */ // if(gMmwMCB.subFrameCfg[currSubFrameIndx].lvdsStreamCfg.isSwEnabled == 1) // { // MmwDemo_transferLVDSUserData(currSubFrameIndx, result); // } // MmwDemo_transmitProcessedOutput(gMmwMCB.loggingUartHandle, result, // &currSubFrameStats->outputStats); // /* Wait until s/w session is complete. We expect the LVDS transmission of // * s/w session to be completed by now because the UART transmission above is slower. // * Doing the wait immediately after starting the transmission above MmwDemo_transferLVDSUserData // * will serialize the LVDS and UART transfers so it is better to do after UART // * transmission (which is blocking call i.e UART transmission is completed when we exit // * out of above MmwDemo_transmitProcessedOutput). Note we cannot replace below code // * with check for previous sub-frame s/w session completion before the // * MmwDemo_transferLVDSUserData above because we need to ensure that // * current sub-frame/frame's contents are not being read during the // * next sub-frame/frame transmission, presently the data that is being // * transmitted is not double buffered to allow this */ // if(gMmwMCB.subFrameCfg[currSubFrameIndx].lvdsStreamCfg.isSwEnabled == 1) // { // /* check Edma errors (which are considered fatal) for the s/w session // * that is expected to be completed by now */ // MmwDemo_checkEdmaErrors(MMW_LVDS_STREAM_EDMA_INSTANCE); // /* Pend completion of s/w session, no wait is expected here */ // Semaphore_pend(gMmwMCB.lvdsStream.swFrameDoneSemHandle, BIOS_WAIT_FOREVER); // } // currSubFrameStats->outputStats.transmitOutputTime = // (Cycleprofiler_getTimeStamp() - startTime)/R4F_CLOCK_MHZ; // startTime = Cycleprofiler_getTimeStamp(); // /* For non-advanced frame case: // * process all pending dynamic config commands. // * For advanced-frame case: // * Process next sub-frame related pending dynamic config commands. // * If the next sub-frame was the first sub-frame of the frame, // * then process common (sub-frame independent) pending dynamic config // * commands. */ // nextSubFrameIndx = MmwDemo_getNextSubFrameIndx(currSubFrameIndx, // numSubFrames); // retVal = MmwDemo_processPendingDynamicCfgCommands(nextSubFrameIndx); // if (retVal != 0) // { // System_printf ("Error: Executing Pending Dynamic Configuration Commands for nextSubFrameIndx = %d [Error code %d]\n", // nextSubFrameIndx, retVal); // MmwDemo_debugAssert(0); // } // currSubFrameStats->pendingConfigProcTime = // (Cycleprofiler_getTimeStamp() - startTime)/R4F_CLOCK_MHZ; // /* Configure ADC for next sub-frame */ // if (numSubFrames > 1) // { // MmwDemo_SubFrameCfg *nextSubFrameCfg; // startTime = Cycleprofiler_getTimeStamp(); // nextSubFrameCfg = &gMmwMCB.subFrameCfg[nextSubFrameIndx]; // retVal = MmwDemo_ADCBufConfig(gMmwMCB.dataPathObj.adcbufHandle, // gMmwMCB.cfg.openCfg.chCfg.rxChannelEn, // nextSubFrameCfg->numChirpsPerChirpEvent, // nextSubFrameCfg->adcBufChanDataSize, // &nextSubFrameCfg->adcBufCfg, // &dummyRxChanOffset[0]); // if (retVal < 0) // { // System_printf("Error: ADCBuf config failed with error [%d]\n", retVal); // MmwDemo_debugAssert (0); // } // /* Configure HW LVDS stream for this subframe? */ // if(nextSubFrameCfg->lvdsStreamCfg.dataFmt != MMW_DEMO_LVDS_STREAM_CFG_DATAFMT_DISABLED) // { // /* check Edma errors (which are considered fatal) for any previous session, even // * though we have checked for a previous s/w session, if s/w session weren't // * enabled, then this will check for previous h/w session related Edma errors */ // MmwDemo_checkEdmaErrors(MMW_LVDS_STREAM_EDMA_INSTANCE); // MmwDemo_configLVDSHwData(nextSubFrameIndx); // } // currSubFrameStats->subFramePreparationTime = // (Cycleprofiler_getTimeStamp() - startTime)/R4F_CLOCK_MHZ; // } // else // { // currSubFrameStats->subFramePreparationTime = 0; // } // // /* indicate result consumed and end of frame/sub-frame processing */ // exportInfo.subFrameIdx = currSubFrameIndx; // retVal = DPM_ioctl (gMmwMCB.dataPathObj.objDetDpmHandle, // DPC_OBJDET_IOCTL__DYNAMIC_EXECUTE_RESULT_EXPORTED, // &exportInfo, // sizeof (DPC_ObjectDetection_ExecuteResultExportedInfo)); // if (retVal < 0) { // System_printf ("Error: DPM DPC_OBJDET_IOCTL__DYNAMIC_EXECUTE_RESULT_EXPORTED failed [Error code %d]\n", // retVal); // MmwDemo_debugAssert(0); // } // } // } } } /** * @b Description * @n * Call back function that was registered during config time and is going * to be called in DPC processing at the beginning of frame/sub-frame processing, * we use this to issue BIOS calls for computing CPU load during inter-frame * * @param[in] subFrameIndx Sub-frame index of the sub-frame during which processing * this function was called. * * @retval None */ void MmwDemo_DPC_ObjectDetection_processFrameBeginCallBackFxn(uint8_t subFrameIndx) { MmwDemo_SubFrameStats *stats; stats = &gMmwMCB.subFrameStats[subFrameIndx]; Load_update(); stats->outputStats.interFrameCPULoad = Load_getCPULoad(); } /** * @b Description * @n * Call back function that was registered during config time and is going * to be called in DPC processing at the beginning of * inter-frame/inter-sub-frame processing, * we use this to issue BIOS calls for computing CPU load during active frame * (chirping) * * @param[in] subFrameIndx Sub-frame index of the sub-frame during which processing * this function was called. * * @retval None */ void MmwDemo_DPC_ObjectDetection_processInterFrameBeginCallBackFxn(uint8_t subFrameIndx) { MmwDemo_SubFrameStats *stats; stats = &gMmwMCB.subFrameStats[subFrameIndx]; Load_update(); stats->outputStats.activeFrameCPULoad = Load_getCPULoad(); } /** * @b Description * @n * Platform specific hardware initialization. * * @retval * Not Applicable. */ void MmwDemo_platformInit(MmwDemo_platformCfg *config) { /* Setup the PINMUX to bring out the UART-1 */ Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINN5_PADBE, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINN5_PADBE, SOC_XWR68XX_PINN5_PADBE_MSS_UARTA_TX); Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINN4_PADBD, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINN4_PADBD, SOC_XWR68XX_PINN4_PADBD_MSS_UARTA_RX); /* Setup the PINMUX to bring out the UART-3 */ Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINF14_PADAJ, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINF14_PADAJ, SOC_XWR68XX_PINF14_PADAJ_MSS_UARTB_TX); /********************************************************************** * Setup the PINMUX: * - GPIO Output: Configure pin K13 as GPIO_2 output **********************************************************************/ Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINK13_PADAZ, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINK13_PADAZ, SOC_XWR68XX_PINK13_PADAZ_GPIO_2); /********************************************************************** * Setup the PINMUX: * - for QSPI Flash **********************************************************************/ Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINR12_PADAP, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINR12_PADAP, SOC_XWR68XX_PINR12_PADAP_QSPI_CLK); Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINP11_PADAQ, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINP11_PADAQ, SOC_XWR68XX_PINP11_PADAQ_QSPI_CSN); Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINR13_PADAL, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINR13_PADAL, SOC_XWR68XX_PINR13_PADAL_QSPI_D0); Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINN12_PADAM, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINN12_PADAM, SOC_XWR68XX_PINN12_PADAM_QSPI_D1); Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINR14_PADAN, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINR14_PADAN, SOC_XWR68XX_PINR14_PADAN_QSPI_D2); Pinmux_Set_OverrideCtrl(SOC_XWR68XX_PINP12_PADAO, PINMUX_OUTEN_RETAIN_HW_CTRL, PINMUX_INPEN_RETAIN_HW_CTRL); Pinmux_Set_FuncSel(SOC_XWR68XX_PINP12_PADAO, SOC_XWR68XX_PINP12_PADAO_QSPI_D3); /********************************************************************** * Setup the GPIO: * - GPIO Output: Configure pin K13 as GPIO_2 output **********************************************************************/ config->SensorStatusGPIO = SOC_XWR68XX_GPIO_2; /* Initialize the DEMO configuration: */ config->sysClockFrequency = MSS_SYS_VCLK; config->loggingBaudRate = 921600; config->commandBaudRate = 115200; /********************************************************************** * Setup the DS3 LED on the EVM connected to GPIO_2 **********************************************************************/ GPIO_setConfig (config->SensorStatusGPIO, GPIO_CFG_OUTPUT); } /** * @b Description * @n * Calibration save/restore initialization * * @retval * Success - 0 * @retval * Error - <0 */ static int32_t MmwDemo_calibInit(void) { int32_t retVal = 0; rlVersion_t verArgs; /* Initialize verArgs */ memset((void *)&verArgs, 0, sizeof(rlVersion_t)); /* Get the version string: */ retVal = rlDeviceGetVersion(RL_DEVICE_MAP_INTERNAL_BSS, &verArgs); if (retVal < 0) { System_printf ("Error: Unable to get the device version from mmWave link [Error %d]\n", retVal); return -1; } /* Calibration save/restore init */ gMmwMCB.calibCfg.sizeOfCalibDataStorage = sizeof(MmwDemo_calibData); gMmwMCB.calibCfg.calibDataHdr.magic = MMWDEMO_CALIB_STORE_MAGIC; memcpy((void *)& gMmwMCB.calibCfg.calibDataHdr.linkVer, (void *)&verArgs.mmWaveLink, sizeof(rlSwVersionParam_t)); memcpy((void *)& gMmwMCB.calibCfg.calibDataHdr.radarSSVer, (void *)&verArgs.rf, sizeof(rlFwVersionParam_t)); /* Check if Calibration data is over the Reserved storage */ if(gMmwMCB.calibCfg.sizeOfCalibDataStorage <= MMWDEMO_CALIB_FLASH_SIZE) { gMmwMCB.calibCfg.calibDataHdr.hdrLen = sizeof(MmwDemo_calibDataHeader); gMmwMCB.calibCfg.calibDataHdr.dataLen= sizeof(MmwDemo_calibData) - sizeof(MmwDemo_calibDataHeader); /* Resets calibration data */ memset((void *)&gCalibDataStorage, 0, sizeof(MmwDemo_calibData)); retVal = mmwDemo_flashInit(); } else { System_printf ("Error: Calibration data size is bigger than reserved size\n"); retVal = -1; } return retVal; } /** * @b Description * @n * This function retrieves the calibration data from front end and saves it in flash. * * @param[in] ptrCalibDataHdr Pointer to Calibration data header * @param[in] ptrCalibrationData Pointer to Calibration data * * @retval * Success - 0 * @retval * Error - <0 */ static int32_t MmwDemo_calibSave(MmwDemo_calibDataHeader *ptrCalibDataHdr, MmwDemo_calibData *ptrCalibrationData) { uint32_t flashOffset; int32_t retVal = 0; /* Calculate the read size in bytes */ flashOffset = gMmwMCB.calibCfg.flashOffset; /* Copy header */ memcpy((void *)&(ptrCalibrationData->calibDataHdr), ptrCalibDataHdr, sizeof(MmwDemo_calibDataHeader)); /* Flash calibration data */ retVal = mmwDemo_flashWrite(flashOffset, (uint32_t *)ptrCalibrationData, sizeof(MmwDemo_calibData)); if(retVal < 0) { /* Flash Header failed */ System_printf ("Error: MmwDemo failed flashing calibration data with error[%d].\n", retVal); } return(retVal); } /** * @b Description * @n * This function reads calibration data from flash and send it to front end through MMWave_open() * * @param[in] ptrCalibData Pointer to Calibration data * * @retval * Success - 0 * @retval * Error - <0 */ static int32_t MmwDemo_calibRestore(MmwDemo_calibData *ptrCalibData) { MmwDemo_calibDataHeader *pDataHdr; int32_t retVal = 0; uint32_t flashOffset; pDataHdr = &(ptrCalibData->calibDataHdr); /* Calculate the read size in bytes */ flashOffset = gMmwMCB.calibCfg.flashOffset; /* Read calibration data header */ if(mmwDemo_flashRead(flashOffset, (uint32_t *)pDataHdr, sizeof(MmwDemo_calibData) )< 0) { /* Error: only one can be enable at at time */ System_printf ("Error: MmwDemo failed when reading calibration data from flash.\n"); return -1; } /* Validate data header */ if( (pDataHdr->magic != MMWDEMO_CALIB_STORE_MAGIC) || (pDataHdr->hdrLen != gMmwMCB.calibCfg.calibDataHdr.hdrLen) || (pDataHdr->dataLen != gMmwMCB.calibCfg.calibDataHdr.dataLen) ) { /* Header validation failed */ System_printf ("Error: MmwDemo calibration data header validation failed.\n"); retVal = -1; } /* Matching mmwLink version: In this demo, we would like to save/restore with the matching mmwLink and RF FW version. However, this logic can be changed to use data saved from previous mmwLink and FW releases, as long as the data format of the calibration data matches. */ else if(memcmp((void *)&pDataHdr->linkVer, (void *)&gMmwMCB.calibCfg.calibDataHdr.linkVer, sizeof(rlSwVersionParam_t)) != 0) { System_printf ("Error: MmwDemo failed mmwLink version validation when restoring calibration data.\n"); retVal = -1; } else if(memcmp((void *)&pDataHdr->radarSSVer, (void *)&gMmwMCB.calibCfg.calibDataHdr.radarSSVer, sizeof(rlFwVersionParam_t)) != 0) { System_printf ("Error: MmwDemo failed RF FW version validation when restoring calibration data.\n"); retVal = -1; } return(retVal); } /** * @b Description * @n * System Initialization Task which initializes the various * components in the system. * * @retval * Not Applicable. */ void MmwDemo_initTask(UArg arg0, UArg arg1) { int32_t errCode; MMWave_InitCfg initCfg; UART_Params uartParams; Task_Params taskParams; Semaphore_Params semParams; DPM_InitCfg dpmInitCfg; DPC_ObjectDetection_InitParams objDetInitParams; uint32_t edmaCCIdx; int32_t i; //int32_t retVal; /* Debug Message: */ System_printf("Debug: Launched the Initialization Task\n"); /***************************************************************************** * Initialize the mmWave SDK components: *****************************************************************************/ /* Initialize the UART */ UART_init(); /* Initialize the GPIO */ GPIO_init(); /* Initialize the Mailbox */ Mailbox_init(MAILBOX_TYPE_MSS); /* Platform specific configuration */ MmwDemo_platformInit(&gMmwMCB.cfg.platformCfg); /* Initialize the Data Path: */ MmwDemo_dataPathInit(&gMmwMCB.dataPathObj); /* Setup the default UART Parameters */ UART_Params_init(&uartParams); uartParams.clockFrequency = gMmwMCB.cfg.platformCfg.sysClockFrequency; uartParams.baudRate = gMmwMCB.cfg.platformCfg.commandBaudRate; uartParams.isPinMuxDone = 1; /* Open the UART Instance */ gMmwMCB.commandUartHandle = UART_open(0, &uartParams); if (gMmwMCB.commandUartHandle == NULL) { //System_printf("Error: Unable to open the Command UART Instance\n"); MmwDemo_debugAssert (0); return; } System_printf("Debug: UART Instance %p has been opened successfully\n", gMmwMCB.commandUartHandle); /* Setup the default UART Parameters */ UART_Params_init(&uartParams); uartParams.writeDataMode = UART_DATA_BINARY; uartParams.readDataMode = UART_DATA_BINARY; uartParams.clockFrequency = gMmwMCB.cfg.platformCfg.sysClockFrequency; uartParams.baudRate = gMmwMCB.cfg.platformCfg.loggingBaudRate; uartParams.isPinMuxDone = 1U; /* Open the Logging UART Instance: */ gMmwMCB.loggingUartHandle = UART_open(1, &uartParams); if (gMmwMCB.loggingUartHandle == NULL) { //System_printf("Error: Unable to open the Logging UART Instance\n"); MmwDemo_debugAssert (0); return; } System_printf("Debug: UART Instance %p has been opened successfully\n", gMmwMCB.loggingUartHandle); /* Create a binary semaphores which are used to signal DPM_start/DPM_stop are done. * The signaling (Semaphore_post) will be done from DPM registered report function * (which will execute in the DPM execute task context). */ Semaphore_Params_init(&semParams); semParams.mode = Semaphore_Mode_BINARY; gMmwMCB.DPMstartSemHandle = Semaphore_create(0, &semParams, NULL); gMmwMCB.DPMstopSemHandle = Semaphore_create(0, &semParams, NULL); /***************************************************************************** * mmWave: Initialization of the high level module *****************************************************************************/ /* Initialize the mmWave control init configuration */ memset ((void*)&initCfg, 0 , sizeof(MMWave_InitCfg)); /* Populate the init configuration: */ initCfg.domain = MMWave_Domain_MSS; initCfg.socHandle = gMmwMCB.socHandle; initCfg.eventFxn = MmwDemo_eventCallbackFxn; initCfg.linkCRCCfg.useCRCDriver = 1U; initCfg.linkCRCCfg.crcChannel = CRC_Channel_CH1; initCfg.cfgMode = MMWave_ConfigurationMode_FULL; initCfg.executionMode = MMWave_ExecutionMode_ISOLATION; /* Initialize and setup the mmWave Control module */ gMmwMCB.ctrlHandle = MMWave_init (&initCfg, &errCode); if (gMmwMCB.ctrlHandle == NULL) { /* Error: Unable to initialize the mmWave control module */ //System_printf ("Error: mmWave Control Initialization failed [Error code %d]\n", errCode); MmwDemo_debugAssert (0); return; } System_printf ("Debug: mmWave Control Initialization was successful\n"); /* Synchronization: This will synchronize the execution of the control module * between the domains. This is a prerequisite and always needs to be invoked. */ if (MMWave_sync (gMmwMCB.ctrlHandle, &errCode) < 0) { /* Error: Unable to synchronize the mmWave control module */ System_printf ("Error: mmWave Control Synchronization failed [Error code %d]\n", errCode); MmwDemo_debugAssert (0); return; } System_printf ("Debug: mmWave Control Synchronization was successful\n"); MmwDemo_dataPathOpen(&gMmwMCB.dataPathObj); /* Initialize LVDS streaming components */ if ((errCode = MmwDemo_LVDSStreamInit()) < 0 ) { System_printf ("Error: MMWDemoDSS LVDS stream init failed with Error[%d]\n",errCode); return; } /* initialize cq configs to invalid profile index to be able to detect * unconfigured state of these when monitors for them are enabled. */ for(i = 0; i < RL_MAX_PROFILES_CNT; i++) { gMmwMCB.cqSatMonCfg[i].profileIndx = (RL_MAX_PROFILES_CNT + 1); gMmwMCB.cqSigImgMonCfg[i].profileIndx = (RL_MAX_PROFILES_CNT + 1); } /* Configure banchmark counter */ Cycleprofiler_init(); /***************************************************************************** * Launch the mmWave control execution task * - This should have a higher priroity than any other task which uses the * mmWave control API *****************************************************************************/ Task_Params_init(&taskParams); taskParams.priority = MMWDEMO_MMWAVE_CTRL_TASK_PRIORITY; taskParams.stackSize = 3*1024; gMmwMCB.taskHandles.mmwaveCtrl = Task_create(MmwDemo_mmWaveCtrlTask, &taskParams, NULL); /***************************************************************************** * Initialization of the DPM Module: *****************************************************************************/ memset ((void *)&objDetInitParams, 0, sizeof(DPC_ObjectDetection_InitParams)); /* Note this must be after MmwDemo_dataPathOpen() above which opens the hwa * and edma drivers */ objDetInitParams.hwaHandle = gMmwMCB.dataPathObj.hwaHandle; for (edmaCCIdx = 0; edmaCCIdx < EDMA_NUM_CC; edmaCCIdx++) { objDetInitParams.edmaHandle[edmaCCIdx] = gMmwMCB.dataPathObj.edmaHandle[edmaCCIdx]; } /* Memory related config */ objDetInitParams.L3ramCfg.addr = (void *)&gMmwL3[0]; objDetInitParams.L3ramCfg.size = sizeof(gMmwL3); objDetInitParams.CoreLocalRamCfg.addr = &gDPC_ObjDetTCM[0]; objDetInitParams.CoreLocalRamCfg.size = sizeof(gDPC_ObjDetTCM); /* Call-back config */ objDetInitParams.processCallBackCfg.processFrameBeginCallBackFxn = MmwDemo_DPC_ObjectDetection_processFrameBeginCallBackFxn; objDetInitParams.processCallBackCfg.processInterFrameBeginCallBackFxn = MmwDemo_DPC_ObjectDetection_processInterFrameBeginCallBackFxn; memset ((void *)&dpmInitCfg, 0, sizeof(DPM_InitCfg)); /* Setup the configuration: */ dpmInitCfg.socHandle = gMmwMCB.socHandle; //dpmInitCfg.ptrProcChainCfg = &gDPC_ObjectDetectionCfg; dpmInitCfg.ptrProcChainCfg = &gDPC_ObjDetRangeHWACfg; dpmInitCfg.instanceId = 0xFEEDFEED; dpmInitCfg.domain = DPM_Domain_LOCALIZED; dpmInitCfg.reportFxn = MmwDemo_DPC_ObjectDetection_reportFxn; dpmInitCfg.arg = &objDetInitParams; dpmInitCfg.argSize = sizeof(DPC_ObjectDetectionRangeHWA_InitParams); /* Initialize the DPM Module: */ gMmwMCB.dataPathObj.objDetDpmHandle = DPM_init (&dpmInitCfg, &errCode); if (gMmwMCB.dataPathObj.objDetDpmHandle == NULL) { System_printf ("Error: Unable to initialize the DPM Module [Error: %d]\n", errCode); MmwDemo_debugAssert (0); return; } /* Launch the DPM Task */ Task_Params_init(&taskParams); taskParams.priority = MMWDEMO_DPC_OBJDET_DPM_TASK_PRIORITY; taskParams.stackSize = 4*1024; gMmwMCB.taskHandles.objDetDpmTask = Task_create(MmwDemo_DPC_ObjectDetection_dpmTask, &taskParams, NULL); /* Calibration save/restore initialization */ if(MmwDemo_calibInit()<0) { System_printf("Error: Calibration data initialization failed \n"); MmwDemo_debugAssert (0); } /***************************************************************************** * Initialize the CLI Module: * User can choose to create their own task here with the same priority * instead that does hard coded config instead of interactive CLI *****************************************************************************/ MmwDemo_CLIInit(MMWDEMO_CLI_TASK_PRIORITY); return; } /** * @b Description * @n * Function to sleep the R4F using WFI (Wait For Interrupt) instruction. * When R4F has no work left to do, * the BIOS will be in Idle thread and will call this function. The R4F will * wake-up on any interrupt (e.g chirp interrupt). * * @retval * Not Applicable. */ void MmwDemo_sleep(void) { /* issue WFI (Wait For Interrupt) instruction */ asm(" WFI "); } /** * @b Description * @n * Entry point into the Millimeter Wave Demo * * @retval * Not Applicable. */ int main (void) { Task_Params taskParams; int32_t errCode; SOC_Handle socHandle; SOC_Cfg socCfg; /* Initialize the ESM: Dont clear errors as TI RTOS does it */ ESM_init(0U); /* Initialize the SOC confiugration: */ memset ((void *)&socCfg, 0, sizeof(SOC_Cfg)); /* Populate the SOC configuration: */ socCfg.clockCfg = SOC_SysClock_INIT; socCfg.dssCfg = SOC_DSSCfg_HALT; socCfg.mpuCfg = SOC_MPUCfg_CONFIG; /* Initialize the SOC Module: This is done as soon as the application is started * to ensure that the MPU is correctly configured. */ socHandle = SOC_init (&socCfg, &errCode); if (socHandle == NULL) { //System_printf ("Error: SOC Module Initialization failed [Error code %d]\n", errCode); MmwDemo_debugAssert (0); return -1; } /* Wait for BSS powerup */ if (SOC_waitBSSPowerUp(socHandle, &errCode) < 0) { /* Debug Message: */ System_printf ("Debug: SOC_waitBSSPowerUp failed with Error [%d]\n", errCode); return 0; } /* Check if the SOC is a secure device */ if (SOC_isSecureDevice(socHandle, &errCode)) { /* Disable firewall for JTAG and LOGGER (UART) which is needed by all unit tests */ SOC_controlSecureFirewall(socHandle, (uint32_t)(SOC_SECURE_FIREWALL_JTAG | SOC_SECURE_FIREWALL_LOGGER), SOC_SECURE_FIREWALL_DISABLE, &errCode); } /* Initialize and populate the demo MCB */ memset ((void*)&gMmwMCB, 0, sizeof(MmwDemo_MCB)); gMmwMCB.socHandle = socHandle; /* Debug Message: */ System_printf ("**********************************************\n"); System_printf ("Debug: Launching the MMW HWA Demo\n"); System_printf ("**********************************************\n"); /* Initialize the Task Parameters. */ Task_Params_init(&taskParams); gMmwMCB.taskHandles.initTask = Task_create(MmwDemo_initTask, &taskParams, NULL); /* Start BIOS */ BIOS_start(); return 0; }
objdetrangehwa.c
/*
* @file objdetrangehwa.c
*
* @brief
* Object Detection DPC implementation with range HWA DPU only
*
* \par
* NOTE:
* (C) Copyright 2019 Texas Instruments, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of Texas Instruments Incorporated 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 <stdint.h>
#include <string.h>
#include <stdio.h>
#define DBG_DPC_OBJDETRANGEHWA
/* mmWave SDK Include Files: */
#include <ti/drivers/soc/soc.h>
#include <ti/common/sys_common.h>
#include <ti/drivers/osal/DebugP.h>
#include <ti/drivers/osal/MemoryP.h>
#include <ti/drivers/edma/edma.h>
#include <ti/utils/mathutils/mathutils.h>
#include <ti/utils/cycleprofiler/cycle_profiler.h>
#include <ti/control/dpm/dpm.h>
/* DPUs */
#include <ti/datapath/dpu/rangeproc/rangeprochwa.h>
/** @addtogroup DPC_OBJDETRANGEHWA_IOCTL__INTERNAL_DEFINITIONS
@{ */
/*! This is supplied at command line when application builds this file. This file
* is owned by the application and contains all resource partitioning, an
* application may include more than one DPC and also use resources outside of DPCs.
* The resource definitions used by this object detection DPC are prefixed by DPC_OBJDETRANGEHWA */
#include APP_RESOURCE_FILE
/* Obj Det instance etc */
#include <ti/datapath/dpc/objectdetection/objdetrangehwa/include/objdetrangehwainternal.h>
#include <ti/datapath/dpc/objectdetection/objdetrangehwa/objdetrangehwa.h>
#ifdef DBG_DPC_OBJDETRANGEHWA
ObjDetObj *gObjDetObj;
#endif
/*! Radar cube data buffer alignment in bytes. No DPU module specifying alignment
* need (through a \#define) implies that no alignment is needed i.e 1 byte alignment.
* But we do the natural data type alignment which is 2 bytes (as radar cube is complex16-bit type)
* because radar cube is exported out of DPC in processing result so assume CPU may access
* it for post-DPC processing.
*/
#define DPC_OBJDETRANGEHWA_RADAR_CUBE_DATABUF_BYTE_ALIGNMENT (sizeof(int16_t))
/**
@}
*/
#define DPC_OBJDETRANGEHWA_HWA_MAX_WINDOW_RAM_SIZE_IN_SAMPLES SOC_HWA_WINDOW_RAM_SIZE_IN_SAMPLES
/******************************************************************************/
/* Local definitions */
#define DPC_USE_SYMMETRIC_WINDOW_RANGE_DPU
#define DPC_DPU_RANGEPROC_FFT_WINDOW_TYPE MATHUTILS_WIN_BLACKMAN
#define DPC_OBJDET_QFORMAT_RANGE_FFT 17
/**************************************************************************
************************** Local Functions *******************************
**************************************************************************/
static DPM_DPCHandle DPC_ObjectDetection_init
(
DPM_Handle dpmHandle,
DPM_InitCfg* ptrInitCfg,
int32_t* errCode
);
static int32_t DPC_ObjectDetection_execute
(
DPM_DPCHandle handle,
DPM_Buffer* ptrResult
);
static int32_t DPC_ObjectDetection_ioctl
(
DPM_DPCHandle handle,
uint32_t cmd,
void* arg,
uint32_t argLen
);
static int32_t DPC_ObjectDetection_start (DPM_DPCHandle handle);
static int32_t DPC_ObjectDetection_stop (DPM_DPCHandle handle);
static int32_t DPC_ObjectDetection_deinit (DPM_DPCHandle handle);
static void DPC_ObjectDetection_frameStart (DPM_DPCHandle handle);
/**************************************************************************
************************* Global Declarations ****************************
**************************************************************************/
/** @addtogroup DPC_OBJDETRANGEHWA__GLOBAL
@{ */
/**
* @brief Global used to register Object Detection DPC in DPM
*/
DPM_ProcChainCfg gDPC_ObjDetRangeHWACfg =
{
DPC_ObjectDetection_init, /* Initialization Function: */
DPC_ObjectDetection_start, /* Start Function: */
DPC_ObjectDetection_execute, /* Execute Function: */
DPC_ObjectDetection_ioctl, /* Configuration Function: */
DPC_ObjectDetection_stop, /* Stop Function: */
DPC_ObjectDetection_deinit, /* Deinitialization Function: */
NULL, /* Inject Data Function: */
NULL, /* Chirp Available Function: */
DPC_ObjectDetection_frameStart /* Frame Start Function: */
};
/* @} */
/**
* @b Description
* @n
* Utility function for reseting memory pool.
*
* @param[in] pool Handle to pool object.
*
* \ingroup DPC_OBJDETRANGEHWA_INTERNAL_FUNCTION
*
* @retval
* none.
*/
static void DPC_ObjDetRangeHwa_MemPoolReset(MemPoolObj *pool)
{
pool->currAddr = (uintptr_t)pool->cfg.addr;
pool->maxCurrAddr = pool->currAddr;
}
/**
* @b Description
* @n
* Utility function for getting maximum memory pool usage.
*
* @param[in] pool Handle to pool object.
*
* \ingroup DPC_OBJDETRANGEHWA_INTERNAL_FUNCTION
*
* @retval
* Amount of pool used in bytes.
*/
static uint32_t DPC_ObjDetRangeHwa_MemPoolGetMaxUsage(MemPoolObj *pool)
{
return((uint32_t)(pool->maxCurrAddr - (uintptr_t)pool->cfg.addr));
}
/**
* @b Description
* @n
* Utility function for allocating from a static memory pool.
*
* @param[in] pool Handle to pool object.
* @param[in] size Size in bytes to be allocated.
* @param[in] align Alignment in bytes
*
* \ingroup DPC_OBJDETRANGEHWA_INTERNAL_FUNCTION
*
* @retval
* pointer to beginning of allocated block. NULL indicates could not
* allocate.
*/
static void *DPC_ObjDetRangeHwa_MemPoolAlloc(MemPoolObj *pool,
uint32_t size,
uint8_t align)
{
void *retAddr = NULL;
uintptr_t addr;
addr = MEM_ALIGN(pool->currAddr, align);
if ((addr + size) <= ((uintptr_t)pool->cfg.addr + pool->cfg.size))
{
retAddr = (void *)addr;
pool->currAddr = addr + size;
pool->maxCurrAddr = MAX(pool->currAddr, pool->maxCurrAddr);
}
return(retAddr);
}
/**
* @b Description
* @n
* Sends Assert
*
* @retval
* Not Applicable.
*/
void _DPC_Objdet_Assert(DPM_Handle handle, int32_t expression,
const char *file, int32_t line)
{
DPM_DPCAssert fault;
if (!expression)
{
fault.lineNum = (uint32_t)line;
fault.arg0 = 0U;
fault.arg1 = 0U;
strncpy (fault.fileName, file, (DPM_MAX_FILE_NAME_LEN-1));
/* Report the fault to the DPM entities */
DPM_ioctl (handle,
DPM_CMD_DPC_ASSERT,
(void*)&fault,
sizeof(DPM_DPCAssert));
}
}
/**
* @b Description
* @n
* Computes the length of window to generate for range DPU.
*
* @param[in] numAdcSamples Number of ADC samples
*
* @retval Length of window to generate
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*/
static uint32_t DPC_ObjDetRangeHwa_GetRangeWinGenLen(uint16_t numAdcSamples)
{
uint32_t winGenLen;
#ifdef DPC_USE_SYMMETRIC_WINDOW_RANGE_DPU
winGenLen = (numAdcSamples + 1)/2;
#else
winGenLen = numAdcSamples;
#endif
return(winGenLen);
}
/**
* @b Description
* @n
* Generate the range DPU window using mathutils API.
*
* @param[in] cfg Range DPU configuration, output window is generated in window
* pointer in the staticCfg of this.
*
* @retval None
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*/
static void DPC_ObjDetRangeHwa_GenRangeWindow(DPU_RangeProcHWA_Config *cfg)
{
mathUtils_genWindow((uint32_t *)cfg->staticCfg.window,
cfg->staticCfg.ADCBufData.dataProperty.numAdcSamples,
DPC_ObjDetRangeHwa_GetRangeWinGenLen(cfg->staticCfg.ADCBufData.dataProperty.numAdcSamples),
DPC_DPU_RANGEPROC_FFT_WINDOW_TYPE,
DPC_OBJDET_QFORMAT_RANGE_FFT);
}
/**
* @b Description
* @n
* Sub-frame reconfiguration, used when switching sub-frames. Invokes the
* DPU configuration using the configuration that was stored during the
* pre-start configuration so reconstruction time is saved because this will
* happen in real-time.
* @param[in] objDetObj Pointer to DPC object
* @param[in] subFrameIndx Sub-frame index.
*
* @retval
* Success - 0
* @retval
* Error - <0
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*/
static int32_t DPC_ObjDetRangeHwa_reconfigSubFrame(ObjDetObj *objDetObj, uint8_t subFrameIndx)
{
int32_t retVal = 0;
SubFrameObj *subFrmObj;
subFrmObj = &objDetObj->subFrameObj[subFrameIndx];
if(objDetObj->commonCfg.numSubFrames > 1)
{
DPC_ObjDetRangeHwa_GenRangeWindow(&subFrmObj->rangeCfg);
retVal = DPU_RangeProcHWA_config(subFrmObj->dpuRangeObj, &subFrmObj->rangeCfg);
if (retVal != 0)
{
goto exit;
}
}
exit:
return(retVal);
}
/**
* @b Description
* @n
* Configure range DPU.
*
* @param[in] dpuHandle Handle to DPU
* @param[in] staticCfg Pointer to static configuration of the sub-frame
* @param[in] dynCfg Pointer to dynamic configuration of the sub-frame
* @param[in] edmaHandle Handle to edma driver to be used for the DPU
* @param[in] radarCube Pointer to DPIF radar cube, which is output of range
* processing.
* @param[in] CoreLocalRamObj Pointer to core local RAM object to allocate local memory
* for the DPU, only for scratch purposes
* @param[out] cfgSave Configuration that is built in local
* (stack) variable is saved here. This is for facilitating
* quick reconfiguration later without having to go through
* the construction of the configuration.
*
* @retval
* Success - 0
* @retval
* Error - <0
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*/
static int32_t DPC_ObjDetRangeHwa_rangeConfig
(
DPU_RangeProcHWA_Handle dpuHandle,
DPC_ObjectDetectionRangeHWA_StaticCfg *staticCfg,
DPC_ObjectDetectionRangeHWA_DynCfg *dynCfg,
EDMA_Handle edmaHandle,
DPIF_RadarCube *radarCube,
MemPoolObj *CoreLocalRamObj,
DPU_RangeProcHWA_Config *cfgSave
)
{
int32_t retVal = 0;
DPU_RangeProcHWA_Config rangeCfg;
DPU_RangeProcHWA_HW_Resources *hwRes = &rangeCfg.hwRes;
DPU_RangeProcHWA_EDMAInputConfig *edmaIn = &hwRes->edmaInCfg;
DPU_RangeProcHWA_EDMAOutputConfig *edmaOut = &hwRes->edmaOutCfg;
DPU_RangeProcHWA_HwaConfig *hwaCfg = &hwRes->hwaCfg;
uint32_t numRxAntennas, winGenLen;
memset(&rangeCfg, 0, sizeof(rangeCfg));
numRxAntennas = staticCfg->ADCBufData.dataProperty.numRxAntennas;
/* Even though Range DPU supports both modes,
* object detection DPC only supports non-interleaved at present */
DebugP_assert(staticCfg->ADCBufData.dataProperty.interleave == DPIF_RXCHAN_NON_INTERLEAVE_MODE);
/* dynamic configuration */
rangeCfg.dynCfg.calibDcRangeSigCfg = &dynCfg->calibDcRangeSigCfg;
/* static configuration */
rangeCfg.staticCfg.ADCBufData = staticCfg->ADCBufData;
rangeCfg.staticCfg.numChirpsPerFrame = staticCfg->numChirpsPerFrame;
rangeCfg.staticCfg.numRangeBins = staticCfg->numRangeBins;
rangeCfg.staticCfg.numTxAntennas = staticCfg->numTxAntennas;
rangeCfg.staticCfg.numVirtualAntennas = staticCfg->numVirtualAntennas;
rangeCfg.staticCfg.resetDcRangeSigMeanBuffer = 1;
rangeCfg.staticCfg.rangeFFTtuning.fftOutputDivShift = staticCfg->rangeFFTtuning.fftOutputDivShift;
rangeCfg.staticCfg.rangeFFTtuning.numLastButterflyStagesToScale = staticCfg->rangeFFTtuning.numLastButterflyStagesToScale;
/* radarCube */
rangeCfg.hwRes.radarCube = *radarCube;
/* static configuration - window */
/* Generating 1D window, allocate first */
winGenLen = DPC_ObjDetRangeHwa_GetRangeWinGenLen(rangeCfg.staticCfg.ADCBufData.dataProperty.numAdcSamples);
rangeCfg.staticCfg.windowSize = winGenLen * sizeof(uint32_t);
rangeCfg.staticCfg.window = (int32_t *)DPC_ObjDetRangeHwa_MemPoolAlloc(CoreLocalRamObj, rangeCfg.staticCfg.windowSize, sizeof(uint32_t));
if (rangeCfg.staticCfg.window == NULL)
{
retVal = DPC_OBJDETRANGEHWA_ENOMEM__CORE_LOCAL_RAM_RANGE_HWA_WINDOW;
goto exit;
}
DPC_ObjDetRangeHwa_GenRangeWindow(&rangeCfg);
/* hwres - dcRangeSig, allocate from heap, this needs to persist within sub-frame/frame
* processing and across sub-frames */
hwRes->dcRangeSigMeanSize = DPU_RANGEPROC_SIGNATURE_COMP_MAX_BIN_SIZE *
staticCfg->numTxAntennas * numRxAntennas * sizeof(cmplx32ImRe_t);
hwRes->dcRangeSigMean = (cmplx32ImRe_t *) MemoryP_ctrlAlloc (hwRes->dcRangeSigMeanSize,
(uint8_t) 0 /*sizeof(cmplx32ImRe_t)*/);
DebugP_assert(rangeCfg.hwRes.dcRangeSigMeanSize == hwRes->dcRangeSigMeanSize);
/* hwres - edma */
hwRes->edmaHandle = edmaHandle;
/* We have choosen ISOLATE mode, so we have to fill in dataIn */
edmaIn->dataIn.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAIN_CH;
edmaIn->dataIn.channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAIN_SHADOW;
edmaIn->dataIn.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAIN_EVENT_QUE;
edmaIn->dataInSignature.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAIN_SIG_CH;
edmaIn->dataInSignature.channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAIN_SIG_SHADOW;
edmaIn->dataInSignature.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAIN_SIG_EVENT_QUE;
/* We are radar Cube FORMAT1 and non-interleaved ADC, so for 3 tx antenna case, we have to
* fill format2, otherwise format1
*/
if ((staticCfg->numTxAntennas == 3) && (radarCube->datafmt == DPIF_RADARCUBE_FORMAT_1))
{
/* Ping */
/* Ping - dataOutPing */
edmaOut->u.fmt2.dataOutPing.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PING_CH;
edmaOut->u.fmt2.dataOutPing.channelShadow[0] = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PING_SHADOW_0;
edmaOut->u.fmt2.dataOutPing.channelShadow[1] = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PING_SHADOW_1;
edmaOut->u.fmt2.dataOutPing.channelShadow[2] = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PING_SHADOW_2;
edmaOut->u.fmt2.dataOutPing.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PING_EVENT_QUE;
/* Ping - dataOutPingData */
edmaOut->u.fmt2.dataOutPingData[0].channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_0_CH;
edmaOut->u.fmt2.dataOutPingData[0].channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_0_SHADOW;
edmaOut->u.fmt2.dataOutPingData[0].eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_0_EVENT_QUE;
edmaOut->u.fmt2.dataOutPingData[1].channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_1_CH;
edmaOut->u.fmt2.dataOutPingData[1].channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_1_SHADOW;
edmaOut->u.fmt2.dataOutPingData[1].eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_1_EVENT_QUE;
edmaOut->u.fmt2.dataOutPingData[2].channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_2_CH;
edmaOut->u.fmt2.dataOutPingData[2].channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_2_SHADOW;
edmaOut->u.fmt2.dataOutPingData[2].eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PINGDATA_2_EVENT_QUE;
/* Pong */
/* Pong - dataOutPong */
edmaOut->u.fmt2.dataOutPong.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONG_CH;
edmaOut->u.fmt2.dataOutPong.channelShadow[0] = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONG_SHADOW_0;
edmaOut->u.fmt2.dataOutPong.channelShadow[1] = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONG_SHADOW_1;
edmaOut->u.fmt2.dataOutPong.channelShadow[2] = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONG_SHADOW_2;
edmaOut->u.fmt2.dataOutPong.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONG_EVENT_QUE;
/* Pong - dataOutPongData */
edmaOut->u.fmt2.dataOutPongData[0].channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_0_CH;
edmaOut->u.fmt2.dataOutPongData[0].channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_0_SHADOW;
edmaOut->u.fmt2.dataOutPongData[0].eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_0_EVENT_QUE;
edmaOut->u.fmt2.dataOutPongData[1].channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_1_CH;
edmaOut->u.fmt2.dataOutPongData[1].channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_1_SHADOW;
edmaOut->u.fmt2.dataOutPongData[1].eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_1_EVENT_QUE;
edmaOut->u.fmt2.dataOutPongData[2].channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_2_CH;
edmaOut->u.fmt2.dataOutPongData[2].channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_2_SHADOW;
edmaOut->u.fmt2.dataOutPongData[2].eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT2_PONGDATA_2_EVENT_QUE;
}
else
{
/* Ping */
edmaOut->u.fmt1.dataOutPing.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT1_PING_CH;
edmaOut->u.fmt1.dataOutPing.channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT1_PING_SHADOW;
edmaOut->u.fmt1.dataOutPing.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT1_PING_EVENT_QUE;
/* Pong */
edmaOut->u.fmt1.dataOutPong.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT1_PONG_CH;
edmaOut->u.fmt1.dataOutPong.channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT1_PONG_SHADOW;
edmaOut->u.fmt1.dataOutPong.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_FMT1_PONG_EVENT_QUE;
}
edmaOut->dataOutSignature.channel = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_SIG_CH;
edmaOut->dataOutSignature.channelShadow = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_SIG_SHADOW;
edmaOut->dataOutSignature.eventQueue = DPC_OBJDET_DPU_RANGEPROC_EDMAOUT_SIG_EVENT_QUE;
/* hwres - hwa */
/* Use ISOLATED mode to support CBUFF in future */
hwaCfg->dataInputMode = DPU_RangeProcHWA_InputMode_ISOLATED;
#ifdef DPC_USE_SYMMETRIC_WINDOW_RANGE_DPU
hwaCfg->hwaWinSym = HWA_FFT_WINDOW_SYMMETRIC;
#else
hwaCfg->hwaWinSym = HWA_FFT_WINDOW_NONSYMMETRIC;
#endif
hwaCfg->hwaWinRamOffset = (uint16_t) DPC_OBJDET_HWA_WINDOW_RAM_OFFSET;
if ((hwaCfg->hwaWinRamOffset + winGenLen) > DPC_OBJDETRANGEHWA_HWA_MAX_WINDOW_RAM_SIZE_IN_SAMPLES)
{
retVal = DPC_OBJDETRANGEHWA_ENOMEM_HWA_WINDOW_RAM;
goto exit;
}
hwaCfg->numParamSet = DPU_RANGEPROCHWA_NUM_HWA_PARAM_SETS;
hwaCfg->paramSetStartIdx = DPC_OBJDET_DPU_RANGEPROC_PARAMSET_START_IDX;
*cfgSave = rangeCfg;
retVal = DPU_RangeProcHWA_config(dpuHandle, &rangeCfg);
if (retVal != 0)
{
goto exit;
}
/* store configuration for use in intra-sub-frame processing and
* inter-sub-frame switching, although window will need to be regenerated and
* dc range sig should not be reset. */
rangeCfg.staticCfg.resetDcRangeSigMeanBuffer = 0;
*cfgSave = rangeCfg;
exit:
return retVal;
}
/**
* @b Description
* @n
* Performs processing related to pre-start configuration, which is per sub-frame,
* by configuring each of the DPUs involved in the processing chain.
* Memory management notes:
* 1. Core Local Memory that needs to be preserved across sub-frames (such as range DPU's calib DC buffer)
* will be allocated using MemoryP_alloc.
* 2. Core Local Memory that needs to be preserved within a sub-frame across DPU calls
* (the DPIF * type memory) or for intermediate private scratch memory for
* DPU (i.e no preservation is required from process call to process call of the DPUs
* within the sub-frame) will be allocated from the Core Local RAM configuration supplied in
* @ref DPC_ObjectDetectionRangeHWA_InitParams given to @ref DPC_ObjectDetection_init API
* 3. L3 memory will only be allocated from the L3 RAM configuration supplied in
* @ref DPC_ObjectDetectionRangeHWA_InitParams given to @ref DPC_ObjectDetection_init API
* No L3 buffers are presently required that need to be preserved across sub-frames
* (type described in #1 above), neither are L3 scratch buffers required for
* intermediate processing within DPU process call.
*
* @param[in] subFrmObj Pointer to sub-frame object
* @param[in] objDetObj Pointer to objDetObj
* @param[in] staticCfg Pointer to static configuration of the sub-frame
* @param[in] dynCfg Pointer to dynamic configuration of the sub-frame
* @param[out] memUsage Pointer to memory usage structure to report mmemory
usage in this DPC
*
* @retval
* Success - 0
* @retval
* Error - <0
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*/
static int32_t DPC_ObjDetRangeHwa_preStartConfig
(
SubFrameObj *subFrmObj,
ObjDetObj *objDetObj,
DPC_ObjectDetectionRangeHWA_StaticCfg *staticCfg,
DPC_ObjectDetectionRangeHWA_DynCfg *dynCfg,
DPC_ObjectDetectionRangeHWA_preStartCfg_memUsage *memUsage
)
{
int32_t retVal = 0;
DPIF_RadarCube radarCube;
MemPoolObj *L3RamObj;
MemPoolObj *CoreLocalRamObj;
L3RamObj = &objDetObj->L3RamObj;
CoreLocalRamObj = &objDetObj->CoreLocalRamObj;
DPC_ObjDetRangeHwa_MemPoolReset(L3RamObj);
DPC_ObjDetRangeHwa_MemPoolReset(CoreLocalRamObj);
/* L3 allocations */
/* L3 - radar cube -- This has be synced with the DSP chain */
radarCube.dataSize = staticCfg->numRangeBins * staticCfg->numDopplerChirps *
staticCfg->numVirtualAntennas * sizeof(cmplx16ReIm_t);
radarCube.data = DPC_ObjDetRangeHwa_MemPoolAlloc(L3RamObj, radarCube.dataSize,
DPC_OBJDETRANGEHWA_RADAR_CUBE_DATABUF_BYTE_ALIGNMENT);
if (radarCube.data == NULL)
{
retVal = DPC_OBJDETRANGEHWA_ENOMEM__L3_RAM_RADAR_CUBE;
goto exit;
}
radarCube.datafmt = staticCfg->radarCubeFormat;
retVal = DPC_ObjDetRangeHwa_rangeConfig(subFrmObj->dpuRangeObj,
staticCfg,
dynCfg,
objDetObj->edmaHandle,
&radarCube, CoreLocalRamObj,
&subFrmObj->rangeCfg);
if (retVal != 0)
{
goto exit;
}
/* Report RAM usage */
memUsage->CoreLocalRamUsage = DPC_ObjDetRangeHwa_MemPoolGetMaxUsage(CoreLocalRamObj);
memUsage->L3RamUsage = DPC_ObjDetRangeHwa_MemPoolGetMaxUsage(L3RamObj);
exit:
return retVal;
}
/**
* @b Description
* @n
* DPC frame start function registered with DPM. This is invoked on reception
* of the frame start ISR from the RF front-end.
*
* @param[in] handle DPM's DPC handle
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Not applicable
*/
static void DPC_ObjectDetection_frameStart (DPM_DPCHandle handle)
{
ObjDetObj *objDetObj = (ObjDetObj *) handle;
objDetObj->stats.frameStartTimeStamp = Cycleprofiler_getTimeStamp();
DebugP_log2("ObjDet DPC: Frame Start, frameIndx = %d, subFrameIndx = %d\n",
objDetObj->stats.frameStartIntCounter, objDetObj->subFrameIndx);
/* Check if previous frame (sub-frame) processing has completed */
DPC_Objdet_Assert(objDetObj->dpmHandle, (objDetObj->interSubFrameProcToken == 0));
objDetObj->interSubFrameProcToken++;
/* Increment interrupt counter for debugging purpose */
if (objDetObj->subFrameIndx == 0)
{
objDetObj->stats.frameStartIntCounter++;
}
/* Notify the DPM Module that the DPC is ready for execution */
DebugP_assert (DPM_notifyExecute (objDetObj->dpmHandle, handle, true) == 0);
return;
}
/**
* @b Description
* @n
* DPC's (DPM registered) execute function which is invoked by the application
* in the DPM's execute context when the DPC issues DPM_notifyExecute API from
* its registered @ref DPC_ObjectDetection_frameStart API that is invoked every
* frame interrupt.
*
* @param[in] handle DPM's DPC handle
* @param[out] ptrResult Pointer to the result
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Success - 0
* @retval
* Error - <0
*/
int32_t DPC_ObjectDetection_execute
(
DPM_DPCHandle handle,
DPM_Buffer* ptrResult
)
{
ObjDetObj *objDetObj;
SubFrameObj *subFrmObj;
DPU_RangeProcHWA_OutParams outRangeProc;
int32_t retVal;
//DPM_Buffer rangeProcResult;
objDetObj = (ObjDetObj *) handle;
DebugP_assert (objDetObj != NULL);
DebugP_assert (ptrResult != NULL);
DebugP_log1("ObjDet DPC: Processing sub-frame %d\n", objDetObj->subFrameIndx);
subFrmObj = &objDetObj->subFrameObj[objDetObj->subFrameIndx];
if (objDetObj->processCallBackFxn.processFrameBeginCallBackFxn != NULL)
{
(*objDetObj->processCallBackFxn.processFrameBeginCallBackFxn)(objDetObj->subFrameIndx);
}
retVal = DPU_RangeProcHWA_process(subFrmObj->dpuRangeObj, &outRangeProc);
if (retVal != 0)
{
goto exit;
}
DebugP_assert(outRangeProc.endOfChirp == true);
subFrmObj = &objDetObj->subFrameObj[objDetObj->subFrameIndx];
if (objDetObj->processCallBackFxn.processInterFrameBeginCallBackFxn != NULL)
{
(*objDetObj->processCallBackFxn.processInterFrameBeginCallBackFxn)(objDetObj->subFrameIndx);
}
/********************************************************************************
* Range Processing is finished, now it can send data to inter frame processing DPC.
********************************************************************************/
DPIF_RadarCube *test_range_result=NULL;
test_range_result->data=objDetObj->subFrameObj[objDetObj->subFrameIndx].rangeCfg.hwRes.radarCube.data;
test_range_result->dataSize=objDetObj->subFrameObj[objDetObj->subFrameIndx].rangeCfg.hwRes.radarCube.dataSize;
test_range_result->datafmt=objDetObj->subFrameObj[objDetObj->subFrameIndx].rangeCfg.hwRes.radarCube.datafmt;
ptrResult->ptrBuffer[0] = (uint8_t *)test_range_result;
ptrResult->size[0] = sizeof(DPIF_RadarCube);
//rangeProcResult.ptrBuffer[0] = objDetObj->subFrameObj[objDetObj->subFrameIndx].rangeCfg.hwRes.radarCube.data;
//rangeProcResult.size[0] = objDetObj->subFrameObj[objDetObj->subFrameIndx].rangeCfg.hwRes.radarCube.dataSize;
/* Relay the results: */
//retVal = DPM_relayResult(objDetObj->dpmHandle, handle, &rangeProcResult);
DebugP_assert (retVal == 0);
/********************************************************************************
* This DPC does not report results to the application so for the
* sake of clarity reset the result buffer
********************************************************************************/
memset ((void *)ptrResult, 0, sizeof(DPM_Buffer));
objDetObj->interSubFrameProcToken--;
/********************************************************************************
* Prepare for next Frame
********************************************************************************/
/* Update subFrame index */
objDetObj->subFrameIndx++;
objDetObj->subFrameIndx = objDetObj->subFrameIndx % objDetObj->commonCfg.numSubFrames;
if(objDetObj->commonCfg.numSubFrames > 1U)
{
/* Re-configure Range DPU for next subFrame */
retVal = DPC_ObjDetRangeHwa_reconfigSubFrame(objDetObj, objDetObj->subFrameIndx);
DebugP_assert (retVal == 0);
}
/* Trigger Range DPU for next frame */
retVal = DPU_RangeProcHWA_control(objDetObj->subFrameObj[objDetObj->subFrameIndx].dpuRangeObj,
DPU_RangeProcHWA_Cmd_triggerProc, NULL, 0);
DPC_Objdet_Assert(objDetObj->dpmHandle, (retVal == 0));
/* For rangeProcHwa, interChirpProcessingMargin is not available */
objDetObj->stats.interChirpProcessingMargin = 0;
objDetObj->stats.interFrameStartTimeStamp = Cycleprofiler_getTimeStamp();
DebugP_log0("ObjDet DPC: Range Proc Done\n");
exit:
return retVal;
}
/**
* @b Description
* @n
* DPC's (DPM registered) start function which is invoked by the
* application using DPM_start API.
*
* @param[in] handle DPM's DPC handle
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Success - 0
* @retval
* Error - <0
*/
static int32_t DPC_ObjectDetection_start (DPM_DPCHandle handle)
{
ObjDetObj *objDetObj;
SubFrameObj *subFrmObj;
int32_t retVal = 0;
objDetObj = (ObjDetObj *) handle;
DebugP_assert (objDetObj != NULL);
objDetObj->stats.frameStartIntCounter = 0;
/* Start marks consumption of all pre-start configs, reset the flag to check
* if pre-starts were issued only after common config was issued for the next
* time full configuration happens between stop and start */
objDetObj->isCommonCfgReceived = false;
/* App must issue export of last frame after stop which will switch to sub-frame 0,
* so start should always see sub-frame indx of 0, check */
DebugP_assert(objDetObj->subFrameIndx == 0);
if(objDetObj->commonCfg.numSubFrames > 1U)
{
/* Pre-start cfgs for sub-frames may have come in any order, so need
* to ensure we reconfig for the current (0) sub-frame before starting */
DPC_ObjDetRangeHwa_reconfigSubFrame(objDetObj, objDetObj->subFrameIndx);
}
/* Trigger Range DPU, related to reconfig above */
subFrmObj = &objDetObj->subFrameObj[objDetObj->subFrameIndx];
retVal = DPU_RangeProcHWA_control(subFrmObj->dpuRangeObj,
DPU_RangeProcHWA_Cmd_triggerProc, NULL, 0);
if(retVal < 0)
{
goto exit;
}
DebugP_log0("ObjDet DPC: Start done\n");
exit:
return(retVal);
}
/**
* @b Description
* @n
* DPC's (DPM registered) stop function which is invoked by the
* application using DPM_stop API.
*
* @param[in] handle DPM's DPC handle
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Success - 0
* @retval
* Error - <0
*/
static int32_t DPC_ObjectDetection_stop (DPM_DPCHandle handle)
{
ObjDetObj *objDetObj;
objDetObj = (ObjDetObj *) handle;
DebugP_assert (objDetObj != NULL);
/* We can be here only after complete frame processing is done, which means
* processing token must be 0 and subFrameIndx also 0 */
DebugP_assert(objDetObj->subFrameIndx == 0);
DebugP_log0("ObjDet DPC: Stop done\n");
return(0);
}
/**
* @b Description
* @n
* DPC IOCTL commands configuration API which will be invoked by the
* application using DPM_ioctl API
*
* @param[in] handle DPM's DPC handle
* @param[in] cmd Capture DPC specific commands
* @param[in] arg Command specific arguments
* @param[in] argLen Length of the arguments which is also command specific
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Success - 0
* @retval
* Error - <0
*/
static int32_t DPC_ObjectDetection_ioctl
(
DPM_DPCHandle handle,
uint32_t cmd,
void* arg,
uint32_t argLen
)
{
ObjDetObj *objDetObj;
SubFrameObj *subFrmObj;
int32_t retVal = 0;
/* Get the DSS MCB: */
objDetObj = (ObjDetObj *) handle;
DebugP_assert(objDetObj != NULL);
DebugP_assert(arg != NULL);
/* Process the commands. Process non sub-frame specific ones first
* so the sub-frame specific ones can share some code. */
if((cmd < DPC_OBJDETRANGEHWA_IOCTL__STATIC_PRE_START_CFG) ||
(cmd > DPC_OBJDETRANGEHWA_IOCTL__DYNAMIC_CALIB_DC_RANGE_SIG_CFG))
{
retVal = DPM_EINVCMD;
}
else if (cmd == DPC_OBJDETRANGEHWA_IOCTL__STATIC_PRE_START_COMMON_CFG)
{
uint8_t index;
DPC_ObjectDetectionRangeHWA_PreStartCommonCfg *cfg;
DebugP_assert(argLen == sizeof(DPC_ObjectDetectionRangeHWA_PreStartCommonCfg));
cfg = (DPC_ObjectDetectionRangeHWA_PreStartCommonCfg*)arg;
/* Release DPU DC range Signal mean memory */
for(index = 0; index < objDetObj->commonCfg.numSubFrames; index ++)
{
subFrmObj = &objDetObj->subFrameObj[index];
if (subFrmObj->rangeCfg.hwRes.dcRangeSigMean)
{
MemoryP_ctrlFree(subFrmObj->rangeCfg.hwRes.dcRangeSigMean,
subFrmObj->rangeCfg.hwRes.dcRangeSigMeanSize);
}
}
objDetObj->commonCfg = *cfg;
objDetObj->isCommonCfgReceived = true;
DebugP_log0("ObjDet DPC: Pre-start Common Config IOCTL processed\n");
}
else
{
uint8_t subFrameNum;
subFrameNum = *(uint8_t *)arg;
switch (cmd)
{
/* Range DPU related */
case DPC_OBJDETRANGEHWA_IOCTL__DYNAMIC_CALIB_DC_RANGE_SIG_CFG:
{
DPC_ObjectDetectionRangeHWA_CalibDcRangeSigCfg *cfg;
DebugP_assert(argLen == sizeof(DPC_ObjectDetectionRangeHWA_CalibDcRangeSigCfg));
cfg = (DPC_ObjectDetectionRangeHWA_CalibDcRangeSigCfg*)arg;
subFrmObj = &objDetObj->subFrameObj[subFrameNum];
retVal = DPU_RangeProcHWA_control(subFrmObj->dpuRangeObj,
DPU_RangeProcHWA_Cmd_dcRangeCfg,
&cfg->cfg,
sizeof(DPU_RangeProc_CalibDcRangeSigCfg));
if (retVal != 0)
{
goto exit;
}
/* save into object */
subFrmObj->dynCfg.calibDcRangeSigCfg = cfg->cfg;
break;
}
/* Related to pre-start configuration */
case DPC_OBJDETRANGEHWA_IOCTL__STATIC_PRE_START_CFG:
{
DPC_ObjectDetectionRangeHWA_PreStartCfg *cfg;
DPC_ObjectDetectionRangeHWA_preStartCfg_memUsage *memUsage;
MemoryP_Stats statsStart;
MemoryP_Stats statsEnd;
/* Pre-start common config must be received before pre-start configs are received. */
if (objDetObj->isCommonCfgReceived == false)
{
retVal = DPC_OBJDETRANGEHWA_PRE_START_CONFIG_BEFORE_PRE_START_COMMON_CONFIG;
goto exit;
}
DebugP_assert(argLen == sizeof(DPC_ObjectDetectionRangeHWA_PreStartCfg));
/* Get system heap size before preStart configuration */
MemoryP_getStats(&statsStart);
cfg = (DPC_ObjectDetectionRangeHWA_PreStartCfg*)arg;
subFrmObj = &objDetObj->subFrameObj[subFrameNum];
memUsage = &cfg->memUsage;
memUsage->L3RamTotal = objDetObj->L3RamObj.cfg.size;
memUsage->CoreLocalRamTotal = objDetObj->CoreLocalRamObj.cfg.size;
retVal = DPC_ObjDetRangeHwa_preStartConfig(subFrmObj,
objDetObj,
&cfg->staticCfg,
&cfg->dynCfg,
memUsage);
if (retVal != 0)
{
goto exit;
}
/* Populate radarCube memory information */
cfg->radarCubeMem.addr = subFrmObj->rangeCfg.hwRes.radarCube.data;
cfg->radarCubeMem.size = subFrmObj->rangeCfg.hwRes.radarCube.dataSize;
/* Get system heap size after preStart configuration */
MemoryP_getStats(&statsEnd);
/* Populate system heap usage */
memUsage->SystemHeapTotal = statsEnd.totalSize;
memUsage->SystemHeapUsed = statsEnd.totalSize -statsEnd.totalFreeSize;
memUsage->SystemHeapDPCUsed = statsStart.totalFreeSize - statsEnd.totalFreeSize;
DebugP_log1("ObjDet DPC: Pre-start Config IOCTL processed (subFrameIndx = %d)\n", cfg->subFrameNum);
break;
}
default:
{
/* Error: This is an unsupported command */
retVal = DPM_EINVCMD;
break;
}
}
}
exit:
return retVal;
}
/**
* @b Description
* @n
* DPC's (DPM registered) initialization function which is invoked by the
* application using DPM_init API. Among other things, this API allocates DPC instance
* and DPU instances (by calling DPU's init APIs) from the MemoryP osal
* heap. If this API returns an error of any type, the heap is not guaranteed
* to be in the same state as before calling the API (i.e any allocations
* from the heap while executing the API are not guaranteed to be deallocated
* in case of error), so any error from this API should be considered fatal and
* if the error is of _ENOMEM type, the application will
* have to be built again with a bigger heap size to address the problem.
*
* @param[in] dpmHandle DPM's DPC handle
* @param[in] ptrInitCfg Handle to the framework semaphore
* @param[out] errCode Error code populated on error
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Success - 0
* @retval
* Error - <0
*/
static DPM_DPCHandle DPC_ObjectDetection_init
(
DPM_Handle dpmHandle,
DPM_InitCfg* ptrInitCfg,
int32_t* errCode
)
{
int32_t i;
ObjDetObj *objDetObj = NULL;
DPC_ObjectDetectionRangeHWA_InitParams *dpcInitParams;
HWA_MemInfo hwaMemInfo;
uint8_t index;
*errCode = 0;
if ((ptrInitCfg == NULL) || (ptrInitCfg->arg == NULL))
{
*errCode = DPC_OBJDETRANGEHWA_EINVAL;
goto exit;
}
if (ptrInitCfg->argSize != sizeof(DPC_ObjectDetectionRangeHWA_InitParams))
{
*errCode = DPC_OBJDETRANGEHWA_EINVAL__INIT_CFG_ARGSIZE;
goto exit;
}
dpcInitParams = (DPC_ObjectDetectionRangeHWA_InitParams *) ptrInitCfg->arg;
objDetObj = MemoryP_ctrlAlloc(sizeof(ObjDetObj), 0);
#ifdef DBG_DPC_OBJDETRANGEHWA
gObjDetObj = objDetObj;
#endif
DebugP_log1("ObjDet DPC: objDetObj address = %d\n", (uint32_t) objDetObj);
if(objDetObj == NULL)
{
*errCode = DPC_OBJDETRANGEHWA_ENOMEM;
goto exit;
}
/* Initialize memory */
memset((void *)objDetObj, 0, sizeof(ObjDetObj));
/* Copy over the DPM configuration: */
memcpy ((void*)&objDetObj->dpmInitCfg, (void*)ptrInitCfg, sizeof(DPM_InitCfg));
objDetObj->dpmHandle = dpmHandle;
objDetObj->socHandle = ptrInitCfg->socHandle;
objDetObj->L3RamObj.cfg = dpcInitParams->L3ramCfg;
objDetObj->CoreLocalRamObj.cfg = dpcInitParams->CoreLocalRamCfg;
/* Validate EDMA handle */
DebugP_assert(dpcInitParams->edmaHandle!= NULL);
objDetObj->edmaHandle = dpcInitParams->edmaHandle;
/* Validate HWA handle */
DebugP_assert(dpcInitParams->hwaHandle!= NULL);
objDetObj->hwaHandle = dpcInitParams->hwaHandle;
objDetObj->processCallBackFxn = dpcInitParams->processCallBackFxn;
/* Set HWA bank memory address */
*errCode = HWA_getHWAMemInfo(dpcInitParams->hwaHandle, &hwaMemInfo);
if (*errCode != 0)
{
goto exit;
}
objDetObj->hwaMemBankSize = hwaMemInfo.bankSize;
for (i = 0; i < hwaMemInfo.numBanks; i++)
{
objDetObj->hwaMemBankAddr[i] = hwaMemInfo.baseAddress +
i * hwaMemInfo.bankSize;
}
for(index = 0; index < RL_MAX_SUBFRAMES; index++)
{
DPU_RangeProcHWA_InitParams rangeInitParams;
rangeInitParams.hwaHandle = objDetObj->hwaHandle;
objDetObj->subFrameObj[index].dpuRangeObj = DPU_RangeProcHWA_init(&rangeInitParams, errCode);
}
exit:
if(*errCode != 0)
{
if(objDetObj != NULL)
{
MemoryP_ctrlFree(objDetObj, sizeof(ObjDetObj));
objDetObj = NULL;
}
}
return ((DPM_DPCHandle)objDetObj);
}
/**
* @b Description
* @n
* DPC's (DPM registered) de-initialization function which is invoked by the
* application using DPM_deinit API.
*
* @param[in] handle DPM's DPC handle
*
* \ingroup DPC_OBJDETRANGEHWA__INTERNAL_FUNCTION
*
* @retval
* Success - 0
* @retval
* Error - <0
*/
static int32_t DPC_ObjectDetection_deinit (DPM_DPCHandle handle)
{
int32_t retVal = 0;
ObjDetObj *objDetObj = NULL;
uint8_t index;
if (handle == NULL)
{
retVal = DPC_OBJDETRANGEHWA_EINVAL;
goto exit;
}
objDetObj = handle;
for(index = 0; index < RL_MAX_SUBFRAMES; index++)
{
if(objDetObj->subFrameObj[index].dpuRangeObj != NULL)
{
retVal = DPU_RangeProcHWA_deinit(objDetObj->subFrameObj[index].dpuRangeObj);
if (retVal != 0)
{
goto exit;
}
}
}
/* Free DPC memory */
MemoryP_ctrlFree(handle, sizeof(ObjDetObj));
exit:
return (retVal);
}
HI,
When HWA is working on the range FFT, the ARM core is just idle and waiting for the HWA finishing semaphore to get ready to do inter-frame process. HWA is triggered by chirping events, and ARM core is not involved in the whole processing.
You can wait until range FFT is done for all the chirps in the frame to start transfer the radarCube data.
Best,
Zigang