

/**
 * main.c
 *
 * EQEP1 loopback test: quadrature signals are generated on GPIO pins and
 * fed back into EQEP1 through the X-BAR (no external wiring required).
 *
 * GPIO0(QA) / GPIO1(QB)  - quadrature outputs, 100 edges total,
 *                          direction reversed at edges 20/42/45/61
 * GPIO2(INDEX)           - index pulses inserted after edges
 *                          10/14/18/22/41/45/59/63, rising/falling alternately
 * GPIO3                  - spare GPIO output (held low)
 *
 * EQEP1 input sources (routed via X-BAR):
 *   QA    <- EPWMXBAR1 <- TRIP1   <- INPUTXBAR1 <- GPIO0
 *   QB    <- EPWMXBAR2 <- TRIP2   <- INPUTXBAR2 <- GPIO1
 *   INDEX <- EPWMXBAR3 <- TRIP3   <- INPUTXBAR3 <- GPIO2
 *
 * Config: quadrature mode, 2x resolution, position counter reset on each
 * index event, QFLG cleared via QCLR before each index rising edge.
 * Register status (QPOSCNT/QPOSILAT/QFLG/QEPSTS) is printed to the console
 * after every edge.
 */


#include "main.h"
#include <stdio.h>

int main(void)
{
    Device_init();

    EQEP_TEST();

    while(1)
    {}

}

