- Also fix propagation delay related configuration Fixes: PINDSW-5681,PINDSW-6533 Signed-off-by: Achala Ram <a-ram@ti.com>
537 lines
18 KiB
C
537 lines
18 KiB
C
/*
|
|
* Copyright (C) 2021-23 Texas Instruments Incorporated
|
|
*
|
|
* 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 EXPgResS 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.
|
|
*/
|
|
|
|
/*
|
|
* \par
|
|
*
|
|
*
|
|
* Example API usage (host trigger mode, single channel):
|
|
* ------------------------------------------------------
|
|
*
|
|
* A. Obtain handle
|
|
*
|
|
* struct endat_priv priv = endat_init(<interface base>);
|
|
* [AM437x: endat_init(0x54440000);]
|
|
*
|
|
* B. Configure to host trigger mode
|
|
*
|
|
* endat_config_host_trigger(priv);
|
|
*
|
|
* C. Select channel
|
|
*
|
|
* endat_config_channel(priv, <#channel>);
|
|
*
|
|
* D. Load & run the firmware
|
|
*
|
|
* E. Wait for firmware to initialize, clock frequency would be set to 8MHz by the end of the following command
|
|
*
|
|
* endat_wait_initialization(priv, <timeout>);
|
|
*
|
|
* F. Set 200KHz frequency to read encoder information so as to not to be affected by propagation delay
|
|
*
|
|
* endat_config_clock(priv, clk_cfg);
|
|
*
|
|
* G. Get encoder information
|
|
*
|
|
* endat_get_encoder_info(priv);
|
|
*
|
|
* H. Set operating frequency, say 8MHz
|
|
*
|
|
* endat_config_clock(priv, &clk_cfg);
|
|
*
|
|
* I. Get the propagation delay estimated by the firmware
|
|
*
|
|
* prop_delay = endat_get_prop_delay(priv);
|
|
*
|
|
* J. Handle propagation delay
|
|
*
|
|
* endat_config_rx_arm_cnt(priv, <prop_delay (minimum 2T, T - period of operating frequency)>);
|
|
* endat_config_rx_clock_disable(priv, <prop_delay - 2T (if < 0, use 0)>);
|
|
*
|
|
* K. Configure tST
|
|
*
|
|
* endat_config_tst_delay(priv, <tST delay (if f > 1MHz, use 2000, else 0)>);
|
|
*
|
|
* L. Process the EnDat command, transmit, this returns upon receive & command is complete,
|
|
*
|
|
* endat_command_process(priv, cmd, cmd_supplement);
|
|
*
|
|
* M. Process the received data
|
|
*
|
|
* endat_recvd_process(priv, cmd, &endat_format_data);
|
|
*
|
|
* N. Do CRC verification
|
|
*
|
|
* endat_recvd_validate(priv, cmd, &endat_format_data);
|
|
*
|
|
* O. Update additional information state tracking, if needed
|
|
*
|
|
* endat_addinfo_track(priv, cmd, &cmd_supplement);
|
|
*
|
|
* Result would be in union endat_format_data
|
|
*
|
|
*
|
|
* Example API usage [simplified] (periodic trigger mode, single channel):
|
|
* -----------------------------------------------------------------------
|
|
*
|
|
* Note: IEP CMP2 is the trigger event in periodic trigger mode and has to be setup beforehand.
|
|
*
|
|
* A. Get encoder info, follow steps A, B, C, D, E, G of host trigger mode, firmware defaults to 8MHz frequency
|
|
*
|
|
* B. Switch to periodic trigger mode, this will take effect after the next command completes
|
|
*
|
|
* endat_config_periodic_trigger(priv);
|
|
*
|
|
* C. Setup & send the 2.2 position periodic command, needs to be done only once
|
|
*
|
|
* endat_command_process(priv, 8, NULL);
|
|
*
|
|
* D. After giving enough time to complete the command after periodic event, to read angle for rotary encoder quickly
|
|
*
|
|
* endat_get_2_2_angle(priv);
|
|
*
|
|
*
|
|
* Example API usage (periodic trigger mode, single channel):
|
|
* ---------------------------------------------------------
|
|
*
|
|
* Note: IEP CMP2 is the trigger event in periodic trigger mode and has to be setup beforehand.
|
|
*
|
|
* A. Get encoder info & set desired timings for required frequency taking care of propagation delay, steps A-K of host trigger mode
|
|
*
|
|
* B. Switch to periodic trigger mode, this will take effect after the next command completes
|
|
*
|
|
* endat_config_periodic_trigger(priv);
|
|
*
|
|
* C. Setup the command to be periodically sent
|
|
*
|
|
* endat_command_build(priv, cmd, cmd_supplement);
|
|
*
|
|
* D. Send the command
|
|
*
|
|
* endat_command_send(priv);
|
|
*
|
|
* E. Wait for the command to finish
|
|
*
|
|
* endat_command_wait(priv);
|
|
*
|
|
* F. Process the received data
|
|
*
|
|
* endat_recvd_process(priv, cmd, &endat_format_data);
|
|
*
|
|
* G. Do CRC verification
|
|
*
|
|
* endat_recvd_validate(priv, cmd, &endat_format_data);
|
|
*
|
|
* H. Update additional information state tracking, if needed
|
|
*
|
|
* endat_addinfo_track(priv, cmd, &cmd_supplement);
|
|
*
|
|
* Result would be in union endat_format_data
|
|
*
|
|
* Repeat E-H to get periodic update after the next periodic event <br>
|
|
* happens, this can be done in say ISR (which could be linked to the <br>
|
|
* periodic event). For a new command to be executed periodically, <br>
|
|
* endat_command_build() can invoked after step H, this will take effect <br>
|
|
* from the next periodic event.
|
|
*
|
|
* EnDat commands:
|
|
* ---------------
|
|
*
|
|
* Command description of command numbers passed to endat_command_process()
|
|
* and endat_command_build() as follows,
|
|
*
|
|
* 1: Encoder send position values <br>
|
|
* 2: Selection of memory area <br>
|
|
* 3: Encoder receive parameter <br>
|
|
* 4: Encoder send parameter <br>
|
|
* 5: Encoder receive reset <br>
|
|
* 6: Encoder send test values <br>
|
|
* 7: Encoder receive test command <br>
|
|
* 8: Encoder to send position + AI(s) <br>
|
|
* 9: Encoder to send position + AI(s) and receive selection of memory area <br>
|
|
* 10: Encoder to send position + AI(s) and receive parameter <br>
|
|
* 11: Encoder to send position + AI(s) and send parameter <br>
|
|
* 12: Encoder to send position + AI(s) and receive error reset <br>
|
|
* 13: Encoder to send position + AI(s) and receive test command <br>
|
|
* 14: Encoder receive communication command <br>
|
|
*
|
|
*/
|
|
|
|
#ifndef ENDAT_API_H_
|
|
#define ENDAT_API_H_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* \defgroup MOTOR_CONTROL_API APIs for Motor Control Encoders
|
|
*
|
|
* This module contains APIs for device drivers for various motor control encoders supported in this SDK.
|
|
*/
|
|
|
|
/**
|
|
* \defgroup ENDAT_API_MODULE APIs for ENDAT Encoder
|
|
* \ingroup MOTOR_CONTROL_API
|
|
*
|
|
* Here is the list of APIs used for EnDAT encoder communication protocol
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* \brief process raw recieved data and format based on the command
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] cmd EnDat command number
|
|
* \param[out] u pointer to union for storing formatted data based on cmd
|
|
*
|
|
* \retval 0 for success, -EINVAL for failure
|
|
*
|
|
*/
|
|
int32_t endat_recvd_process(struct endat_priv *priv, int32_t cmd,
|
|
union endat_format_data *u);
|
|
|
|
/**
|
|
* \brief CRC result indicated in return value as follows, <br>
|
|
* 0th bit high position/address/params/test CRC success <br>
|
|
* 0th bit low position/address/params/test CRC failure <br>
|
|
* 1st bit high if addinfo 1 present, addinfo 1 CRC success <br>
|
|
* 1st bit low if addinfo 1 present, addinfo 1 CRC failure <br>
|
|
* 2nd bit high if addinfo 2 present, addinfo 2 CRC success <br>
|
|
* 2nd bit low if addinfo 2 present, addinfo 2 CRC failure
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] cmd EnDat command number
|
|
* \param[in] u pointer to union having formatted data based on cmd
|
|
*
|
|
* \retval status position/address/params/test CRC status
|
|
*
|
|
*/
|
|
uint32_t endat_recvd_validate(struct endat_priv *priv, int32_t cmd,
|
|
union endat_format_data *u);
|
|
|
|
/**
|
|
* \brief send the EnDat command and wait till firmware acknowledges
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] cmd EnDat command number
|
|
* \param[in] cmd_supplement Supplement information needed to setup EnDat cmd
|
|
*
|
|
* \retval 0 for success, -EINVAL for failure
|
|
*
|
|
*/
|
|
int32_t endat_command_process(struct endat_priv *priv, int32_t cmd,
|
|
struct cmd_supplement *cmd_supplement);
|
|
|
|
/**
|
|
* \brief setup the EnDat command in the PRU interface buffer
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] cmd EnDat command number
|
|
* \param[in] cmd_supplement Supplement information needed to setup EnDat cmd
|
|
*
|
|
* \retval 0 for success, -EINVAL for failure
|
|
*
|
|
*/
|
|
int32_t endat_command_build(struct endat_priv *priv, int32_t cmd,
|
|
struct cmd_supplement *cmd_supplement);
|
|
|
|
/**
|
|
* \brief trigger sending the EnDat command in PRU
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
*
|
|
*/
|
|
void endat_command_send(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief wait till PRU finishes EnDat transaction
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
*
|
|
*/
|
|
void endat_command_wait(struct endat_priv *priv);
|
|
|
|
|
|
/**
|
|
* \brief read RT from DMEM
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
* \retval Value of Recovery Time in nanoseconds
|
|
*
|
|
*/
|
|
uint32_t endat_get_recovery_time(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief update priv with position resolution, id, serial number, encoder
|
|
* type and supported command set
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
* \retval 0 for success, -EINVAL for failure
|
|
*
|
|
*/
|
|
int32_t endat_get_encoder_info(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief get propagation delay automatically estimated by the firmware
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
* \retval delay estimated propogation delay
|
|
*
|
|
*/
|
|
uint32_t endat_get_prop_delay(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief track presence of additional information in priv
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] cmd EnDat command number
|
|
* \param[in] cmd_supplement Supplement information needed to setup EnDat cmd
|
|
*
|
|
*
|
|
*/
|
|
void endat_addinfo_track(struct endat_priv *priv, int32_t cmd,
|
|
struct cmd_supplement *cmd_supplement);
|
|
|
|
/**
|
|
* \brief configure EnDat clock
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] clk_cfg pointer to structure containing clock configuration data
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_clock(struct endat_priv *priv,
|
|
struct endat_clk_cfg *clk_cfg);
|
|
|
|
/**
|
|
* \brief configure tST delay
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] delay tST delay value
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_tst_delay(struct endat_priv *priv, uint16_t delay);
|
|
|
|
/**
|
|
* \brief configure rx arm counter
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] val rx arm counter value in ns
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_rx_arm_cnt(struct endat_priv *priv, uint16_t val);
|
|
|
|
/**
|
|
* \brief configure wire delay for the selected channel
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] val wire delay in ns
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_wire_delay(struct endat_priv *priv, uint16_t val);
|
|
|
|
/**
|
|
* \brief configure clocks to be disabled at the end of rx to account for tD
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] val number of clocks to be disabled
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_rx_clock_disable(struct endat_priv *priv,
|
|
uint16_t val);
|
|
|
|
/**
|
|
* \brief start continuous mode
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
* \retval 0 success, -EINVAL for failure
|
|
*
|
|
*/
|
|
int32_t endat_start_continuous_mode(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief stop continuous mode
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
*
|
|
*/
|
|
void endat_stop_continuous_mode(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief configure EnDat master for host trigger mode
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_host_trigger(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief configure EnDat master in periodic trigger mode
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_periodic_trigger(struct endat_priv *priv);
|
|
/* brief set syn_bits of all connected channels for synchronization before global_TX_init
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] mask channels mask
|
|
*
|
|
*/
|
|
void endat_config_syn_bits(struct endat_priv *priv, uint8_t mask);
|
|
/**
|
|
* \brief set a core as primay core for global configuration, clk configuration and TX_GLOBAL_INIT
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] mask channels mask
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_primary_core_mask(struct endat_priv *priv, uint8_t mask);
|
|
/**
|
|
* \brief enable load share mode if encoders has diffent make
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
*/
|
|
void endat_enable_load_share_mode(struct endat_priv *priv);
|
|
/**
|
|
* \brief select channel to be used by EnDat master
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] ch channel to be selected
|
|
*
|
|
*
|
|
*/
|
|
void endat_config_channel(struct endat_priv *priv, int32_t ch);
|
|
/**
|
|
* \brief select mask of channels to be used in multi channel configuration by EnDat master
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] mask channel mask
|
|
* \param[in] loadshare value for loadshare mode enable.
|
|
*
|
|
*/
|
|
void endat_config_multi_channel_mask(struct endat_priv *priv,
|
|
uint8_t mask,
|
|
uint8_t loadshare);
|
|
/**
|
|
* \brief select channels detected in multi channel configuration by EnDat master. <br>
|
|
* required to be invoked only if firmware indicates initialization failure <br>
|
|
* to know the channels that has been detected. Initialization success implies <br>
|
|
* that all channels indicated has been detected.
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
* \retval mask mask of the detected channels
|
|
*
|
|
*/
|
|
uint8_t endat_multi_channel_detected(struct endat_priv *priv);
|
|
|
|
/**
|
|
* \brief In multi channel configuration, select channel before receive processing in <br>
|
|
* multi channel configuration. After receive is complete, select each channel <br>
|
|
* and invoke rx API's to parse data recieved in each channel.
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] ch channel number to be selected
|
|
*
|
|
*
|
|
*/
|
|
void endat_multi_channel_set_cur(struct endat_priv *priv, int32_t ch);
|
|
/**
|
|
* \brief wait for EnDat master firmware to initialize
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
* \param[in] timeout timeout to wait for initialization
|
|
* \param[in] mask channel mask
|
|
* \retval 0 for success, -EINVAL for failure
|
|
*
|
|
*/
|
|
int32_t endat_wait_initialization(struct endat_priv *priv, uint32_t timeout, uint8_t mask);
|
|
|
|
/**
|
|
* \brief Initialize EnDat firmware interface address and get the pointer
|
|
* to struct endat_priv instance
|
|
*
|
|
* \param[in] pruss_xchg EnDat firmware interface address
|
|
* \param[in] pruss_cfg ICSS PRU config base address
|
|
* \param[in] pruss_iep ICSS PRU iep base address
|
|
* \param[in] slice ICSS PRU SLICE
|
|
*
|
|
* \retval priv pointer to struct endat_priv instance
|
|
*
|
|
*/
|
|
struct endat_priv *endat_init(struct endat_pruss_xchg *pruss_xchg,
|
|
void *pruss_cfg, void *pruss_iep, int32_t slice);
|
|
|
|
/**
|
|
* \brief Read EnDat 2.2 angular position in steps for rotary encoders <br>
|
|
* (prior to invoking this, 2.2 position command has to be completed)<br>
|
|
* This checks the CRC status (updated on-the-fly by firmware), <br>
|
|
* checks the group alarm errors (F1/F2 bits) and the angle value <br>
|
|
* recieved in reverse are reversed in a highly optimized way using <br>
|
|
* inline assembly. <br>
|
|
* Assumptions (that holds good for quite a few encoders): <br>
|
|
* 1. Total resolution >= 25 <br>
|
|
* 2. Single turn resolution <= 30
|
|
*
|
|
* \param[in] priv cookie returned by endat_init
|
|
*
|
|
* \retval angle for angular position in steps on success, -1 for failure
|
|
*
|
|
*/
|
|
int32_t endat_get_2_2_angle(struct endat_priv *priv);
|
|
|
|
/** @} */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|