/* DCL.h - C2000 Digital Control Library * */ //############################################################################# //! //! Copyright: Copyright (C) 2023 Texas Instruments Incorporated - //! All rights reserved not granted herein. //! Limited License. //! //! Texas Instruments Incorporated grants a world-wide, royalty-free, //! non-exclusive license under copyrights and patents it now or hereafter //! owns or controls to make, have made, use, import, offer to sell and sell //! ("Utilize") this software subject to the terms herein. With respect to the //! foregoing patent license, such license is granted solely to the extent that //! any such patent is necessary to Utilize the software alone. The patent //! license shall not apply to any combinations which include this software, //! other than combinations with devices manufactured by or for TI //! ("TI Devices"). //! No hardware patent is licensed hereunder. //! //! Redistributions must preserve existing copyright notices and reproduce this //! license (including the above copyright notice and the disclaimer and //! (if applicable) source code license limitations below) in the documentation //! and/or other materials provided with the distribution. //! //! Redistribution and use in binary form, without modification, are permitted //! provided that the following conditions are met: //! //! * No reverse engineering, decompilation, or disassembly of this software is //! permitted with respect to any software provided in binary form. //! * Any redistribution and use are licensed by TI for use only //! with TI Devices. //! * Nothing shall obligate TI to provide you with source code for the //! software licensed and provided to you in object code. //! //! If software source code is provided to you, modification and redistribution //! of the source code are permitted provided that the following conditions //! are met: //! //! * any redistribution and use of the source code, including any resulting //! derivative works, are licensed by TI for use only with TI Devices. //! * any redistribution and use of any object code compiled from the source //! code and any resulting derivative works, are licensed by TI for use //! only with TI Devices. //! //! Neither the name of Texas Instruments Incorporated nor the names of its //! suppliers may be used to endorse or promote products derived from this //! software without specific prior written permission. //############################################################################# #ifndef _C_DCL_H #define _C_DCL_H #ifdef __cplusplus extern "C" { #endif //! \file DCL.h //! \brief Contains the public interface to the common //! Digital Controller Library functions //! \brief Library version number formatted for numerical comparison //! #define DCL_VERSION 3040000 #ifndef C2000_IEEE754_TYPES #define C2000_IEEE754_TYPES #ifdef __TI_EABI__ typedef float float32_t; typedef double float64_t; #else typedef float float32_t; typedef long double float64_t; #endif // __TI_EABI__ #endif // C2000_IEEE754_TYPES #ifndef __TMS320C28XX_CLA__ #include #include #include #include #include //! \brief Local definitions of mathematical constants //! #define CONST_PI_32 3.14159265358979323846f #define CONST_2PI_32 2.0f * CONST_PI_32 #define CONST_PI_64 3.1415926535897932384626433832795028841971693993751058209749445923078164062L #define CONST_2PI_64 2.0L * CONST_PI_64 //! \brief Defines 32-bit null address for pointer initialization //! #define NULL_ADDR 0x00000000 //! \brief Define the acceptable FPU numerical tolerances //! #define DEFAULT_FPU32_TOL 1.0e-06f #define DEFAULT_FPU64_TOL 1.0e-10f //! \brief Determines numerical proximity to specified value //! #define F32_IS_VALUE(x,y) (((x < (y + DEFAULT_FPU32_TOL)) && (x > (y - DEFAULT_FPU32_TOL))) ? 1 : 0) #define F64_IS_VALUE(x,y) (((x < (y + DEFAULT_FPU64_TOL)) && (x > (y - DEFAULT_FPU64_TOL))) ? 1 : 0) //! \brief Determines numerical proximity to zero //! #define F32_IS_ZERO(x) F32_IS_VALUE(x,0.0f) #define F64_IS_ZERO(x) F64_IS_VALUE(x,0.0L) //! \brief Returns a random floating point result between -1.0 and +1.0 //! where 'a' is a single or double precision float. //! Useful for initialization of arrays and matrices during test. //! Ensure compiler switch "--fp_mode = relaxed" is set to ensure h/w division. //! //! \code //! float32_t s = DCL_randf(1.0f); //! #define DCL_randf(a) (a * ((float32_t) rand() / (float32_t) (RAND_MAX >> 1) - 1.0f)) #define DCL_randf64(a) (a * ((float64_t) rand() / (float64_t) (RAND_MAX >> 1) - 1.0L)) //! \brief Defines the lower limit on derivative filter coefficient c2 //! in order for fc to lie below the Nyquist frequency //! #define DCL_C2_LIMIT_32 ((2.0f - CONST_PI_32) / (2.0f + CONST_PI_32)) #define DCL_C2_LIMIT_64 ((2.0L - CONST_PI_64) / (2.0L + CONST_PI_64)) //! \brief Define the default control period in seconds //! #define DCL_DEFAULT_T_F32 100.0e-06f #define DCL_DEFAULT_T_F64 100.0e-06L //! \brief Build the library with controller test points enabled //! #define DCL_TESTPOINTS_ENABLED //! \brief Build the library with break points enabled //! #define DCL_BREAK_POINTS_ENABLED //! \brief Defines a debug break point //! #ifdef DCL_BREAK_POINTS_ENABLED #define DCL_BREAK_POINT asm(" ESTOP0") #else #define DCL_BREAK_POINT ; #endif //! \brief Boundary instructions for atomic code blocks //! Global interrupt mask is set at start of atomic block and //! restored to its' original value at the end //! #ifdef __TMS320C28XX__ #define DCL_DISABLE_INTS DCL_disableInts() #define DCL_RESTORE_INTS(v) DCL_restoreInts(v) //! \brief Sets global interrupts mask //! \return Original ST1 register value //! static inline int16_t DCL_disableInts(void) { return __disable_interrupts(); } //! \brief Restores global interrupts if they were previously enabled //! \param[in] v Original ST1 register value //! \return None //! static inline void DCL_restoreInts(int16_t v) { if (0 == (v & 0x1)) { __enable_interrupts(); } } #else #define DCL_DISABLE_INTS 0 #define DCL_RESTORE_INTS(v) ; #warning "CPU not recognized. Parameter updates may not be atomic." #endif //--- Controller Common Support Structure ------------------------------------ //! \brief Defines the controller common support structure //! //! \details The CSS is accessed via a pointer in most of the DCL //! controller structs. It contains data used for testing and //! configuring the controller, as well as for error checking. //! typedef struct dcl_css { float32_t tpt; //!< Test point float32_t T; //!< Controller period in seconds uint32_t sts; //!< Status word uint32_t err; //!< Error code uint32_t loc; //!< Error location } DCL_CSS; //! \brief Default values to initialize the CSS structure //! #define DCL_CSS_DEFAULTS { 0.0f, DCL_DEFAULT_T_F32, 0UL, 0UL, 0UL } //! \brief Loads the controller period in the CSS //! CSS pointer must be configured first //! \param[in] p Pointer to the controller structure //! \param[in] a Sample period in seconds //! \return None //! #define DCL_SET_CONTROLLER_PERIOD(p,a) ((p)->css->T = a) //! \brief Re-definition of legacy controller period call //! #define DCL_SET_SAMPLE_RATE DCL_SET_CONTROLLER_PERIOD //--- Status word ------------------------------------------------------------ //! \brief Defines the library enumerated status bits //! //! \details To perform a safe parameter update, the user first loads new //! parameters into the controller shadow parameter set, then sets //! the STS_UPDATE_PENDING bit in the controller status word. The //! next call to the update function performs the "shadow-to- //! active" set copy while global interrupts are disabled. //! enum dcl_status_bits { STS_NONE = 0UL, //!< Status empty STS_UPDATE_PENDING = (1U << 0), //!< Parameter update pending STS_CONTROLLER_RUNNING = (1U << 1), //!< Controller operation in progress STS_ADJUSTMENT_RUNNING = (1U << 2) //!< Parameter adjustment in progress }; //! \brief Macros to set the update flag in the status word to initiate //! controller parameter update on next DCL_update() call, and to //! clear the flag on completion. //! #define DCL_REQUEST_UPDATE(p) ((p)->css->sts |= STS_UPDATE_PENDING) #define DCL_CLEAR_UPDATE_REQUEST(p) ((p)->css->sts &= ~STS_UPDATE_PENDING) //! \brief Macro to determine whether a parameter update is pending //! based on the STS_UPDATE_PENDING bit in the status word. #define DCL_UPDATE_WAITING(p) (0U != ((p)->css->sts & STS_UPDATE_PENDING)) //! \brief Macros placed at the beginning and end of the controller //! so that other functions know a control operation is in //! progress. Typically only used with complex controllers //! which may not be atomic. //! #define DCL_CONTROLLER_BEGIN(p) ((p)->css->sts |= STS_CONTROLLER_RUNNING) #define DCL_CONTROLLER_END(p) ((p)->css->sts &= ~STS_CONTROLLER_RUNNING) //! \brief Macro to determine whether a controller is being executed //! based on the DCL_CONTROLLER_RUNNING bit in the status word. #define DCL_CONTROLLER_IN_PROGRESS(p) (0U != ((p)->css->sts & STS_CONTROLLER_RUNNING)) //! \brief Macros to set the flag in the status word to denote //! that parameter adjustment is in progress, and to //! clear the flag when the target is reached. //! #define DCL_ADJUSTMENT_RUNNING(p) ((p)->css->sts |= STS_ADJUSTMENT_RUNNING) #define DCL_ADJUSTMENT_COMPLETE(p) ((p)->css->sts &= ~STS_ADJUSTMENT_RUNNING) //! \brief Macro to determine whether parameter adjustment is underway //! based on the DCL_ADJUSTMENT_RUNNING bit in the status word. #define DCL_ADJUSTMENT_IN_PROGRESS(p) (0U != ((p)->css->sts & STS_ADJUSTMENT_RUNNING)) //--- Error handling --------------------------------------------------------- //! \brief Build the library with error handling enabled //! #define DCL_ERROR_HANDLING_ENABLED //! \brief Defines the library enumerated error codes //! These will be applied as bit masks in the error handler //! enum dcl_error_codes { ERR_NONE = 0U, //!< No error ERR_PARAM_RANGE = (1U << 0), //!< Parameter range exceeded ERR_PARAM_INVALID = (1U << 1), //!< Parameter not valid ERR_PARAM_WARN = (1U << 2), //!< Parameter warning ERR_INPUT_RANGE = (1U << 3), //!< Input range exceeded ERR_OVERFLOW = (1U << 4), //!< Numerical overflow ERR_UNDERFLOW = (1U << 5), //!< Numerical underflow ERR_VERSION = (1U << 6), //!< Incorrect DCL version ERR_DEVICE = (1U << 7), //!< Device not supported ERR_CONTROLLER = (1U << 8), //!< Controller operation not completed ERR_TIMING = (1U << 9), //!< Timing error ERR_COMPUTATION = (1U << 10) //!< Computation error }; //! \brief Macro to clear stored error code in CSS //! #define DCL_CLEAR_ERROR_CODE(p) (p->css->err = ERR_NONE) //! \brief Macro to store code location of error in CSS //! #define DCL_GET_ERROR_LOC(n) (n->loc = (ERR_NONE == n->err) ? NULL_ADDR : __LINE__) //! \brief Define error handling routine //! #define DCL_RUN_ERROR_HANDLER(n) DCL_runErrorHandler(n) //! \brief Prototype for external basic error handler [DCL_error.c] //! \param[in] p Pointer to DCL_CSS structure //! \return None //! extern void DCL_runErrorHandler(DCL_CSS *p); //--- Polynomial stability functions ----------------------------------------- //! \brief Determines stability of a first order real polynomial //! P(z) = z + a1 //! \param[in] a1 Coefficient a1 //! \return 'true' if the root has magnitude less than 1, 'false' otherwise //! static inline bool DCL_isStablePn1(float32_t a1) { return(((a1 * a1) < 1.0f) ? true : false); } //! \brief Determines stability of a second order polynomial with real coefficients //! P(z) = a0 z^2 + a1 z + a2 //! \param[in] a1 Coefficient a1 //! \param[in] a2 Coefficient a2 //! \return 'true' if both roots have magnitude less than 1, 'false' otherwise //! static inline bool DCL_isStablePn2(float32_t a0, float32_t a1, float32_t a2) { float32_t b0, b1, c0; b0 = a0 - a2 * a2 / a0; b1 = a1 - a1 * a2 / a0; c0 = b0 - b1 * b1 / b0; if ((a0 > 0.0f) && (b0 > 0.0f) && (c0 > 0.0f)) { return(true); } else { return(false); } } //! \brief Determines stability of a third order polynomial with real coefficients //! P(z) = a0 z^3 + a1 z^2 + a2 z + a3 //! \param[in] a1 Coefficient a1 //! \param[in] a2 Coefficient a2 //! \param[in] a3 Coefficient a3 //! \return 'true' if all roots have magnitude less than 1, 'false' otherwise //! static inline bool DCL_isStablePn3(float32_t a0, float32_t a1, float32_t a2, float32_t a3) { float32_t b0, b1, b2, c0, c1, d0; b0 = a0 - a3 * a3 / a0; b1 = a1 - a2 * a3 / a0; b2 = a2 - a1 * a3 / a0; c0 = b0 - b2 * b2 / b0; c1 = b1 - b1 * b2 / b0; d0 = c0 - c1 * c1 / c0; if ((a0 > 0.0f) && (b0 > 0.0f) && (c0 > 0.0f) && (d0 > 0.0f)) { return(true); } else { return(false); } } //--- ZPK3 structure --------------------------------------------------------- //! \brief Defines the DCL_ZPK3 controller structure. //! //! \details Allows controllers to be defined in terms of complex pole //! and zero frequencies. The common structure consists of //! three complex zeros, three complex poles, and a real gain. //! All frequencies must be specified in radians/sec. //! typedef struct dcl_zpk3 { float complex z1; float complex z2; float complex z3; float complex p1; float complex p2; float complex p3; float32_t K; } DCL_ZPK3; //! \brief Defines default values to initialize the DCL_ZPK3 structure //! #define ZPK3_DEFAULTS { 0.0f + 0.0f*I, 0.0f + 0.0f*I, 0.0f + 0.0f*I, \ 0.0f + 0.0f*I, 0.0f + 0.0f*I, 0.0f + 0.0f*I, \ 1.0f } //! \brief Determines stability of a ZPK3 representation by checking pole magnitude //! \param[in] q Pointer to DCL_ZPK3 structure //! \return 'true' if all poles have magnitude less than 1, 'false' otherwise //! static inline bool DCL_isStableZpk3(DCL_ZPK3 *q) { return(((cabsf(q->p1) < 1.0f) && (cabsf(q->p2) < 1.0f) && (cabsf(q->p3) < 1.0f)) ? true : false); } //---------------------------------------------------------------------------- #endif // __TMS320C28XX_CLA__ #ifdef __cplusplus } #endif // extern "C" #endif // _C_DCL_H /* end of file */