void EQEP_TEST(void)
{
    //
    // Configure GPIO0-3 as GPIO outputs, initially low
    //
    GPIO_setPinConfig(GPIO_0_GPIO0);
    GPIO_setPinConfig(GPIO_1_GPIO1);
    GPIO_setPinConfig(GPIO_2_GPIO2);
    GPIO_setPinConfig(GPIO_3_GPIO3);

    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
    GPIO_writePin(0, 0);

    GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(1, GPIO_DIR_MODE_OUT);
    GPIO_writePin(1, 0);

    GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(2, GPIO_DIR_MODE_OUT);
    GPIO_writePin(2, 0);

    GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(3, GPIO_DIR_MODE_OUT);
    GPIO_writePin(3, 0);

    //
    // INPUTXBAR1-3 inputs select GPIO0-2 respectively
    //
    XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 0);
    XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT2, 1);
    XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT3, 2);

    //
    // EPWM X-BAR TRIP1-3 inputs select INPUTXBAR1-3 respectively
    //
    XBAR_setEPWMMuxConfig(XBAR_TRIP1, XBAR_EPWM_MUX01_INPUTXBAR1_INPUT1);
    XBAR_setEPWMMuxConfig(XBAR_TRIP2, XBAR_EPWM_MUX03_INPUTXBAR1_INPUT2);
    XBAR_setEPWMMuxConfig(XBAR_TRIP3, XBAR_EPWM_MUX05_INPUTXBAR1_INPUT3);

    XBAR_enableEPWMMux(XBAR_TRIP1, XBAR_MUX01);
    XBAR_enableEPWMMux(XBAR_TRIP2, XBAR_MUX03);
    XBAR_enableEPWMMux(XBAR_TRIP3, XBAR_MUX05);

    //
    // EQEP1 input source selection: QA←EPWMXBAR1, QB←EPWMXBAR2, INDEX←EPWMXBAR3
    //
    EQEP_SourceSelect srcSel = { EQEP_SOURCE_PWMXBAR1,
                                 EQEP_SOURCE_PWMXBAR2,
                                 EQEP_SOURCE_PWMXBAR3 };
    EQEP_selectSource(EQEP1_BASE, srcSel);

    //
    // QDECCTL[QIDIRE]=0: disable direction change during index
    //
    EQEP_disableDirectionChangeDuringIndex(EQEP1_BASE);

    //
    // EQEP1 quadrature counting mode, 2x resolution
    //
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_QUADRATURE |
                                      EQEP_CONFIG_2X_RESOLUTION |
                                      EQEP_CONFIG_NO_SWAP |
                                      EQEP_CONFIG_IGATE_DISABLE);

    //
    // Reset position counter on each Index event, max value 65535
    //
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_IDX, 65535);

    //
    // QEPCTL[IEL]=3: latch on index event marker
    //
    EQEP_setLatchMode(EQEP1_BASE,
                      EQEP_LATCH_SW_INDEX_MARKER | EQEP_LATCH_RISING_STROBE |
                      EQEP_LATCH_CNT_READ_BY_CPU);

    //
    // Enable EQEP1
    //
    EQEP_enableModule(EQEP1_BASE);

    //
    // Generate 100 consecutive quadrature edges via GPIO0(QA)/GPIO1(QB)
    // Default forward (A leads B by 90°); reverse direction at edges 20/42/45/61
    // Phase table: index = phase 0..3, value = QA<<1 | QB, i.e. (0,0),(1,0),(1,1),(0,1)
    //
    static const uint16_t abState[4] = { 0U, 2U, 3U, 1U };
    int16_t dir   = 1;   // +1 = forward (A leads B), -1 = reverse (B leads A)
    int16_t phase = 0;   // current phase, index into abState

    //
    // INDEX(GPIO2) edge insertion points: after edges 10/14/18/22/41/45/59/63
    // Insert rising/falling index edges alternately (1st/3rd/5th/7th rising, 2nd/4th/6th/8th falling)
    //
    static const uint16_t idxEdges[8] = { 10U, 14U, 18U, 22U, 41U, 45U, 59U, 63U };
    uint32_t idxCount = 0U;   // number of index edges inserted so far
    uint32_t idxLevel = 0U;   // current index (GPIO2) level (initially low)

    uint32_t i;
    for(i = 0; i < 100; i++)
    {
        //
        // Reverse direction at the specified edges (that edge is the first of the new direction)
        //
        if((i + 1 == 20) || (i + 1 == 42) || (i + 1 == 45) || (i + 1 == 61))
        {
            dir = -dir;
        }

        phase = (phase + dir + 4) % 4;

        GPIO_writePin(0, (abState[phase] >> 1) & 1U);   // QA level
        GPIO_writePin(1,  abState[phase]       & 1U);   // QB level

        DEVICE_DELAY_US(1);   // 1us delay between edges for reliable EQEP capture

        EQEP_PrintEdgeStatus(i + 1);   // print QA/QB levels and QPOSCNT/QPOSILAT/QFLG/QEPSTS for edge i+1

        //
        // Insert a rising or falling index edge after the specified edges (alternating)
        //
        if((idxCount < 8U) && ((i + 1U) == idxEdges[idxCount]))
        {
            idxLevel ^= 1U;   // 0→1 rising edge, 1→0 falling edge

            //
            // Before the index rising edge, clear all QFLG flags via the QCLR register
            // (QCLR clears bits written with 1; 0x1FFF covers QFLG bits 0-12)
            //
            if(idxLevel == 1U)
            {
                EQEP_clearInterruptStatus(EQEP1_BASE, 0x1FFFU);
                DEVICE_DELAY_US(1);

                printf("\r\n--- QCLR clear done (before INDEX RISING edge) ---\r\n");
                EQEP_PrintRegStatus();   // print register status after clearing
            }

            GPIO_writePin(2, idxLevel);
            DEVICE_DELAY_US(1);   // ensure reliable EQEP capture of the index event

            printf("\r\n--- INDEX %s edge after Edge %lu (GPIO2=%u) ---\r\n",
                   (idxLevel == 1U) ? "RISING" : "FALLING",
                   (unsigned long)(i + 1U), (unsigned)idxLevel);
            EQEP_PrintRegStatus();   // print register status after the index edge
            idxCount++;
        }
    }

}

//
// Print status for quadrature edge edgeNum: QA/QB levels, QPOSCNT, QPOSILAT,
// QFLG, QEPSTS (besides the raw values, print each bit name and value; reading QEPSTS clears its latched bits)
//
void EQEP_PrintEdgeStatus(uint32_t edgeNum)
{
    uint32_t qa = GPIO_readPin(0);   // QA (GPIO0) current level
    uint32_t qb = GPIO_readPin(1);   // QB (GPIO1) current level

    printf("\r\n--- Edge %lu: QA=%u, QB=%u ---\r\n",
           (unsigned long)edgeNum, (unsigned)qa, (unsigned)qb);
    EQEP_PrintRegStatus();
}

