How to use pd_phy api get EMCA message?

Announcements

Live Webinar: USB-C adoption. Simple & Cost-efficient solutions | April 18th @9am or 5pm CEST. Register now !

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
hysj_4827286
Level 2
Level 2
10 replies posted 5 replies posted First question asked

Now,I can use the API of  pd_phy_load_msg()and pd_phy_send_msg() send vdm message to EMCA,  but I can not get EMCA ACK message.

Actually,EMCA have been send GOODCRC msg and VDM ACK msg (that msg check by CY4500),however, the program does not generate the RX interrupt signal and enters the interrupt processing function(pdss_intr0_handler()),which mean I can‘t use pd_phy_get_rx_packet() to get EMCA ACK MSG;

There are things need to be clear that :

                                                        1. I have been invoke pd_prot_rx_en() to enable RX interrupt;

                                                        2. my test chip is CYPD4126

                                                        3. every time after sending VDM Discover ID message to EMCA, the program will generate TX interrupt (PDSS_INTR0_CRC_RX_TIMER_EXP),then invoke pdss_intr0_handler() to handle this interrupt ,I have no idea about why the TX interrupt  is generated;

this is my test code:​

             

static cc_state_t InitEmarkChannel(uint8_t port) {

    uint8_t eMarkCommCha = 2u;

    uint8_t eMarkVconnCha = 2u;

    cc_state_t cc_state;

   

    pd_typec_en_rp(port, CC_CHANNEL_1, RP_TERM_RP_CUR_DEF);

    pd_typec_en_rp(port, CC_CHANNEL_2, RP_TERM_RP_CUR_DEF);

    cc_state = pd_typec_get_cc_status(port);

    if (cc_state.cc[CC_CHANNEL_1] == RP_RA) {

        eMarkVconnCha = CC_CHANNEL_1;

        eMarkCommCha = CC_CHANNEL_2;

    } else if (cc_state.cc[CC_CHANNEL_2] == RP_RA) {

        eMarkVconnCha = CC_CHANNEL_2;

        eMarkCommCha = CC_CHANNEL_1;

    }

    (void)eMarkCommCha;

    if (eMarkVconnCha < 2u)  {

        pd_typec_dis_rp(port, eMarkCommCha);

        pd_typec_dis_rp(port, eMarkVconnCha);

        pd_typec_en_rp(port, eMarkCommCha, RP_TERM_RP_CUR_3A);

        pd_vconn_enable(port, eMarkVconnCha);

    }

    return cc_state;

}

#define GOODCRC_MSG_TYPE      (1u)

#define VMD_DEFINED_TYPE      (15u)

typedef union

{

    uint32_t val;

    struct MSG_HDR {

        uint32_t msg_type         : 5;//0:4 bit

        uint32_t port_data_role   : 1;// 5 bit

        uint32_t spec_rev         : 2;// 6:7 bit

        uint32_t port_pwr_role    : 1;//8 bit

        uint32_t msg_id           : 3;//9:11bit

        uint32_t num_doj          : 3;//12:14bit

        uint32_t extended         : 1;//15bit

        uint32_t extendheader     : 16;// 16:31 bit

    } msg_hdr;

} phy_msg_header_t;

