From db86c3eb4f1a54a30ccfb1efc45c7f77b35475aa Mon Sep 17 00:00:00 2001 From: James Fitzsimons Date: Tue, 23 Feb 2021 21:18:39 +1300 Subject: bsps/beagle: Adding QEP driver support to BeagleBoneBlack BSP --- bsps/arm/beagle/headers.am | 2 + bsps/arm/beagle/include/bsp/bbb-pwm.h | 11 - bsps/arm/beagle/include/bsp/pwmss.h | 54 ++++ bsps/arm/beagle/include/bsp/qep.h | 382 +++++++++++++++++++++++++++ bsps/arm/beagle/pwm/pwm.c | 60 +---- bsps/arm/beagle/pwmss/pwmss.c | 64 +++++ bsps/arm/beagle/qep/qep.c | 445 ++++++++++++++++++++++++++++++++ c/src/lib/libbsp/arm/beagle/Makefile.am | 6 + spec/build/bsps/arm/beagle/obj.yml | 5 +- 9 files changed, 959 insertions(+), 70 deletions(-) create mode 100644 bsps/arm/beagle/include/bsp/pwmss.h create mode 100644 bsps/arm/beagle/include/bsp/qep.h create mode 100644 bsps/arm/beagle/pwmss/pwmss.c create mode 100644 bsps/arm/beagle/qep/qep.c diff --git a/bsps/arm/beagle/headers.am b/bsps/arm/beagle/headers.am index 4dc35f2e2a..e4a746b2e1 100644 --- a/bsps/arm/beagle/headers.am +++ b/bsps/arm/beagle/headers.am @@ -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 diff --git a/bsps/arm/beagle/include/bsp/bbb-pwm.h b/bsps/arm/beagle/include/bsp/bbb-pwm.h index cf5d6fe552..6fdba486be 100644 --- a/bsps/arm/beagle/include/bsp/bbb-pwm.h +++ b/bsps/arm/beagle/include/bsp/bbb-pwm.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, diff --git a/bsps/arm/beagle/include/bsp/pwmss.h b/bsps/arm/beagle/include/bsp/pwmss.h new file mode 100644 index 0000000000..3a9dcbb70a --- /dev/null +++ b/bsps/arm/beagle/include/bsp/pwmss.h @@ -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 + * + * 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 */ diff --git a/bsps/arm/beagle/include/bsp/qep.h b/bsps/arm/beagle/include/bsp/qep.h new file mode 100644 index 0000000000..fc086e3c80 --- /dev/null +++ b/bsps/arm/beagle/include/bsp/qep.h @@ -0,0 +1,382 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief eQEP (enhanced Quadrature Encoder Pulse) support API. + */ + +/** + * Copyright (c) 2020 James Fitzsimons + * + * 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 */ diff --git a/bsps/arm/beagle/pwm/pwm.c b/bsps/arm/beagle/pwm/pwm.c index 81ace1254e..4bd09293e8 100644 --- a/bsps/arm/beagle/pwm/pwm.c +++ b/bsps/arm/beagle/pwm/pwm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/bsps/arm/beagle/pwmss/pwmss.c b/bsps/arm/beagle/pwmss/pwmss.c new file mode 100644 index 0000000000..c4d36d8ae1 --- /dev/null +++ b/bsps/arm/beagle/pwmss/pwmss.c @@ -0,0 +1,64 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief Support for eQEP for the BeagleBone Black. + */ + +/** + * Copyright (c) 2020 James Fitzsimons + * + * 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 +#include +#include +#include +#include + + +/** + * @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; +} diff --git a/bsps/arm/beagle/qep/qep.c b/bsps/arm/beagle/qep/qep.c new file mode 100644 index 0000000000..34eb453258 --- /dev/null +++ b/bsps/arm/beagle/qep/qep.c @@ -0,0 +1,445 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief Support for eQEP for the BeagleBone Black. + */ + +/** + * Copyright (c) 2020 James Fitzsimons + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * @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; +} diff --git a/c/src/lib/libbsp/arm/beagle/Makefile.am b/c/src/lib/libbsp/arm/beagle/Makefile.am index 1be71b27ae..46e782bd64 100644 --- a/c/src/lib/libbsp/arm/beagle/Makefile.am +++ b/c/src/lib/libbsp/arm/beagle/Makefile.am @@ -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 diff --git a/spec/build/bsps/arm/beagle/obj.yml b/spec/build/bsps/arm/beagle/obj.yml index 904fbf1d15..908c188547 100644 --- a/spec/build/bsps/arm/beagle/obj.yml +++ b/spec/build/bsps/arm/beagle/obj.yml @@ -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 -- cgit v1.2.3