//
// Print EQEP1 register status: QPOSCNT, QPOSILAT, QFLG, QEPSTS
// (besides the raw values, print each bit name and value; reading QEPSTS clears its latched bits)
//
void EQEP_PrintRegStatus(void)
{
    uint32_t qposcnt    = EQEP_getPosition(EQEP1_BASE);
    uint32_t qposilat   = EQEP_getIndexPositionLatch(EQEP1_BASE);
    uint16_t qflg       = EQEP_getInterruptStatus(EQEP1_BASE);
    uint16_t qepsts     = EQEP_getStatus(EQEP1_BASE);

    printf("QPOSCNT  = 0x%08lX (%lu)\r\n", (unsigned long)qposcnt, (unsigned long)qposcnt);
    printf("QPOSILAT = 0x%08lX (%lu)\r\n", (unsigned long)qposilat, (unsigned long)qposilat);

    printf("QFLG     = 0x%04X\r\n", (unsigned)qflg);
    printf("  [ 0] INT   Global Int Flag        = %u\r\n", (unsigned)((qflg & EQEP_INT_GLOBAL) != 0U));
    printf("  [ 1] PCE   Pos Cnt Error          = %u\r\n", (unsigned)((qflg & EQEP_INT_POS_CNT_ERROR) != 0U));
    printf("  [ 2] PHE   Phase Error            = %u\r\n", (unsigned)((qflg & EQEP_INT_PHASE_ERROR) != 0U));
    printf("  [ 3] QDC   Dir Change             = %u\r\n", (unsigned)((qflg & EQEP_INT_DIR_CHANGE) != 0U));
    printf("  [ 4] WTO   Watchdog Timeout       = %u\r\n", (unsigned)((qflg & EQEP_INT_WATCHDOG) != 0U));
    printf("  [ 5] PCU   Pos Cnt Underflow      = %u\r\n", (unsigned)((qflg & EQEP_INT_UNDERFLOW) != 0U));
    printf("  [ 6] PCO   Pos Cnt Overflow       = %u\r\n", (unsigned)((qflg & EQEP_INT_OVERFLOW) != 0U));
    printf("  [ 7] PCR   Pos Cmp Ready          = %u\r\n", (unsigned)((qflg & EQEP_INT_POS_COMP_READY) != 0U));
    printf("  [ 8] PCM   Pos Cmp Match          = %u\r\n", (unsigned)((qflg & EQEP_INT_POS_COMP_MATCH) != 0U));
    printf("  [ 9] SEL   Strobe Evnt Latch      = %u\r\n", (unsigned)((qflg & EQEP_INT_STROBE_EVNT_LATCH) != 0U));
    printf("  [10] IEL   Index Evnt Latch       = %u\r\n", (unsigned)((qflg & EQEP_INT_INDEX_EVNT_LATCH) != 0U));
    printf("  [11] UTO   Unit Timeout           = %u\r\n", (unsigned)((qflg & EQEP_INT_UNIT_TIME_OUT) != 0U));
    printf("  [12] QMA   QMA Error              = %u\r\n", (unsigned)((qflg & EQEP_INT_QMA_ERROR) != 0U));

    printf("QEPSTS   = 0x%02X\r\n", (unsigned)qepsts);
    printf("  [ 0] PCEF  Pos Cnt Error Flag     = %u\r\n", (unsigned)((qepsts & EQEP_STS_POS_CNT_ERROR) != 0U));
    printf("  [ 1] FIMF  1st Index Marker Flag  = %u\r\n", (unsigned)((qepsts & EQEP_STS_1ST_IDX_FLAG) != 0U));
    printf("  [ 2] CDEF  Capture Dir Err Flag   = %u\r\n", (unsigned)((qepsts & EQEP_STS_CAP_DIR_ERROR) != 0U));
    printf("  [ 3] COEF  Capture Ovrflw Err Flg = %u\r\n", (unsigned)((qepsts & EQEP_STS_CAP_OVRFLW_ERROR) != 0U));
    printf("  [ 4] QDLF  Quad Dir Latch Flag    = %u\r\n", (unsigned)((qepsts & EQEP_STS_DIR_LATCH) != 0U));
    printf("  [ 5] QDF   Quad Dir Flag (1=CW)   = %u\r\n", (unsigned)((qepsts & EQEP_STS_DIR_FLAG) != 0U));
    printf("  [ 6] FIDF  Dir on 1st Index       = %u\r\n", (unsigned)((qepsts & EQEP_STS_DIR_ON_1ST_IDX) != 0U));
    printf("  [ 7] UPEV  Unit Pos Event Flag    = %u\r\n", (unsigned)((qepsts & EQEP_STS_UNIT_POS_EVNT) != 0U));
}