static void pd_phy_task(uint8_t port, uint16_t svid, uint8_t vdm_cmd, uint8_t* msg_id, sop_t sop){

    uint8_t retries = 0;

    uint8_t doj_size = 1;

    phy_msg_header_t msg_header;

    pd_do_t msg_doj;

    msg_header.msg_hdr.extendheader = 0x0000;

    msg_header.msg_hdr.msg_type = VMD_DEFINED_TYPE;      // Vendor_Defined

    msg_header.msg_hdr.num_doj = 1;           // data object number(32 bits)

    msg_header.msg_hdr.port_data_role = 0;    // SOP* set 0

    msg_header.msg_hdr.port_pwr_role = 0;     // SOP: 0:UFP  1:DFP;SOP* is cable plug: 0 indicate DFP_UFP 1:cable

    msg_header.msg_hdr.spec_rev = 2;          // 2:spec_rev3 1:spec_rev2;

    msg_header.msg_hdr.msg_id = *msg_id;            // 0~7, increment after every send

    msg_header.msg_hdr.extended = 0;

    msg_doj.std_vdm_hdr.cmd = vdm_cmd;            //discover modes:3 discover ID:1  Discover SVIDs:2

    msg_doj.std_vdm_hdr.rsvd1 = 0;

    msg_doj.std_vdm_hdr.rsvd2 = 0;

    msg_doj.std_vdm_hdr.cmd_type = 0;

    msg_doj.std_vdm_hdr.obj_pos = 0;

    msg_doj.std_vdm_hdr.st_ver = 1;

    msg_doj.std_vdm_hdr.vdm_type = 1;

    msg_doj.std_vdm_hdr.svid = svid;

    if (!pd_phy_is_busy(port)) {

        pd_phy_load_msg(

                    port,

                    sop,

                    retries,

                    doj_size,

                    (uint32_t)msg_header.val,

                    false,

                    (uint32_t *)&msg_doj.val

        );

       pd_phy_send_msg(port);

        *msg_id = *msg_id + 1;

        if (*msg_id > 7) {

               *msg_id = 0;

        }

    }  

}

static void send_goodcrc(uint8_t port,  uint8_t msg_id, sop_t sop, uint32_t spec_rev) {

    uint8_t retries = 0;

    uint8_t doj_size = 0;

    phy_msg_header_t msg_header;

    pd_do_t msg_doj = {0} ;

    msg_header.msg_hdr.extendheader = 0x0000;      // not extend msg

    msg_header.msg_hdr.msg_type = GOODCRC_MSG_TYPE;               // goodcrc

    msg_header.msg_hdr.num_doj = 0;                // data object number(32 bits)

    msg_header.msg_hdr.port_data_role = 0;         // SOP* set 0

    msg_header.msg_hdr.port_pwr_role = 0;          // SOP: 0:UFP  1:DFP; SOP* is cable plug: 0<=>DFP_UFP  1<=>cable

    msg_header.msg_hdr.spec_rev = spec_rev;        // 2:spec_rev3 1:spec_rev2;

    msg_header.msg_hdr.msg_id = msg_id;            // 0~7, increment after every send

    msg_header.msg_hdr.extended = 0;

    if (!pd_phy_is_busy(port)) {

        pd_phy_load_msg(

                    port,

                    sop,

                    retries,

                    doj_size,

                    (uint32_t)msg_header.val,

                    false,

                    (uint32_t *)&msg_doj.val

        );       

       pd_phy_send_msg(port);

    }

}

#endif

#if 1

static pd_packet_extd_t pd_packet;

static uint8_t event_id;

static void pd_phy_cbk_func(uint8_t port, pd_phy_evt_t event){

    // PD_PHY_EVT_TX_MSG_COLLISION,        /**< Bus busy at message transmission. */

    // PD_PHY_EVT_TX_MSG_PHY_IDLE,         /**< Bus idle, ready for message transmission. */

    // PD_PHY_EVT_TX_MSG_FAILED,           /**< Message transmission was not successful. */

    // PD_PHY_EVT_TX_MSG_SUCCESS,          /**< Message transmission was successful. */

    // PD_PHY_EVT_TX_RST_COLLISION,        /**< Bus busy just before reset transmission. */

    // PD_PHY_EVT_TX_RST_SUCCESS,          /**< Reset transmission was successful. */

    // PD_PHY_EVT_RX_MSG,                  /**< Message received. */

    // PD_PHY_EVT_RX_MSG_CMPLT,            /**< Message received and GoodCRC sent aka collision type 3. */

    // PD_PHY_EVT_RX_RST,                  /**< Reset was received. */

    // PD_PHY_EVT_FRS_SIG_RCVD,            /**< FRS signal was received. */

    // PD_PHY_EVT_FRS_SIG_SENT,            /**< FRS signal was transmitted. */

    // PD_PHY_EVT_CRC_ERROR                /**< Message recieved with CRC error. */

        pd_packet_extd_t* rx_pd_packet = NULL;

        event_id = event;

        switch (event)

        {

        case PD_PHY_EVT_RX_MSG:

                rx_pd_packet = pd_phy_get_rx_packet(port);

                if (rx_pd_packet != NULL) {

                      memcpy(&pd_packet, rx_pd_packet, sizeof(pd_packet_extd_t)); 

                }

        break;

        case PD_PHY_EVT_TX_MSG_FAILED:

        break;

        case PD_PHY_EVT_TX_MSG_SUCCESS:

        break;

        default:

        break;

        }

}

