forked from Imagelibrary/rtems
bsps/beagle: Adding QEP driver support to BeagleBoneBlack BSP
This commit is contained in:
committed by
Christian Mauderer
parent
c0c4b8b8b5
commit
db86c3eb4f
@@ -13,3 +13,5 @@ include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/beagleboneb
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/i2c.h
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/irq.h
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/spi.h
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/qep.h
|
||||
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/pwmss.h
|
||||
|
||||
@@ -31,17 +31,6 @@ extern "C" {
|
||||
#define BBB_CONTROL_CONF_GPMC_AD(n) (0x800 + (n * 4))
|
||||
#define BBB_CONTROL_CONF_LCD_DATA(n) (0x8a0 + (n * 4))
|
||||
|
||||
/**
|
||||
* @brief The set of possible PWM subsystem module
|
||||
*
|
||||
* Enumerated type to define various instance of pwm module.
|
||||
*/
|
||||
typedef enum{
|
||||
BBB_PWMSS0 = 0,
|
||||
BBB_PWMSS1,
|
||||
BBB_PWMSS2,
|
||||
BBB_PWMSS_COUNT
|
||||
}BBB_PWMSS;
|
||||
|
||||
typedef enum{
|
||||
BBB_P8_13_2B = 3,
|
||||
|
||||
54
bsps/arm/beagle/include/bsp/pwmss.h
Normal file
54
bsps/arm/beagle/include/bsp/pwmss.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup arm_beagle
|
||||
*
|
||||
* @brief Shared PWMSS module functions used by PWM, eQEP and eCAP (when added).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright (c) 2020 James Fitzsimons <james.fitzsimons@gmail.com>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_ARM_BEAGLE_PWMSS_H
|
||||
#define LIBBSP_ARM_BEAGLE_PWMSS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* The following definitions are bitmasks for the clk control registers for
|
||||
* the PWMSS module clocks. All three modules have the same clock control
|
||||
* hence the EPMSSx to signify these values are consistent across all
|
||||
* EPWMSS instances. */
|
||||
#define AM335X_CM_PER_EPWMSSx_CLKCTRL_MODULEMODE_ENABLE (0x2u)
|
||||
#define AM335X_CM_PER_EPWMSSx_CLKCTRL_MODULEMODE (0x00000003u)
|
||||
#define AM335X_CM_PER_EPWMSSx_CLKCTRL_IDLEST_FUNC (0x0u)
|
||||
#define AM335X_CM_PER_EPWMSSx_CLKCTRL_IDLEST_SHIFT (0x00000010u)
|
||||
#define AM335X_CM_PER_EPWMSSx_CLKCTRL_IDLEST (0x00030000u)
|
||||
|
||||
/**
|
||||
* @brief The set of possible PWM subsystem module
|
||||
*
|
||||
* Enumerated type to define various instance of pwm module.
|
||||
*/
|
||||
typedef enum {
|
||||
BBB_PWMSS0 = 0,
|
||||
BBB_PWMSS1,
|
||||
BBB_PWMSS2,
|
||||
BBB_PWMSS_COUNT
|
||||
} BBB_PWMSS;
|
||||
|
||||
|
||||
rtems_status_code pwmss_module_clk_config(BBB_PWMSS pwmss_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* LIBBSP_ARM_BEAGLE_PWMSS_H */
|
||||
382
bsps/arm/beagle/include/bsp/qep.h
Normal file
382
bsps/arm/beagle/include/bsp/qep.h
Normal file
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup arm_beagle
|
||||
*
|
||||
* @brief eQEP (enhanced Quadrature Encoder Pulse) support API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright (c) 2020 James Fitzsimons <james.fitzsimons@gmail.com>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*
|
||||
* For details of the Enhanced Quadrature Encoder Pulse (eQEP) Module refer to
|
||||
* page 2511 of the TI Technical Reference Manual
|
||||
* (https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf)
|
||||
*
|
||||
* This driver supports using the QEP modules in Quadrature-clock Mode.
|
||||
* Direction-count Mode is not currently supported. Similarly the QEPI: Index
|
||||
* or Zero Marker and QEPS: Strobe Input pins are not currently supported.
|
||||
*
|
||||
* The mode can be any one of:
|
||||
* - Quadrature-count mode - For encoders that generate pulses 90 degrees
|
||||
* out of phase for determining direction and speed.
|
||||
* - Direction-count mode - for position encoders that provide direction and
|
||||
* clock outputs, instead of quadrature outputs.
|
||||
* - UP-count mode - The counter direction signal is hard-wired for up count
|
||||
* and the position counter is used to measure the frequency of the QEPA
|
||||
* input.
|
||||
* - DOWN-count mode - The counter direction signal is hard-wired for a down
|
||||
* count and the position counter is used to measure the frequency of the
|
||||
* QEPA input.
|
||||
*
|
||||
* When the eQEP module is configured in quadrature mode, the module
|
||||
* can either provide an absolute position, or a relative position. Absolute
|
||||
* simply increments or decrements depending on the direction. Relative
|
||||
* increments until the unit timer overflows at which point it latches the
|
||||
* position value, resets the position count to zero and starts again.
|
||||
*/
|
||||
|
||||
#ifndef LIBBSP_ARM_BEAGLE_QEP_H
|
||||
#define LIBBSP_ARM_BEAGLE_QEP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define AM335X_EQEP_REGS (0x00000180)
|
||||
#define AM335X_EQEP_0_REGS (AM335X_PWMSS0_MMAP_ADDR + AM335X_EQEP_REGS)
|
||||
#define AM335X_EQEP_1_REGS (AM335X_PWMSS1_MMAP_ADDR + AM335X_EQEP_REGS)
|
||||
#define AM335X_EQEP_2_REGS (AM335X_PWMSS2_MMAP_ADDR + AM335X_EQEP_REGS)
|
||||
|
||||
/* eQEP registers of the PWMSS modules - see page 1672 of the TRM for details */
|
||||
#define AM335x_EQEP_QPOSCNT 0x0 /* eQEP Position Counter */
|
||||
#define AM335x_EQEP_QPOSINIT 0x4 /* eQEP Position Counter Initialization */
|
||||
#define AM335x_EQEP_QPOSMAX 0x8 /* eQEP Maximum Position Count */
|
||||
#define AM335x_EQEP_QPOSCMP 0xC /* eQEP Position-Compare */
|
||||
#define AM335x_EQEP_QPOSILAT 0x10 /* eQEP Index Position Latch */
|
||||
#define AM335x_EQEP_QPOSSLAT 0x14 /* eQEP Strobe Position Latch */
|
||||
#define AM335x_EQEP_QPOSLAT 0x18 /* eQEP Position Counter Latch */
|
||||
#define AM335x_EQEP_QUTMR 0x1C /* eQEP Unit Timer */
|
||||
#define AM335x_EQEP_QUPRD 0x20 /* eQEP Unit Period */
|
||||
#define AM335x_EQEP_QWDTMR 0x24 /* eQEP Watchdog Timer */
|
||||
#define AM335x_EQEP_QWDPRD 0x26 /* eQEP Watchdog Period */
|
||||
#define AM335x_EQEP_QDECCTL 0x28 /* eQEP Decoder Control */
|
||||
#define AM335x_EQEP_QEPCTL 0x2A /* eQEP Control */
|
||||
#define AM335x_EQEP_QCAPCTL 0x2C /* eQEP Capture Control */
|
||||
#define AM335x_EQEP_QPOSCTL 0x2E /* eQEP Position-Compare Control */
|
||||
#define AM335x_EQEP_QEINT 0x30 /* eQEP Interrupt Enable */
|
||||
#define AM335x_EQEP_QFLG 0x32 /* eQEP Interrupt Flag */
|
||||
#define AM335x_EQEP_QCLR 0x34 /* eQEP Interrupt Clear */
|
||||
#define AM335x_EQEP_QFRC 0x36 /* eQEP Interrupt Force */
|
||||
#define AM335x_EQEP_QEPSTS 0x38 /* eQEP Status */
|
||||
#define AM335x_EQEP_QCTMR 0x3A /* eQEP Capture Timer */
|
||||
#define AM335x_EQEP_QCPRD 0x3C /* eQEP Capture Period */
|
||||
#define AM335x_EQEP_QCTMRLAT 0x3E /* eQEP Capture Timer Latch */
|
||||
#define AM335x_EQEP_QCPRDLAT 0x40 /* eQEP Capture Period Latch */
|
||||
#define AM335x_EQEP_REVID 0x5C /* eQEP Revision ID */
|
||||
|
||||
/* bitmasks for eQEP registers */
|
||||
#define AM335x_EQEP_QEPCTL_UTE (1 << 1)
|
||||
#define AM335x_EQEP_QEPCTL_QCLM (1 << 2)
|
||||
#define AM335x_EQEP_QEPCTL_PHEN (1 << 3)
|
||||
#define AM335x_EQEP_QEPCTL_IEL (1 << 4)
|
||||
#define AM335x_EQEP_QEPCTL_SWI (1 << 7)
|
||||
#define AM335x_EQEP_QEPCTL_PCRM (3 << 12)
|
||||
#define AM335x_EQEP_QDECCTL_QSRC (3 << 14)
|
||||
#define AM335x_EQEP_QDECCTL_XCR (1 << 11)
|
||||
#define AM335x_EQEP_QDECCTL_SWAP (1 << 10)
|
||||
#define AM335x_EQEP_QDECCTL_IGATE (1 << 9)
|
||||
#define AM335x_EQEP_QDECCTL_QAP (1 << 8)
|
||||
#define AM335x_EQEP_QDECCTL_QBP (1 << 7)
|
||||
#define AM335x_EQEP_QDECCTL_QIP (1 << 6)
|
||||
#define AM335x_EQEP_QDECCTL_QSP (1 << 5)
|
||||
#define AM335x_EQEP_CLK_EN (1 << 4)
|
||||
#define AM335x_EQEP_QEINT_UTO (1 << 11)
|
||||
#define AM335x_EQEP_QFLG_UTO (1 << 11)
|
||||
#define AM335x_EQEP_QFLG_MASK 0x0FFF
|
||||
|
||||
/* The pin mux modes for the QEP input pins on the P8 and P9 headers */
|
||||
#define BBB_P8_11_MUX_QEP 4
|
||||
#define BBB_P8_12_MUX_QEP 4
|
||||
#define BBB_P8_15_MUX_QEP 4
|
||||
#define BBB_P8_16_MUX_QEP 4
|
||||
#define BBB_P8_31_MUX_QEP 2
|
||||
#define BBB_P8_32_MUX_QEP 2
|
||||
#define BBB_P8_33_MUX_QEP 2
|
||||
#define BBB_P8_35_MUX_QEP 2
|
||||
#define BBB_P8_39_MUX_QEP 3
|
||||
#define BBB_P8_40_MUX_QEP 3
|
||||
#define BBB_P8_41_MUX_QEP 3
|
||||
#define BBB_P8_42_MUX_QEP 3
|
||||
#define BBB_P9_25_MUX_QEP 1
|
||||
#define BBB_P9_27_MUX_QEP 1
|
||||
#define BBB_P9_41_MUX_QEP 1
|
||||
#define BBB_P9_42_MUX_QEP 1
|
||||
|
||||
#define NANO_SEC_PER_SEC 1000000000
|
||||
/* This is the max clock rate for the EPWMSS module. See 15.1.2.2 of the TRM.
|
||||
* If the CPU was using dynamic scaling this could potentially be wrong */
|
||||
#define SYSCLKOUT 100000000
|
||||
|
||||
/**
|
||||
* @brief The set of possible eQEP Position Counter Input Modes
|
||||
*
|
||||
* Enumerated type to define various modes for the eQEP module. The values
|
||||
* correspond to the values for the QSRC bits of the QDECCTL register.
|
||||
*/
|
||||
typedef enum {
|
||||
QUADRATURE_COUNT = 0,
|
||||
DIRECTION_COUNT,
|
||||
UP_COUNT,
|
||||
DOWN_COUNT
|
||||
} BBB_QEP_COUNT_MODE;
|
||||
|
||||
/**
|
||||
* @brief The set of possible modes for Quadrature decode
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ABSOLUTE = 0,
|
||||
RELATIVE
|
||||
} BBB_QEP_QUADRATURE_MODE;
|
||||
|
||||
/**
|
||||
* @brief The set of possible eQEP input pins
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
BBB_P8_11_2B_IN,
|
||||
BBB_P8_12_2A_IN,
|
||||
BBB_P8_15_2_STROBE,
|
||||
BBB_P8_16_2_IDX,
|
||||
BBB_P8_31_1_IDX,
|
||||
BBB_P8_32_1_STROBE,
|
||||
BBB_P8_33_1B_IN,
|
||||
BBB_P8_35_1A_IN,
|
||||
BBB_P8_39_2_IDX,
|
||||
BBB_P8_40_2_STROBE,
|
||||
BBB_P8_41_2A_IN,
|
||||
BBB_P8_42_2B_IN,
|
||||
BBB_P9_25_0_STROBE,
|
||||
BBB_P9_27_0B_IN,
|
||||
BBB_P9_41_0_IDX,
|
||||
BBB_P9_42_0A_IN
|
||||
} bbb_qep_pin;
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function definition is used to declare a callback function that
|
||||
* will be called by the interrupt handler of the QEP driver. In order for the
|
||||
* interrupt event to trigger the driver must be configured in RELATIVE mode
|
||||
* (using the beagle_qep_get_quadrature_mode function), and the unit timer must
|
||||
* have been configured (using the beagle_eqep_set_timer_period function).
|
||||
*
|
||||
* @param BBB_PWMSS This argument is provided to the user call back function so
|
||||
* that the user can tell which QEP module raised the interrupt.
|
||||
*
|
||||
* @param position The value of the position counter that was latched when the
|
||||
* unit timer raised this interrupt. This is the value that would be returned
|
||||
* by calling "beagle_qep_get_position".
|
||||
*
|
||||
* @param user This a pointer to a user provided data structure. The user sets
|
||||
* this pointer value when configuring the unit timer callback via the
|
||||
* beagle_eqep_set_timer_period function and it is returned here as an argument.
|
||||
* The driver does not touch this value.
|
||||
*/
|
||||
typedef void (*bbb_eqep_timer_callback)(
|
||||
BBB_PWMSS,
|
||||
uint32_t position,
|
||||
void* user
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @brief This structure represents an eQEP module instance. The members
|
||||
* represent the configuration of a specific eQEP module. There are three
|
||||
* eQEP modules in the AM335x, one associated with each PWMSS unit.
|
||||
* @var bbb_eqep::pwmss_id The PWMSS unit this eQEP module belongs to.
|
||||
* @var bbb_eqep::mmio_base The base address for this eQEP modules registers
|
||||
* @var bbb_eqep::irq The IRQ vector for this eQEP module
|
||||
* @var bbb_eqep::timer_callback An optional user provided callback function
|
||||
* when the driver is configured in RELATIVE mode using the unit timer
|
||||
* @var bbb_eqep::user An optional pointer to user provided data that will be
|
||||
* handed to the callback function as an argument.
|
||||
* @var bbb_eqep::count_mode The count mode for this eQEP module. Defaults to
|
||||
* QUADRATURE.
|
||||
* @var bbb_eqep::quadrature_mode The mode for QUADRATURE operation. Defaults
|
||||
* to ABSOLUTE - will count up to overflow or until the user resets the
|
||||
* position. Can be set to RELATIVE which will trigger a call back of the unit
|
||||
* timer if configured.
|
||||
* @var bbb_eqep::invert_qa 1 to invert the A channel input, 0 to leave as is.
|
||||
* @var bbb_eqep::invert_qb 1 to invert the B channel input, 0 to leave as is.
|
||||
* @var bbb_eqep::invert_qi 1 to invert the INDEX input, 0 to leave as is.
|
||||
* @var bbb_eqep::invert_qs 1 to invert the STROBE input, 0 to leave as is.
|
||||
* @var bbb_eqep::swap_inputs 1 to swap the A and B channel inputs, 0 to leave
|
||||
* as is.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
const BBB_PWMSS pwmss_id;
|
||||
const uint32_t mmio_base;
|
||||
const rtems_vector_number irq;
|
||||
bbb_eqep_timer_callback timer_callback;
|
||||
void* user;
|
||||
BBB_QEP_COUNT_MODE count_mode;
|
||||
BBB_QEP_QUADRATURE_MODE quadrature_mode;
|
||||
uint32_t invert_qa;
|
||||
uint32_t invert_qb;
|
||||
uint32_t invert_qi;
|
||||
uint32_t invert_qs;
|
||||
uint32_t swap_inputs;
|
||||
} bbb_eqep;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialises the eQEP module of the specified PWMSS unit. This
|
||||
* configures the clocks, sets up the interrupt handler and unit timer,
|
||||
* The module is configured in Quadrature decode mode using
|
||||
* absolute position by default.
|
||||
*
|
||||
* @param pwmss_id The PWMSS module to configure the eQEP for.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_init(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Enables the eQEP module of the specified PWMSS unit.
|
||||
*
|
||||
* @param pwmss_id The PWMSS module which will have the eQEP function enabled.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_enable(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Disables the eQEP module of the specified PWMSS unit.
|
||||
*
|
||||
* @param pwmss_id The PWMSS module which will have the eQEP function disabled.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_disable(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Configures a given pin for use with the eQEP function of the supplied
|
||||
* PWMSS module.
|
||||
*
|
||||
* @param pin_no The P9 or P8 header pin to be configured for the eQEP function.
|
||||
* @param pwmss_id The PWMSS module which will have the eQEP function enabled.
|
||||
* @param pullup_enable If true then the internal pull up resistor on the
|
||||
* specified pin will be enabled, if false the pull down will be enabled.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_pinmux_setup(
|
||||
bbb_qep_pin pin_no,
|
||||
BBB_PWMSS pwmss_id,
|
||||
bool pullup_enable
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Returns the current position value of the eQEP function for the
|
||||
* specified PWMSS module.
|
||||
*
|
||||
* @param pwmss_id Identifies which PWMSS module to return the eQEP position for
|
||||
* @return int32_t The current position value.
|
||||
*/
|
||||
int32_t beagle_qep_get_position(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Sets the initial position value of the eQEP function for the
|
||||
* specified PWMSS module.
|
||||
*
|
||||
* @param pwmss_id Identifies which PWMSS module to set the eQEP position for
|
||||
* @param position The value to initialise the position register with.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_set_position(
|
||||
BBB_PWMSS pwmss_id,
|
||||
uint32_t position
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Sets the count mode for the eQEP module.
|
||||
* @param pwmss_id Identifies which PWMSS module to set the eQEP count mode for.
|
||||
* @param mode One of the above modes to configure the eQEP module for.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_set_count_mode(
|
||||
BBB_PWMSS pwmss_id,
|
||||
BBB_QEP_COUNT_MODE mode
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Gets the currently configured count mode for the eQEP module.
|
||||
* @param pwmss_id Identifies which PWMSS module to set the eQEP count mode for.
|
||||
* @return An enum value representing the current count mode.
|
||||
*/
|
||||
BBB_QEP_COUNT_MODE beagle_qep_get_count_mode(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Returns the currently configured quadrature mode - either absolute,
|
||||
* or relative.
|
||||
* @param pwmss_id Identifies which PWMSS module to get the eQEP quadrature
|
||||
* mode for.
|
||||
* @return BBB_QEP_QUADRATURE_MODE The currently configured quadrature mode.
|
||||
*/
|
||||
BBB_QEP_QUADRATURE_MODE beagle_qep_get_quadrature_mode(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Sets the quadrature mode to either absolute or relative.
|
||||
* @param pwmss_id Identifies which PWMSS module to set the eQEP quadrature
|
||||
* mode for.
|
||||
* @param mode BBB_QEP_QUADRATURE_MODE Set the mode of the eQEP to either
|
||||
* absolute or relative.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_qep_set_quadrature_mode(
|
||||
BBB_PWMSS pwmss_id,
|
||||
BBB_QEP_QUADRATURE_MODE mode
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Returns the the currently configured unit timer period.
|
||||
* @param pwmss_id Identifies which PWMSS module to get the eQEP timer value for
|
||||
* @return uint32_t The current unit timer value in nanoseconds
|
||||
*/
|
||||
uint32_t beagle_eqep_get_timer_period(BBB_PWMSS pwmss_id);
|
||||
|
||||
/**
|
||||
* @brief Sets the unit timer period for the eQEP module.
|
||||
* 0 = off, greater than zero sets the period.
|
||||
* @param pwmss_id Identifies which PWMSS module to set the eQEP unit timer for.
|
||||
* @param period The value in nanoseconds to set the unit timer period to.
|
||||
* @param timer_callback This is the user provided callback function that will
|
||||
* be called by the interrupt event handler on expiry of the unit timer. The
|
||||
* user can provide NULL if they don't require a call back.
|
||||
* @param user This is a pointer to a user provided data structure that will be
|
||||
* handed back as an argument to the timer callback. The driver does not touch
|
||||
* this value.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_ID if an invalid pwmss_id is
|
||||
* supplied.
|
||||
*/
|
||||
rtems_status_code beagle_eqep_set_timer_period(
|
||||
BBB_PWMSS pwmss_id,
|
||||
uint64_t period,
|
||||
bbb_eqep_timer_callback timer_callback,
|
||||
void* user
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* LIBBSP_ARM_BEAGLE_QEP_H */
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <bsp/gpio.h>
|
||||
#include <bsp/bbb-gpio.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/pwmss.h>
|
||||
#include <bsp/bbb-pwm.h>
|
||||
#include <bsp/beagleboneblack.h>
|
||||
|
||||
@@ -38,7 +39,7 @@
|
||||
* @param pwm_id It is the instance number of EPWM of pwm sub system.
|
||||
*
|
||||
* @return Base Address of respective pwm instant.
|
||||
*/
|
||||
*/
|
||||
static uint32_t select_pwm(BBB_PWMSS pwm_id)
|
||||
{
|
||||
uint32_t baseAddr=0;
|
||||
@@ -181,63 +182,6 @@ static bool pwm_clock_enable(BBB_PWMSS pwm_id)
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function configures the L3 and L4_PER system clocks.
|
||||
* It also configures the system clocks for the specified ePWMSS
|
||||
* instance.
|
||||
*
|
||||
* @param pwmss_id The instance number of ePWMSS whose system clocks
|
||||
* have to be configured.
|
||||
*
|
||||
* 'pwmss_id' can take one of the following values:
|
||||
* (0 <= pwmss_id <= 2)
|
||||
*
|
||||
* @return True if successful
|
||||
* False if Unsuccessful
|
||||
*/
|
||||
static bool pwmss_module_clk_config(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
bool is_valid = true;
|
||||
|
||||
if(pwmss_id == BBB_PWMSS0) {
|
||||
const uint32_t is_functional = AM335X_CM_PER_EPWMSS0_CLKCTRL_IDLEST_FUNC <<
|
||||
AM335X_CM_PER_EPWMSS0_CLKCTRL_IDLEST_SHIFT;
|
||||
const uint32_t clkctrl = AM335X_CM_PER_ADDR + AM335X_CM_PER_EPWMSS0_CLKCTRL;
|
||||
const uint32_t idle_bits = AM335X_CM_PER_EPWMSS0_CLKCTRL_IDLEST;
|
||||
const uint32_t is_enable = AM335X_CM_PER_EPWMSS0_CLKCTRL_MODULEMODE_ENABLE;
|
||||
const uint32_t module_mode = AM335X_CM_PER_EPWMSS0_CLKCTRL_MODULEMODE;
|
||||
|
||||
REG(clkctrl) |= is_enable;
|
||||
while((REG(clkctrl) & module_mode) != is_enable);
|
||||
while((REG(clkctrl) & idle_bits) != is_functional);
|
||||
}
|
||||
else if(pwmss_id == BBB_PWMSS1) {
|
||||
const uint32_t is_functional = AM335X_CM_PER_EPWMSS1_CLKCTRL_IDLEST_FUNC <<
|
||||
AM335X_CM_PER_EPWMSS1_CLKCTRL_IDLEST_SHIFT;
|
||||
const uint32_t clkctrl = AM335X_CM_PER_ADDR + AM335X_CM_PER_EPWMSS1_CLKCTRL;
|
||||
const uint32_t idle_bits = AM335X_CM_PER_EPWMSS1_CLKCTRL_IDLEST;
|
||||
const uint32_t is_enable = AM335X_CM_PER_EPWMSS1_CLKCTRL_MODULEMODE_ENABLE;
|
||||
const uint32_t module_mode = AM335X_CM_PER_EPWMSS1_CLKCTRL_MODULEMODE;
|
||||
|
||||
REG(clkctrl) |= is_enable;
|
||||
while((REG(clkctrl) & module_mode) != is_enable);
|
||||
while((REG(clkctrl) & idle_bits) != is_functional);
|
||||
} else if(pwmss_id == BBB_PWMSS2) {
|
||||
const uint32_t is_functional = AM335X_CM_PER_EPWMSS2_CLKCTRL_IDLEST_FUNC <<
|
||||
AM335X_CM_PER_EPWMSS2_CLKCTRL_IDLEST_SHIFT;
|
||||
const uint32_t clkctrl = AM335X_CM_PER_ADDR + AM335X_CM_PER_EPWMSS2_CLKCTRL;
|
||||
const uint32_t idle_bits = AM335X_CM_PER_EPWMSS2_CLKCTRL_IDLEST;
|
||||
const uint32_t is_enable = AM335X_CM_PER_EPWMSS2_CLKCTRL_MODULEMODE_ENABLE;
|
||||
const uint32_t module_mode = AM335X_CM_PER_EPWMSS2_CLKCTRL_MODULEMODE;
|
||||
|
||||
REG(clkctrl) |= is_enable;
|
||||
while((REG(clkctrl) & module_mode) != is_enable);
|
||||
while((REG(clkctrl) & idle_bits) != is_functional);
|
||||
} else
|
||||
is_valid = false;
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
bool beagle_pwm_init(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
const bool id_is_valid = pwmss_id < BBB_PWMSS_COUNT;
|
||||
|
||||
64
bsps/arm/beagle/pwmss/pwmss.c
Normal file
64
bsps/arm/beagle/pwmss/pwmss.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup arm_beagle
|
||||
*
|
||||
* @brief Support for eQEP for the BeagleBone Black.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright (c) 2020 James Fitzsimons <james.fitzsimons@gmail.com>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <libcpu/am335x.h>
|
||||
#include <stdio.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/pwmss.h>
|
||||
#include <bsp/beagleboneblack.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function configures the L3 and L4_PER system clocks.
|
||||
* It also configures the system clocks for the specified ePWMSS
|
||||
* instance.
|
||||
*
|
||||
* @param pwmss_id The instance number of ePWMSS whose system clocks
|
||||
* have to be configured.
|
||||
*
|
||||
* 'pwmss_id' can take one of the following values:
|
||||
* (0 <= pwmss_id <= 2)
|
||||
*
|
||||
* @return True if successful
|
||||
* False if Unsuccessful
|
||||
*/
|
||||
rtems_status_code pwmss_module_clk_config(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
uint32_t clkctrl;
|
||||
|
||||
/* calculate the address of the clock control register for the PWMSS
|
||||
* module we are configuring */
|
||||
if(pwmss_id == BBB_PWMSS0) {
|
||||
clkctrl = AM335X_CM_PER_ADDR + AM335X_CM_PER_EPWMSS0_CLKCTRL;
|
||||
} else if(pwmss_id == BBB_PWMSS1) {
|
||||
clkctrl = AM335X_CM_PER_ADDR + AM335X_CM_PER_EPWMSS1_CLKCTRL;
|
||||
} else if(pwmss_id == BBB_PWMSS2) {
|
||||
clkctrl = AM335X_CM_PER_ADDR + AM335X_CM_PER_EPWMSS2_CLKCTRL;
|
||||
}
|
||||
|
||||
/* when the module is functional the IDLEST bits (16 -17) of the
|
||||
* CM_PER_EPWMSSx_CLKCTRL register will be 0x0. */
|
||||
const uint32_t is_functional = 0x0;
|
||||
const uint32_t idle_bits = AM335X_CM_PER_EPWMSSx_CLKCTRL_IDLEST;
|
||||
const uint32_t is_enable = AM335X_CM_PER_EPWMSSx_CLKCTRL_MODULEMODE_ENABLE;
|
||||
const uint32_t module_mode = AM335X_CM_PER_EPWMSSx_CLKCTRL_MODULEMODE;
|
||||
|
||||
REG(clkctrl) |= is_enable;
|
||||
while((REG(clkctrl) & module_mode) != is_enable);
|
||||
while((REG(clkctrl) & idle_bits) != is_functional);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
445
bsps/arm/beagle/qep/qep.c
Normal file
445
bsps/arm/beagle/qep/qep.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup arm_beagle
|
||||
*
|
||||
* @brief Support for eQEP for the BeagleBone Black.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright (c) 2020 James Fitzsimons <james.fitzsimons@gmail.com>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <libcpu/am335x.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <bsp/gpio.h>
|
||||
#include <bsp/bbb-gpio.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/pwmss.h>
|
||||
#include <bsp/qep.h>
|
||||
#include <bsp/beagleboneblack.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Represents all the PWMSS QEP modules and their default values.
|
||||
*/
|
||||
static bbb_eqep bbb_eqep_table[ BBB_PWMSS_COUNT ] =
|
||||
{
|
||||
{
|
||||
.pwmss_id = BBB_PWMSS0,
|
||||
.mmio_base = AM335X_EQEP_0_REGS,
|
||||
.irq = AM335X_INT_eQEP0INT,
|
||||
.timer_callback = NULL,
|
||||
.user = NULL,
|
||||
.count_mode = QUADRATURE_COUNT,
|
||||
.quadrature_mode = ABSOLUTE,
|
||||
.invert_qa = 0,
|
||||
.invert_qb = 0,
|
||||
.invert_qi = 0,
|
||||
.invert_qs = 0,
|
||||
.swap_inputs = 0
|
||||
},
|
||||
{
|
||||
.pwmss_id = BBB_PWMSS1,
|
||||
.mmio_base = AM335X_EQEP_1_REGS,
|
||||
.irq = AM335X_INT_eQEP1INT,
|
||||
.timer_callback = NULL,
|
||||
.user = NULL,
|
||||
.count_mode = QUADRATURE_COUNT,
|
||||
.quadrature_mode = ABSOLUTE,
|
||||
.invert_qa = 0,
|
||||
.invert_qb = 0,
|
||||
.invert_qi = 0,
|
||||
.invert_qs = 0,
|
||||
.swap_inputs = 0
|
||||
},
|
||||
{
|
||||
.pwmss_id = BBB_PWMSS2,
|
||||
.mmio_base = AM335X_EQEP_2_REGS,
|
||||
.irq = AM335X_INT_eQEP2INT,
|
||||
.timer_callback = NULL,
|
||||
.user = NULL,
|
||||
.count_mode = QUADRATURE_COUNT,
|
||||
.quadrature_mode = ABSOLUTE,
|
||||
.invert_qa = 0,
|
||||
.invert_qb = 0,
|
||||
.invert_qi = 0,
|
||||
.invert_qs = 0,
|
||||
.swap_inputs = 0
|
||||
}
|
||||
};
|
||||
|
||||
/* eQEP Interrupt handler */
|
||||
static void beagle_eqep_irq_handler(void *arg)
|
||||
{
|
||||
uint16_t flags;
|
||||
int32_t position = 0;
|
||||
bbb_eqep* eqep = arg;
|
||||
|
||||
/* Use the interrupt register (QFLG) mask to determine what caused the
|
||||
* interrupt. */
|
||||
flags = REG16(eqep->mmio_base + AM335x_EQEP_QFLG) & AM335x_EQEP_QFLG_MASK;
|
||||
/* Check the interrupt source to see if it was a unit timer overflow */
|
||||
if (flags & AM335x_EQEP_QFLG_UTO && eqep->timer_callback != NULL) {
|
||||
/* Handle the unit timer overflow interrupt */
|
||||
position = beagle_qep_get_position(eqep->pwmss_id);
|
||||
eqep->timer_callback(eqep->pwmss_id, position, eqep->user);
|
||||
}
|
||||
|
||||
/* Clear interrupt flags (write back triggered flags to the clear register) */
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QCLR) = flags;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_init(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
uint16_t qdecctl;
|
||||
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
sc = pwmss_module_clk_config(eqep->pwmss_id);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
/* failed to successfully configure the PWMSS module clocks */
|
||||
return sc;
|
||||
}
|
||||
|
||||
/* This enables clock for EQEP module in PWMSS subsystem. */
|
||||
REG(eqep->mmio_base + AM335X_PWMSS_CLKCONFIG) |= AM335x_EQEP_CLK_EN;
|
||||
|
||||
/* Setup interrupt handler */
|
||||
sc = rtems_interrupt_handler_install(
|
||||
eqep->irq,
|
||||
NULL,
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
(rtems_interrupt_handler)beagle_eqep_irq_handler,
|
||||
(void*)eqep
|
||||
);
|
||||
|
||||
/* The QDECCTL register configures the QEP Decoder module. We use it to set */
|
||||
/* the count mode, input inversion, channel swaps, unit timer interrupt etc. */
|
||||
qdecctl = 0;
|
||||
if (eqep->count_mode <= 3) {
|
||||
qdecctl |= eqep->count_mode << 14;
|
||||
|
||||
/* If the count mode is UP_COUNT or DOWN_COUNT then only count on
|
||||
* the rising edge. QUADRATURE_COUNT and DIRECTION_COUNT count on
|
||||
* both edges. */
|
||||
if (eqep->count_mode >= 2) {
|
||||
qdecctl |= AM335x_EQEP_QDECCTL_XCR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Should we swap the cha and chb inputs */
|
||||
if (eqep->swap_inputs == 1) {
|
||||
qdecctl |= AM335x_EQEP_QDECCTL_SWAP;
|
||||
}
|
||||
/* Should we invert the qa input */
|
||||
if (eqep->invert_qa == 1) {
|
||||
qdecctl |= AM335x_EQEP_QDECCTL_QAP;
|
||||
}
|
||||
/* Should we invert the qb input */
|
||||
if (eqep->invert_qb == 1) {
|
||||
qdecctl |= AM335x_EQEP_QDECCTL_QBP;
|
||||
}
|
||||
/* Should we invert the index input */
|
||||
if (eqep->invert_qi == 1) {
|
||||
qdecctl |= AM335x_EQEP_QDECCTL_QIP;
|
||||
|
||||
}
|
||||
/* Should we invert the strobe input */
|
||||
if (eqep->invert_qs == 1) {
|
||||
qdecctl |= AM335x_EQEP_QDECCTL_QSP;
|
||||
}
|
||||
|
||||
/* Write the configured decoder control settings to the QDECCTL register */
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QDECCTL) = qdecctl;
|
||||
/* Set the position counter initialisation register */
|
||||
REG(eqep->mmio_base + AM335x_EQEP_QPOSINIT) = 0;
|
||||
/* initialise the maximum position counter value */
|
||||
REG(eqep->mmio_base + AM335x_EQEP_QPOSMAX) = ~0;
|
||||
/* initialise the position counter register */
|
||||
REG(eqep->mmio_base + AM335x_EQEP_QPOSCNT) = 0;
|
||||
/* Enable Unit Time Period interrupt. */
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEINT) |= AM335x_EQEP_QEINT_UTO;
|
||||
|
||||
/* The following bitmasks enable the eQEP module with:
|
||||
* - the unit timer disabled
|
||||
* - will latch the value in QPOSLAT to QPOSCNT upon unit timer overflow
|
||||
* - will latch QPOSILAT on index signal.
|
||||
* - Software initialisation of position counter (will be set to 0 because
|
||||
* QPOSINIT = 0).
|
||||
*/
|
||||
uint32_t value = AM335x_EQEP_QEPCTL_QCLM | AM335x_EQEP_QEPCTL_IEL |
|
||||
AM335x_EQEP_QEPCTL_PHEN | AM335x_EQEP_QEPCTL_SWI;
|
||||
|
||||
/* set the enable bit of the control register */
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = value;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_enable(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
/* set the enable bit of the control register */
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) |= AM335x_EQEP_QEPCTL_PHEN;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_disable(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
/* clear the enable bit of the control register */
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) &= ~AM335x_EQEP_QEPCTL_PHEN;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_pinmux_setup(
|
||||
bbb_qep_pin pin_no,
|
||||
BBB_PWMSS pwmss_id,
|
||||
bool pullup_enable
|
||||
)
|
||||
{
|
||||
rtems_status_code result = RTEMS_SUCCESSFUL;
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
/* enable internal pull up / pull down resistor in pull up mode, and set the
|
||||
* pin as an input. */
|
||||
uint32_t pin_mode = BBB_RXACTIVE;
|
||||
if ( pullup_enable ) {
|
||||
pin_mode |= BBB_PU_EN;
|
||||
}
|
||||
// The offsets from AM335X_PADCONF_BASE (44e10000) are named after the mode0 mux for that pin.
|
||||
if(pwmss_id == BBB_PWMSS0) {
|
||||
if (pin_no == BBB_P9_25_0_STROBE) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_AHCLKX) = pin_mode | BBB_MUXMODE(BBB_P9_25_MUX_QEP);
|
||||
} else if (pin_no == BBB_P9_27_0B_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_FSR) = pin_mode | BBB_MUXMODE(BBB_P9_27_MUX_QEP);
|
||||
} else if (pin_no == BBB_P9_41_0_IDX) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_AXR1) = pin_mode | BBB_MUXMODE(BBB_P9_41_MUX_QEP);
|
||||
} else if (pin_no == BBB_P9_42_0A_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_ACLKR) = pin_mode | BBB_MUXMODE(BBB_P9_42_MUX_QEP);
|
||||
} else {
|
||||
result = RTEMS_INTERNAL_ERROR;
|
||||
}
|
||||
} else if (pwmss_id == BBB_PWMSS1) {
|
||||
if (pin_no == BBB_P8_31_1_IDX) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA14) = pin_mode | BBB_MUXMODE(BBB_P8_31_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_32_1_STROBE) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA15) = pin_mode | BBB_MUXMODE(BBB_P8_32_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_33_1B_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA13) = pin_mode | BBB_MUXMODE(BBB_P8_33_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_35_1A_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA12) = pin_mode | BBB_MUXMODE(BBB_P8_35_MUX_QEP);
|
||||
} else {
|
||||
result = RTEMS_INTERNAL_ERROR;
|
||||
}
|
||||
} else if (pwmss_id == BBB_PWMSS2) {
|
||||
if (pin_no == BBB_P8_11_2B_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD13) = pin_mode | BBB_MUXMODE(BBB_P8_11_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_12_2A_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD12) = pin_mode | BBB_MUXMODE(BBB_P8_12_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_15_2_STROBE) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD15) = pin_mode | BBB_MUXMODE(BBB_P8_15_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_16_2_IDX) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD14) = pin_mode | BBB_MUXMODE(BBB_P8_16_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_39_2_IDX) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA6) = pin_mode | BBB_MUXMODE(BBB_P8_39_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_40_2_STROBE) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA7) = pin_mode | BBB_MUXMODE(BBB_P8_40_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_41_2A_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA4) = pin_mode | BBB_MUXMODE(BBB_P8_41_MUX_QEP);
|
||||
} else if (pin_no == BBB_P8_42_2B_IN) {
|
||||
REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA5) = pin_mode | BBB_MUXMODE(BBB_P8_42_MUX_QEP);
|
||||
} else {
|
||||
result = RTEMS_INTERNAL_ERROR;
|
||||
}
|
||||
} else {
|
||||
result = RTEMS_INTERNAL_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t beagle_qep_get_position(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
int32_t position = 0;
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return -1;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
if (eqep->quadrature_mode == ABSOLUTE) {
|
||||
/* return the current value of the QPOSCNT register */
|
||||
position = REG(eqep->mmio_base + AM335x_EQEP_QPOSCNT);
|
||||
} else if (eqep->quadrature_mode == RELATIVE) {
|
||||
/* return the latched value from the last unit timer interrupt */
|
||||
position = REG(eqep->mmio_base + AM335x_EQEP_QPOSLAT);
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_set_position(BBB_PWMSS pwmss_id, uint32_t position)
|
||||
{
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
/* setting the position only really makes sense in ABSOLUTE mode. */
|
||||
if (eqep->quadrature_mode == ABSOLUTE) {
|
||||
REG(eqep->mmio_base + AM335x_EQEP_QPOSCNT) = position;
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_set_count_mode(
|
||||
BBB_PWMSS pwmss_id,
|
||||
BBB_QEP_COUNT_MODE mode
|
||||
)
|
||||
{
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
eqep->count_mode = mode;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
BBB_QEP_COUNT_MODE beagle_qep_get_count_mode(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
return eqep->count_mode;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_qep_set_quadrature_mode(
|
||||
BBB_PWMSS pwmss_id,
|
||||
BBB_QEP_QUADRATURE_MODE mode
|
||||
)
|
||||
{
|
||||
uint16_t qepctl;
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
qepctl = REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL);
|
||||
|
||||
if (mode == ABSOLUTE) {
|
||||
/*
|
||||
* Disable the unit timer position reset
|
||||
*/
|
||||
qepctl &= ~AM335x_EQEP_QEPCTL_PCRM;
|
||||
|
||||
eqep->quadrature_mode = ABSOLUTE;
|
||||
} else if (mode == RELATIVE) {
|
||||
/*
|
||||
* enable the unit timer position reset
|
||||
*/
|
||||
qepctl |= AM335x_EQEP_QEPCTL_PCRM;
|
||||
|
||||
eqep->quadrature_mode = RELATIVE;
|
||||
}
|
||||
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = qepctl;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
BBB_QEP_QUADRATURE_MODE beagle_qep_get_quadrature_mode(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return -1;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
return eqep->quadrature_mode;
|
||||
}
|
||||
|
||||
|
||||
/* Function to read the period of the unit time event timer */
|
||||
uint32_t beagle_eqep_get_timer_period(BBB_PWMSS pwmss_id)
|
||||
{
|
||||
uint64_t period;
|
||||
uint32_t timer_period;
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return -1;
|
||||
}
|
||||
const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
/* Convert from counts per interrupt back into period_ns */
|
||||
period = REG(eqep->mmio_base + AM335x_EQEP_QUPRD);
|
||||
period = period * NANO_SEC_PER_SEC;
|
||||
timer_period = (uint32_t)(period / SYSCLKOUT);
|
||||
|
||||
return timer_period;
|
||||
}
|
||||
|
||||
rtems_status_code beagle_eqep_set_timer_period(
|
||||
BBB_PWMSS pwmss_id,
|
||||
uint64_t period,
|
||||
bbb_eqep_timer_callback timer_callback,
|
||||
void* user
|
||||
)
|
||||
{
|
||||
uint16_t qepctl;
|
||||
uint64_t tmp_period;
|
||||
uint32_t timer_period;
|
||||
if ( pwmss_id >= BBB_PWMSS_COUNT ) {
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
|
||||
|
||||
/* Disable the unit timer before modifying its period register */
|
||||
qepctl = readw(eqep->mmio_base + AM335x_EQEP_QEPCTL);
|
||||
qepctl &= ~(AM335x_EQEP_QEPCTL_UTE | AM335x_EQEP_QEPCTL_QCLM);
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = qepctl;
|
||||
|
||||
/* Zero the unit timer counter register */
|
||||
REG(eqep->mmio_base + AM335x_EQEP_QUTMR) = 0;
|
||||
|
||||
/* If the timer is enabled (a non-zero period has been passed) */
|
||||
if (period) {
|
||||
/* update the period */
|
||||
tmp_period = period * SYSCLKOUT;
|
||||
timer_period = (uint32_t)(tmp_period / NANO_SEC_PER_SEC);
|
||||
REG(eqep->mmio_base + AM335x_EQEP_QUPRD) = timer_period;
|
||||
|
||||
/* Enable unit timer, and latch QPOSLAT to QPOSCNT on timer expiration */
|
||||
qepctl |= AM335x_EQEP_QEPCTL_UTE | AM335x_EQEP_QEPCTL_QCLM;
|
||||
REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = qepctl;
|
||||
|
||||
/* attach the unit timer interrupt handler if one has been supplied */
|
||||
if (timer_callback != NULL) {
|
||||
eqep->timer_callback = timer_callback;
|
||||
}
|
||||
/* attach the user data if it has been provided */
|
||||
if (user != NULL) {
|
||||
eqep->user = user;
|
||||
}
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
@@ -77,9 +77,15 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/spi/spi.c
|
||||
# GPIO
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/gpio/bbb-gpio.c
|
||||
|
||||
#pwmss shared
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/pwmss/pwmss.c
|
||||
|
||||
#pwm
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/pwm/pwm.c
|
||||
|
||||
#qep
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/qep/qep.c
|
||||
|
||||
#RTC
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/rtc/rtc.c
|
||||
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/dev/rtc/rtc-support.c
|
||||
|
||||
@@ -19,7 +19,8 @@ install:
|
||||
- bsps/arm/beagle/include/bsp/beagleboneblack.h
|
||||
- bsps/arm/beagle/include/bsp/i2c.h
|
||||
- bsps/arm/beagle/include/bsp/irq.h
|
||||
- bsps/arm/beagle/include/bsp/spi.h
|
||||
- bsps/arm/beagle/include/bsp/pwmss.h
|
||||
- bsps/arm/beagle/include/bsp/qep.h
|
||||
- destination: ${BSP_LIBDIR}
|
||||
source:
|
||||
- bsps/arm/beagle/start/linkcmds
|
||||
@@ -31,6 +32,8 @@ source:
|
||||
- bsps/arm/beagle/i2c/bbb-i2c.c
|
||||
- bsps/arm/beagle/irq/irq.c
|
||||
- bsps/arm/beagle/pwm/pwm.c
|
||||
- bsps/arm/beagle/pwmss/pwmss.c
|
||||
- bsps/arm/beagle/qep/qep.c
|
||||
- bsps/arm/beagle/rtc/rtc.c
|
||||
- bsps/arm/beagle/spi/spi.c
|
||||
- bsps/arm/beagle/start/bspdebug.c
|
||||
|
||||
Reference in New Issue
Block a user