2020-07-14 09:07 PM
Hello,
I have developed an application which can dynamically detect source capabilities by reading the capabilities soon after a PD charger is plugged in. In order to renegotiate with the new PDO, I currently must issue a reset by writing to the RESET_CTRL register. Unfortunately, this approach causes VBUS to be lost momentarily, an undesirable side-effect.
From browsing ST's example application source code, I noticed the use of "PdMessage_SoftReset", a way to soft reset the PD negotiation using the PD protocol. Seems simple enough: write the soft reset message 0x0D to the TX_header register at address 0x51, then write the send PD message command 0x26 to the address 0x1A.
Unfortunately, I've had absolutely zero luck with this approach. I have tried with multiple different PD compliant chargers, neither of them renegotiate after issuing the soft reset message. I have also tried two separate STUSB4500 chips. I have tried writing the soft reset message as a single byte 0x0D, as well as writing it as a 2 bytes, 0x000D. I have only been successful using the register reset approach.
What could I be missing here?
Best,
Jeff
Solved! Go to Solution.
2020-07-22 11:29 PM
Hello,
I'm wondering wether the source takes into account the 2nd soft_reset and sends its source capa, when its PSRdy has not been sent. Can you please check on scope that after each soft_reset you got source_capa ?
For your application, I would suggest to follow the proposed code and wait for state PE_SNK_READY of PE_FSM, before to send Soft_reset.
Best regards
Nathalie
2020-07-20 07:52 AM
Hello
Could you please share your code and/or USBPD trace ?
Thanks
Best regards
Nathalie
2020-07-20 09:24 AM
Attached the relevant code here. Basically, I can read the source capabilities successfully, and my code selects the "optimal" pdo based desired user voltage/current parameters, writing it to the high priority PDO3 profile. I cannot get the renegotiation to this profile until I use the provided register "reset()" function provided in the code. It does work after that. However, I would like to use the function "send_pd_message()" with the parameter PD_SOFT_RESET to force the renegotiation. The writes are successful, but nothing seems to happen afterwards. Thanks for looking into this.
// STUSB4500 i2c address
#define STUSB_ADDR 0x28
// STUSB4500 registers
#define PORT_STATUS 0x0E
#define PRT_STATUS 0x16
#define CMD_CTRL 0x1A
#define RESET_CTRL 0x23
#define WHO_AM_I 0x2F
#define RX_BYTE_CNT 0x30
#define RX_HEADER 0x31
#define RX_DATA_OBJ 0x33
#define TX_HEADER 0x51
#define DPM_SNK_PDO1 0x85
// STUSB4500 masks/constants
#define STUSB4500_ID 0x25
#define STUSB4500B_ID 0x21
#define SW_RESET_ON 0x01
#define SW_RESET_OFF 0x00
#define ATTACH 0x01
#define PRT_MESSAGE_RECEIVED 0x04
#define SRC_CAPABILITIES_MSG 0x01
// Maximum number of source power profiles
#define MAX_SRC_PDOS 10
// PD protocol commands, see USB PD spec Table 6-3
#define PD_CMD 0x26
#define PD_GET_SRC_CAP 0x0007
#define PD_SOFT_RESET 0x000D
#define RESET_DELAY_MS 27
#define PLUG_TIMEOUT_MS 3000
#define RETRIEVE_TIMEOUT_MS 500
static bool send_pd_message(const uint16_t msg) {
return (
i2c_master_write_u16(STUSB_ADDR, TX_HEADER, msg) &&
i2c_master_write_u8(STUSB_ADDR, CMD_CTRL, PD_CMD));
}
static bool is_present(stusb4500_config_t* config) {
uint32_t time = config->get_ms();
uint8_t res;
do {
if (!i2c_master_read_u8(STUSB_ADDR, WHO_AM_I, &res)) return false;
if (config->get_ms() - time > RETRIEVE_TIMEOUT_MS) return false;
} while (res != STUSB4500_ID && res != STUSB4500B_ID);
return true;
}
static bool reset(stusb4500_config_t* config) {
// Enable software reset
if (!i2c_master_write_u8(STUSB_ADDR, RESET_CTRL, SW_RESET_ON)) return false;
// Wait for VBUS to discharge
uint32_t time = config->get_ms();
while ((uint32_t)(config->get_ms() - time) < RESET_DELAY_MS)
;
// Verify reset success
if (!is_present(config)) return false;
// Disable software reset
if (!i2c_master_write_u8(STUSB_ADDR, RESET_CTRL, SW_RESET_OFF)) return false;
return true;
}
// some other functions here
.....
//
bool stusb4500_negotiate(stusb4500_config_t* config, bool on_interrupt) {
// code to read header here
.....
// Read source capabilities
// WARNING: This must happen very soon after the previous code block is
// executed. The source will send an accept message which partially
// overwrites the source capabilities message. Use i2c clock >= 300 kHz
if (!i2c_master_read(
STUSB_ADDR,
RX_DATA_OBJ,
buffer,
HEADER_NUM_DATA_OBJECTS(header) * sizeof(stusb4500_pdo_t)))
return false;
// Find and load the optimal PDO, if any
if (!load_optimal_pdo(config, (stusb4500_pdo_t*)buffer, HEADER_NUM_DATA_OBJECTS(header)))
return false;
// Force a renegotiation
// NOTE: vbus will be momentarily lost
return reset(config);
}
2020-07-21 07:12 AM
Hello
Up to now I did not detect any failure on code you shared.
Can you please ensure that voltage but also current requested is below or equal to source PDO one ?
I attach a snapshot of trace done using the FW demo which we are proposing: sw reset is sent, then source exposes again its capabilities which allows stusb4500 to negociate a new PDO based on its settings.
Can you please share a PD trace ?
Best regards
Nathalie
2020-07-21 11:45 PM
I am certain that the requested voltage and current are equal to the source PDO. The code can only request a voltage and current that matches a source profile. I'm not sure how I can provide you with a PD trace. I do own an oscilloscope, but I do not own a USB/PD analyzer, and as far as I know I can't get that from the STUSB4500. Please let me know what I can do to further troubleshoot.
Best,
Jeff
2020-07-22 03:33 AM
2020-07-22 09:50 PM
I hooked up a scope to the CC pins, and was in fact seeing activity when sending the soft reset message. I noticed that the soft-reset message did in fact work, but only while debugging. To reiterate, my method of performing negotiation is:
After further investigation, I've determined that the method is only successful IF there is a >= 120ms delay between step 1 and 2. I'm glad that I have something working, but could you clarify what could be making this delay necessary?
2020-07-22 11:29 PM
Hello,
I'm wondering wether the source takes into account the 2nd soft_reset and sends its source capa, when its PSRdy has not been sent. Can you please check on scope that after each soft_reset you got source_capa ?
For your application, I would suggest to follow the proposed code and wait for state PE_SNK_READY of PE_FSM, before to send Soft_reset.
Best regards
Nathalie
2020-07-22 11:51 PM
I don't think it had anything to do with the second soft reset, as I said in the previous message, the delay was required between the initial soft reset and the PDO write. However, I do see your point and I replaced the delay with a loop to wait for the PE_SNK_READY state before writing the new PDO. This seems to have solved the problem. I can't thank you enough for your help, it's great to have this level of support in a community forum.
Best,
Jeff