Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:48

0001 /**
0002  * @file
0003  *
0004  * @ingroup arm_beagle
0005  *
0006  * @brief eQEP (enhanced Quadrature Encoder Pulse) support API.
0007  */
0008 
0009 /*
0010  * SPDX-License-Identifier: BSD-2-Clause
0011  *
0012  * Copyright (c) 2020, 2021 James Fitzsimons <james.fitzsimons@gmail.com>
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 /**
0037  *
0038  * For details of the Enhanced Quadrature Encoder Pulse (eQEP) Module refer to
0039  * page 2511 of the TI Technical Reference Manual
0040  * (https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf)
0041  *
0042  * This driver supports using the QEP modules in Quadrature-clock Mode.
0043  * Direction-count Mode is not currently supported. Similarly the QEPI: Index
0044  * or Zero Marker and QEPS: Strobe Input pins are not currently supported.
0045  *
0046  * The mode can be any one of:
0047  *  - Quadrature-count mode - For encoders that generate pulses 90 degrees
0048  *      out of phase for determining direction and speed.
0049  *  - Direction-count mode - for position encoders that provide direction and
0050  *      clock outputs, instead of quadrature outputs.
0051  *  - UP-count mode - The counter direction signal is hard-wired for up count
0052  *      and the position counter is used to measure the frequency of the QEPA
0053  *      input.
0054  *  - DOWN-count mode - The counter direction signal is hard-wired for a down
0055  *      count and the position counter is used to measure the frequency of the
0056  *      QEPA input.
0057  *
0058  * When the eQEP module is configured in quadrature mode, the module
0059  * can either provide an absolute position, or a relative position. Absolute
0060  * simply increments or decrements depending on the direction. Relative
0061  * increments until the unit timer overflows at which point it latches the
0062  * position value, resets the position count to zero and starts again.
0063  */
0064 
0065 #ifndef LIBBSP_ARM_BEAGLE_QEP_H
0066 #define LIBBSP_ARM_BEAGLE_QEP_H
0067 
0068 #ifdef __cplusplus
0069 extern "C" {
0070 #endif /* __cplusplus */
0071 
0072 #define AM335X_EQEP_REGS                       (0x00000180)
0073 #define AM335X_EQEP_0_REGS                     (AM335X_PWMSS0_MMAP_ADDR + AM335X_EQEP_REGS)
0074 #define AM335X_EQEP_1_REGS                     (AM335X_PWMSS1_MMAP_ADDR + AM335X_EQEP_REGS)
0075 #define AM335X_EQEP_2_REGS                     (AM335X_PWMSS2_MMAP_ADDR + AM335X_EQEP_REGS)
0076 
0077 /* eQEP registers of the PWMSS modules - see page 1672 of the TRM for details */
0078 #define AM335x_EQEP_QPOSCNT       0x0   /* eQEP Position Counter */
0079 #define AM335x_EQEP_QPOSINIT      0x4   /* eQEP Position Counter Initialization */
0080 #define AM335x_EQEP_QPOSMAX       0x8   /* eQEP Maximum Position Count */
0081 #define AM335x_EQEP_QPOSCMP       0xC   /* eQEP Position-Compare */
0082 #define AM335x_EQEP_QPOSILAT      0x10  /* eQEP Index Position Latch */
0083 #define AM335x_EQEP_QPOSSLAT      0x14  /* eQEP Strobe Position Latch */
0084 #define AM335x_EQEP_QPOSLAT       0x18  /* eQEP Position Counter Latch */
0085 #define AM335x_EQEP_QUTMR         0x1C  /* eQEP Unit Timer */
0086 #define AM335x_EQEP_QUPRD         0x20  /* eQEP Unit Period */
0087 #define AM335x_EQEP_QWDTMR        0x24  /* eQEP Watchdog Timer */
0088 #define AM335x_EQEP_QWDPRD        0x26  /* eQEP Watchdog Period */
0089 #define AM335x_EQEP_QDECCTL       0x28  /* eQEP Decoder Control */
0090 #define AM335x_EQEP_QEPCTL        0x2A  /* eQEP Control */
0091 #define AM335x_EQEP_QCAPCTL       0x2C  /* eQEP Capture Control */
0092 #define AM335x_EQEP_QPOSCTL       0x2E  /* eQEP Position-Compare Control */
0093 #define AM335x_EQEP_QEINT         0x30  /* eQEP Interrupt Enable */
0094 #define AM335x_EQEP_QFLG          0x32  /* eQEP Interrupt Flag */
0095 #define AM335x_EQEP_QCLR          0x34  /* eQEP Interrupt Clear */
0096 #define AM335x_EQEP_QFRC          0x36  /* eQEP Interrupt Force */
0097 #define AM335x_EQEP_QEPSTS        0x38  /* eQEP Status */
0098 #define AM335x_EQEP_QCTMR         0x3A  /* eQEP Capture Timer */
0099 #define AM335x_EQEP_QCPRD         0x3C  /* eQEP Capture Period */
0100 #define AM335x_EQEP_QCTMRLAT      0x3E  /* eQEP Capture Timer Latch */
0101 #define AM335x_EQEP_QCPRDLAT      0x40  /* eQEP Capture Period Latch */
0102 #define AM335x_EQEP_REVID         0x5C  /* eQEP Revision ID */
0103 
0104 /* bitmasks for eQEP registers  */
0105 #define AM335x_EQEP_QEPCTL_UTE    (1 << 1)
0106 #define AM335x_EQEP_QEPCTL_QCLM   (1 << 2)
0107 #define AM335x_EQEP_QEPCTL_PHEN   (1 << 3)
0108 #define AM335x_EQEP_QEPCTL_IEL    (1 << 4)
0109 #define AM335x_EQEP_QEPCTL_SWI    (1 << 7)
0110 #define AM335x_EQEP_QEPCTL_PCRM   (3 << 12)
0111 #define AM335x_EQEP_QDECCTL_QSRC  (3 << 14)
0112 #define AM335x_EQEP_QDECCTL_XCR   (1 << 11)
0113 #define AM335x_EQEP_QDECCTL_SWAP  (1 << 10)
0114 #define AM335x_EQEP_QDECCTL_IGATE (1 << 9)
0115 #define AM335x_EQEP_QDECCTL_QAP   (1 << 8)
0116 #define AM335x_EQEP_QDECCTL_QBP   (1 << 7)
0117 #define AM335x_EQEP_QDECCTL_QIP   (1 << 6)
0118 #define AM335x_EQEP_QDECCTL_QSP   (1 << 5)
0119 #define AM335x_EQEP_CLK_EN        (1 << 4)
0120 #define AM335x_EQEP_QEINT_UTO     (1 << 11)
0121 #define AM335x_EQEP_QFLG_UTO      (1 << 11)
0122 #define AM335x_EQEP_QFLG_MASK     0x0FFF
0123 
0124 /* The pin mux modes for the QEP input pins on the P8 and P9 headers */
0125 #define BBB_P8_11_MUX_QEP 4
0126 #define BBB_P8_12_MUX_QEP 4
0127 #define BBB_P8_15_MUX_QEP 4
0128 #define BBB_P8_16_MUX_QEP 4
0129 #define BBB_P8_31_MUX_QEP 2
0130 #define BBB_P8_32_MUX_QEP 2
0131 #define BBB_P8_33_MUX_QEP 2
0132 #define BBB_P8_35_MUX_QEP 2
0133 #define BBB_P8_39_MUX_QEP 3
0134 #define BBB_P8_40_MUX_QEP 3
0135 #define BBB_P8_41_MUX_QEP 3
0136 #define BBB_P8_42_MUX_QEP 3
0137 #define BBB_P9_25_MUX_QEP 1
0138 #define BBB_P9_27_MUX_QEP 1
0139 #define BBB_P9_41_MUX_QEP 1
0140 #define BBB_P9_42_MUX_QEP 1
0141 
0142 #define NANO_SEC_PER_SEC  1000000000
0143 /* This is the max clock rate for the EPWMSS module. See 15.1.2.2 of the TRM.
0144  * If the CPU was using dynamic scaling this could potentially be wrong */
0145 #define SYSCLKOUT         100000000
0146 
0147 /**
0148  * @brief The set of possible eQEP Position Counter Input Modes
0149  *
0150  * Enumerated type to define various modes for the eQEP module. The values
0151  * correspond to the values for the QSRC bits of the QDECCTL register.
0152  */
0153 typedef enum {
0154   QUADRATURE_COUNT = 0,
0155   DIRECTION_COUNT,
0156   UP_COUNT,
0157   DOWN_COUNT
0158 } BBB_QEP_COUNT_MODE;
0159 
0160 /**
0161  * @brief The set of possible modes for Quadrature decode
0162  *
0163  */
0164 typedef enum {
0165   ABSOLUTE = 0,
0166   RELATIVE
0167 } BBB_QEP_QUADRATURE_MODE;
0168 
0169 /**
0170  * @brief The set of possible eQEP input pins
0171  *
0172  */
0173 typedef enum {
0174   BBB_P8_11_2B_IN,
0175   BBB_P8_12_2A_IN,
0176   BBB_P8_15_2_STROBE,
0177   BBB_P8_16_2_IDX,
0178   BBB_P8_31_1_IDX,
0179   BBB_P8_32_1_STROBE,
0180   BBB_P8_33_1B_IN,
0181   BBB_P8_35_1A_IN,
0182   BBB_P8_39_2_IDX,
0183   BBB_P8_40_2_STROBE,
0184   BBB_P8_41_2A_IN,
0185   BBB_P8_42_2B_IN,
0186   BBB_P9_25_0_STROBE,
0187   BBB_P9_27_0B_IN,
0188   BBB_P9_41_0_IDX,
0189   BBB_P9_42_0A_IN
0190 } bbb_qep_pin;
0191 
0192 
0193 /**
0194  * @brief This function definition is used to declare a callback function that
0195  * will be called by the interrupt handler of the QEP driver. In order for the
0196  * interrupt event to trigger the driver must be configured in RELATIVE mode
0197  * (using the beagle_qep_get_quadrature_mode function), and the unit timer must
0198  * have been configured (using the beagle_eqep_set_timer_period function).
0199  *
0200  * @param BBB_PWMSS This argument is provided to the user call back function so
0201  * that the user can tell which QEP module raised the interrupt.
0202  *
0203  * @param position The value of the position counter that was latched when the
0204  * unit timer raised this interrupt. This is the value that would be returned
0205  * by calling "beagle_qep_get_position".
0206  *
0207  * @param user This a pointer to a user provided data structure. The user sets
0208  * this pointer value when configuring the unit timer callback via the
0209  * beagle_eqep_set_timer_period function and it is returned here as an argument.
0210  * The driver does not touch this value.
0211  */
0212 typedef void (*bbb_eqep_timer_callback)(
0213   BBB_PWMSS,
0214   uint32_t position,
0215   void* user
0216 );
0217 
0218 
0219 /**
0220  * @brief This structure represents an eQEP module instance. The members
0221  * represent the configuration of a specific eQEP module. There are three
0222  * eQEP modules in the AM335x, one associated with each PWMSS unit.
0223  * @var bbb_eqep::pwmss_id The PWMSS unit this eQEP module belongs to.
0224  * @var bbb_eqep::mmio_base The base address for this eQEP modules registers
0225  * @var bbb_eqep::irq The IRQ vector for this eQEP module
0226  * @var bbb_eqep::timer_callback An optional user provided callback function
0227  * when the driver is configured in RELATIVE mode using the unit timer
0228  * @var bbb_eqep::user An optional pointer to user provided data that will be
0229  * handed to the callback function as an argument.
0230  * @var bbb_eqep::count_mode The count mode for this eQEP module. Defaults to
0231  * QUADRATURE.
0232  * @var bbb_eqep::quadrature_mode The mode for QUADRATURE operation. Defaults
0233  * to ABSOLUTE - will count up to overflow or until the user resets the
0234  * position. Can be set to RELATIVE which will trigger a call back of the unit
0235  * timer if configured.
0236  * @var bbb_eqep::invert_qa 1 to invert the A channel input, 0 to leave as is.
0237  * @var bbb_eqep::invert_qb 1 to invert the B channel input, 0 to leave as is.
0238  * @var bbb_eqep::invert_qi 1 to invert the INDEX input, 0 to leave as is.
0239  * @var bbb_eqep::invert_qs 1 to invert the STROBE input, 0 to leave as is.
0240  * @var bbb_eqep::swap_inputs 1 to swap the A and B channel inputs, 0 to leave
0241  * as is.
0242  *
0243  */
0244 typedef struct {
0245   const BBB_PWMSS pwmss_id;
0246   const uint32_t mmio_base;
0247   const rtems_vector_number irq;
0248   bbb_eqep_timer_callback timer_callback;
0249   void* user;
0250   BBB_QEP_COUNT_MODE count_mode;
0251   BBB_QEP_QUADRATURE_MODE quadrature_mode;
0252   uint32_t invert_qa;
0253   uint32_t invert_qb;
0254   uint32_t invert_qi;
0255   uint32_t invert_qs;
0256   uint32_t swap_inputs;
0257 } bbb_eqep;
0258 
0259 
0260 /**
0261  * @brief Initialises the eQEP module of the specified PWMSS unit. This
0262  * configures the clocks, sets up the interrupt handler and unit timer,
0263  * The module is configured in Quadrature decode mode using
0264  * absolute position by default.
0265  *
0266  * @param pwmss_id The PWMSS module to configure the eQEP for.
0267  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0268  * supplied.
0269  */
0270 rtems_status_code beagle_qep_init(BBB_PWMSS pwmss_id);
0271 
0272 /**
0273  * @brief Enables the eQEP module of the specified PWMSS unit.
0274  *
0275  * @param pwmss_id The PWMSS module which will have the eQEP function enabled.
0276  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0277  * supplied.
0278  */
0279 rtems_status_code beagle_qep_enable(BBB_PWMSS pwmss_id);
0280 
0281 /**
0282  * @brief Disables the eQEP module of the specified PWMSS unit.
0283  *
0284  * @param pwmss_id The PWMSS module which will have the eQEP function disabled.
0285  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0286  * supplied.
0287  */
0288 rtems_status_code beagle_qep_disable(BBB_PWMSS pwmss_id);
0289 
0290 /**
0291  * @brief Configures a given pin for use with the eQEP function of the supplied
0292  * PWMSS module.
0293  *
0294  * @param pin_no The P9 or P8 header pin to be configured for the eQEP function.
0295  * @param pwmss_id The PWMSS module which will have the eQEP function enabled.
0296  * @param pullup_enable If true then the internal pull up resistor on the
0297  * specified pin will be enabled, if false the pull down will be enabled.
0298  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0299  * supplied.
0300  */
0301 rtems_status_code beagle_qep_pinmux_setup(
0302   bbb_qep_pin pin_no,
0303   BBB_PWMSS pwmss_id,
0304   bool pullup_enable
0305 );
0306 
0307 /**
0308  * @brief Returns the current position value of the eQEP function for the
0309  * specified PWMSS module.
0310  *
0311  * @param pwmss_id Identifies which PWMSS module to return the eQEP position for
0312  * @return int32_t The current position value.
0313  */
0314 int32_t beagle_qep_get_position(BBB_PWMSS pwmss_id);
0315 
0316 /**
0317  * @brief Sets the initial position value of the eQEP function for the
0318  * specified PWMSS module.
0319  *
0320  * @param pwmss_id Identifies which PWMSS module to set the eQEP position for
0321  * @param position The value to initialise the position register with.
0322  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0323  * supplied.
0324  */
0325 rtems_status_code beagle_qep_set_position(
0326     BBB_PWMSS pwmss_id,
0327     uint32_t position
0328 );
0329 
0330 /**
0331  * @brief Sets the count mode for the eQEP module.
0332  * @param pwmss_id Identifies which PWMSS module to set the eQEP count mode for.
0333  * @param mode One of the above modes to configure the eQEP module for.
0334  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0335  * supplied.
0336  */
0337 rtems_status_code beagle_qep_set_count_mode(
0338   BBB_PWMSS pwmss_id,
0339   BBB_QEP_COUNT_MODE mode
0340 );
0341 
0342 /**
0343  * @brief Gets the currently configured count mode for the eQEP module.
0344  * @param pwmss_id Identifies which PWMSS module to set the eQEP count mode for.
0345  * @return An enum value representing the current count mode.
0346  */
0347 BBB_QEP_COUNT_MODE beagle_qep_get_count_mode(BBB_PWMSS pwmss_id);
0348 
0349 /**
0350  * @brief Returns the currently configured quadrature mode - either absolute,
0351  * or relative.
0352  * @param pwmss_id Identifies which PWMSS module to get the eQEP quadrature
0353  * mode for.
0354  * @return BBB_QEP_QUADRATURE_MODE The currently configured quadrature mode.
0355  */
0356 BBB_QEP_QUADRATURE_MODE beagle_qep_get_quadrature_mode(BBB_PWMSS pwmss_id);
0357 
0358 /**
0359  * @brief Sets the quadrature mode to either absolute or relative.
0360  * @param pwmss_id Identifies which PWMSS module to set the eQEP quadrature
0361  * mode for.
0362  * @param mode BBB_QEP_QUADRATURE_MODE Set the mode of the eQEP to either
0363  * absolute or relative.
0364  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0365  * supplied.
0366  */
0367 rtems_status_code beagle_qep_set_quadrature_mode(
0368     BBB_PWMSS pwmss_id,
0369     BBB_QEP_QUADRATURE_MODE mode
0370 );
0371 
0372 /**
0373  * @brief Returns the the currently configured unit timer period.
0374  * @param pwmss_id Identifies which PWMSS module to get the eQEP timer value for
0375  * @return uint32_t The current unit timer value in nanoseconds
0376  */
0377 uint32_t beagle_eqep_get_timer_period(BBB_PWMSS pwmss_id);
0378 
0379 /**
0380  * @brief Sets the unit timer period for the eQEP module.
0381  * 0 = off, greater than zero sets the period.
0382  * @param pwmss_id Identifies which PWMSS module to set the eQEP unit timer for.
0383  * @param period The value in nanoseconds to set the unit timer period to.
0384  * @param timer_callback This is the user provided callback function that will
0385  * be called by the interrupt event handler on expiry of the unit timer. The
0386  * user can provide NULL if they don't require a call back.
0387  * @param user This is a pointer to a user provided data structure that will be
0388  * handed back as an argument to the timer callback. The driver does not touch
0389  * this value.
0390  * @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
0391  * supplied.
0392  */
0393 rtems_status_code beagle_eqep_set_timer_period(
0394     BBB_PWMSS pwmss_id,
0395     uint64_t period,
0396     bbb_eqep_timer_callback timer_callback,
0397     void* user
0398 );
0399 
0400 #ifdef __cplusplus
0401 }
0402 #endif /* __cplusplus */
0403 
0404 #endif /* LIBBSP_ARM_BEAGLE_QEP_H */