#endif

int main()

{

    uint32_t conf_addr;

    uint8_t i;

    /* Enable this to delay the firmware execution under SWD connect. */

#ifdef BREAK_AT_MAIN

    uint8_t volatile x = 0;

    while(x==0);

#endif /* BREAK_AT_MAIN */

#if (CYDEV_BCLK__SYSCLK__MHZ == 48)

    /* Use the maximum number of flash access wait states when the CPU clock frequency is 48 MHz. */

    CPUSS_FLASH_CTL = 0x13;

#endif /* (CYDEV_BCLK__SYSCLK__MHZ == 48) */

#if CCG_FIRMWARE_APP_ONLY

    sys_set_device_mode (SYS_FW_MODE_FWIMAGE_1);

#else /* !CCG_FIRMWARE_APP_ONLY */

    if ((uint32_t)&base_version < CCG_FW1_CONFTABLE_MAX_ADDR)

    {

        sys_set_device_mode (SYS_FW_MODE_FWIMAGE_1);

    }

    else

    {

        sys_set_device_mode (SYS_FW_MODE_FWIMAGE_2);

    }

#endif /* CCG_FIRMWARE_APP_ONLY */

    /* Validate the signature and checksum of the configuration table. */

    conf_addr = (uint32_t)get_pd_config ();

    if ((boot_validate_configtable ((uint8_t *)conf_addr) != CCG_STAT_SUCCESS) ||

            (!app_validate_configtable_offsets()))

    {

#if CCG_FIRMWARE_APP_ONLY

        /* Can't do anything if config table is not valid. */

        while (1);

#else /* !CCG_FIRMWARE_APP_ONLY */

        /* Erase the firmware metadata so that this binary stops loading. */

        if (sys_get_device_mode() == SYS_FW_MODE_FWIMAGE_1)

        {

            flash_row_clear (CCG_IMG1_METADATA_ROW_NUM);

        }

        else

        {

            flash_row_clear (CCG_IMG2_METADATA_ROW_NUM);

        }

        /* Now reset the device. */

        CySoftwareReset ();

#endif /* CCG_FIRMWARE_APP_ONLY */

    }

    /*

     * Configure the FET type usage model. This should be modified only if

     * the board supports a different configuration. Wrong configuration

     * shall result in damage of the boards and attached devices. Leave it

     * to default configuration for working with standard cypress design.

     *

     * For CCG4, the default for PCTRL is active high and CCTRL is active low.

     */

    pd_hal_set_fet_drive(PD_FET_DR_ACTIVE_HIGH, PD_FET_DR_ACTIVE_LOW);

    /* Configure the ADC block and input used for VBus detach detection. */

    pd_hal_set_vbus_detach_params(APP_VBUS_DETACH_ADC_ID, APP_VBUS_DETACH_ADC_INPUT);

    system_init();

    /* Timer INIT has to be done first. */

    timer_init();

    /* Enable global interrupts */

    CyGlobalIntEnable;

#if RIDGE_SLAVE_ENABLE

    /* Initialize the Alpine-Ridge slave interface. */

    ridge_slave_init (RIDGE_SLAVE_SCB_INDEX, 0);

#endif /* RIDGE_SLAVE_ENABLE */

#if CCG_HPI_ENABLE

#if (DISABLE_I2C_ADDR_CONFIG == 0)

    /* Set the HPI slave address based on the state of the I2C_CFG pin. */

    get_hpi_slave_addr();

#endif /* (DISABLE_I2C_ADDR_CONFIG == 0) */

#if CCG_FIRMWARE_APP_ONLY

    /* Configure HPI for no-boot operation. */

    hpi_set_no_boot_mode (true);

#endif /* CCG_FIRMWARE_APP_ONLY */

    /* Set the flash sizes and bootloader size limits. */

    hpi_set_flash_params (CCG_FLASH_SIZE, CCG_FLASH_ROW_SIZE, CCG_LAST_FLASH_ROW_NUM + 1, CCG_BOOT_LOADER_LAST_ROW);

    /* Initialize the HPI interface. */

    hpi_init (HPI_SCB_INDEX);

    /* Update HPI registers with mode and version information. */

    update_hpi_regs ();

#endif /* CCG_HPI_ENABLE */

    /* Initialize the instrumentation related data structures. */

    instrumentation_init();

#if (MUX_INIT_DELAY_MS != 0)

    /* Specify the MUX enable delay value to be used. */

    dpm_update_mux_enable_wait_period(MUX_INIT_DELAY_MS);

#endif /* (MUX_INIT_DELAY_MS != 0) */

#if CCG_UCSI_ENABLE

    /* Initialize the UCSI interface */

    ucsi_init ();

#endif /* CCG_UCSI_ENABLE */

    /* Perform application level initialization. */

     app_init();

    /* Initialize the Device Policy Manager for each PD port on the device. */

    for (i = TYPEC_PORT_0_IDX; i < NO_OF_TYPEC_PORTS; i++)

    {

      // dpm_init (i, app_get_callback_ptr(i));

    }

     //  init pd hal

     for(i = TYPEC_PORT_0_IDX ; i < NO_OF_TYPEC_PORTS; i++)

     {

// for debug       

         pd_hal_init(i);

         pd_typec_init(i);

         pd_phy_init(i, pd_phy_cbk_func);

         pd_typec_start(i);

         pd_prot_rx_en(i);

     }

#if CCG_HPI_ENABLE

    /* Send a reset complete event to the EC. */

    hpi_send_fw_ready_event ();

    /* Wait until EC ready event has been received or 100 ms has elapsed. */

    for (i = 0; i < 100; i++)

    {

        hpi_task ();

        if (hpi_is_ec_ready ())

            break;

#if (CYDEV_BCLK__SYSCLK__MHZ == 48)

        /*

         * Using CyDelayCycles as CyDelay is leading to a 25% error.

         * The parameter used here assumes that CPU clock is running at 48 MHz.

         */

        CyDelayCycles (38400);

#else

        /*

         * Using CyDelayCycles as CyDelay is leading to a 25% error.

         * The parameter used here assumes that CPU clock is running at 24 MHz.

         */

        CyDelayCycles (19200);

#endif /* (CYDEV_BCLK__SYSCLK__MHZ == 48) */

    }

#endif /* CCG_HPI_ENABLE */

#if APP_FW_LED_ENABLE

    /* Configure the LED control GPIO as an output. */

    gpio_hsiom_set_config (FW_LED_GPIO_PORT_PIN, HSIOM_MODE_GPIO, GPIO_DM_STRONG, true);

    /* Start a timer that will blink the FW ACTIVE LED, if required. */

    timer_start (0, LED_TIMER_ID, LED_TIMER_PERIOD, led_timer_cb);

#endif /* APP_FW_LED_ENABLE */

    /* Start any timers or tasks associated with application instrumentation. */

    instrumentation_start();

    for (i = TYPEC_PORT_0_IDX ; i < NO_OF_TYPEC_PORTS; i++)

    {

#if CCG_HPI_ENABLE

        /* Start the DPM for the port only if it is enabled at the HPI level. It is possible that the port

           got disabled before we got here.

         */

        if ((hpi_get_port_enable () & (1 << i)) != 0)

#endif /* CCG_HPI_ENABLE */

        {

         // dpm_start (i);

        }

    }

        memset(&pd_packet, 0, sizeof(pd_packet_extd_t));

        event_id = 255;

    while (1)

    {

        /* Perform DPM, APP and HPI tasks. */

        for (i = TYPEC_PORT_0_IDX; i < NO_OF_TYPEC_PORTS; i++)

        {

            dpm_task (i);

            app_task (i);

            // for debug

            static uint32_t send_count = 0;

            static uint8_t msg_id = 0;

            static bool init_count[2] = {false, false};

            //pd_packet_extd_t pd_protocol_packet;

            if (init_count == false) {

//                cc_state_t cc_state;

//                cc_state = InitEmarkChannel(i);

//                init_count = true;

//                uint16_t cc1_2 = 0x0000;

//                cc1_2 =   cc_state.cc[CC_CHANNEL_1];

//                cc1_2 |=  (cc_state.cc[CC_CHANNEL_2] << 8);

//                CyDelayUs(2000);

//                pd_phy_task(i, cc1_2, 1);

                InitEmarkChannel(i);

                init_count = true;

                // pd_phy_task(i, 0xff00, 1, &msg_id);

            } else if (send_count == 1000) {

                cc_state_t cc_state = pd_typec_get_cc_status(i);

                (void)cc_state;

                pd_phy_task(i, 0xff00, 1, &msg_id, SOP_PRIME);

                //pd_dpm_send_vdm_msg(i, 0x1234, 1, SOP_PRIME);

                send_count = 0;

            } else if (send_count == 2500) {

                //pd_prot_send_ctrl_msg(i, SOP_PRIME, CTRL_MSG_GOOD_CRC);

               pd_phy_task(i, 0xff00, 2, &msg_id, SOP_PRIME);

            } else if (send_count == 3000) {

                pd_phy_task(i, 0xff00, 3, &msg_id, SOP_PRIME);

                send_count = 0;

            } else if (send_count == 4000) {

                send_goodcrc(i, msg_id, SOP_PRIME, 2);

                send_count = 0;

            }

       

            if (pd_packet.hdr.hdr.msg_type != 0) {

                        send_goodcrc(i, pd_packet.hdr.hdr.msg_id, SOP_PRIME, 2);

                        memset(&pd_packet, 0, sizeof(pd_packet_extd_t));

                        event_id = 255;

            } else if (event_id != 255) {

                        pd_phy_task(i, event_id, 2, &msg_id, SOP);

                        event_id = 255;

            }

       

            CyDelayUs(1000); //1ms

//            send_count++;   

#if CCG_HPI_ENABLE

            /* Handle any pending HPI commands. */

            hpi_task ();

#endif /* CCG_HPI_ENABLE */

#if CCG_UCSI_ENABLE

            /* Handle any pending UCSI commands. */

            ucsi_task ();

#endif /* CCG_UCSI_ENABLE */

            /* Perform tasks associated with instrumentation. */

            instrumentation_task();

        }

#if SYS_DEEPSLEEP_ENABLE

        /* If possible, enter sleep mode for power saving. */

        system_sleep();

#endif /* SYS_DEEPSLEEP_ENABLE */

    }

}

0 Likes
1 Solution

Hi, I have been fix the problem:

          I geuss pd phy default RX msg only for SOP msg, so I set  pd->rx_order_set_ctrl |=  EN_PRIME_SOP_DET_VAL,then I can see the RX msg which sent by EMCA!

View solution in original post

0 Likes
2 Replies
Abhilash_P
Moderator
Moderator
Moderator
50 likes received 500 replies posted 250 solutions authored

Hi,

   Can you please send me the code and the relevant logs where "pdss_intr0_handler()" is invoked.

Regards,

Abhilash P

0 Likes

Hi, I have been fix the problem:

          I geuss pd phy default RX msg only for SOP msg, so I set  pd->rx_order_set_ctrl |=  EN_PRIME_SOP_DET_VAL,then I can see the RX msg which sent by EMCA!

0 Likes