Advertisement
GyroDragona

stusb4500_flasher

Dec 15th, 2019
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 14.34 KB | None | 0 0
  1. // stusb4500_flasher.ino - flash STUSB4500 NVM with configuration
  2. // Ported to Arduino from https://github.com/usb-c/STUSB4500 and further configuration
  3. // builder implemented on top.
  4. //
  5. // 1. Connect to fabpide2 board as following:
  6. //
  7. //   Arduino   | fabpide2
  8. //   --------------------
  9. //   SDA         SDA
  10. //   SCL         SCL
  11. //   5v/3.3v     VCC
  12. //   5v/3.3v     VPP
  13. //   GND         GND
  14. //
  15. // SDA and SCL pins are defined further below by macros. They can be any
  16. // pin on the arduino as software I2C is used.
  17. //
  18. // 2. Set SDA_PIN & SCL_PIN to the pin number of the SDA and SCL on your board.
  19. // 3. Set SDA_PORT & SCL_PORT to the port name of the SDA and SCL pins on your board.
  20. //    * The default config is for Arduino Nano board.
  21. // 4. Set appropriate values for the configuration macros below.
  22. // 5. Upload the sketch and set serial monitor baud to 115200.
  23. // 6. Follow the prompt.
  24. //
  25. /////////////////////////////////////////////////////////////////
  26. // Config Macros
  27. /////////////////////////////////////////////////////////////////
  28. // * There are three PDOs (1, 2 and 3) each defining a voltage range and
  29. //   max current. The voltage is defined with 50mV resolution between
  30. //   5-20V and a lower and upper percentage range from 5%-20%. For
  31. //   instance, when configured with 12V with 5% lower and 20% upper
  32. //   threshold, supply voltages between 11.4-14.4V are accepted.
  33. //
  34. // * If PDO_COUNT is set to 3, PDO3 will be tried to match first. If
  35. //   supply doesn't support the range and/or max. current, PDO2 will be
  36. //   tried. If PDO2 cannot be satisfied, PDO 1 is tried like the other two
  37. //   only if PDO1_ENABLED is true.  Otherwise, the power path is disabled
  38. //   and no power is supplied to downstream.
  39. //
  40. // * If number of PDOs is set to 2 or 1, the matching starts at the
  41. //   corresponding PDO and goes down to 1, ignoring higher PDO profiles.
  42. //
  43. // * PDO1's voltage is 5V and cannot be changed. Max. current for all
  44. //   PDOs can be set to range 0.5-5A in at specific values. It can
  45. //   optionally be set to FLEX_I which can be defined on a more granular
  46. //   level.
  47. //
  48. // * Other config parameters are explained in further comments below.
  49. /////////////////////////////////////////////////////////////////
  50.  
  51. // Max. current - note increments change from 0.25A to 0.5A toward the
  52. // higher currents.
  53. #define CURRENT_FLEX 0
  54. #define CURRENT_0_50 1
  55. #define CURRENT_0_75 2
  56. #define CURRENT_1_00 3
  57. #define CURRENT_1_25 4
  58. #define CURRENT_1_50 5
  59. #define CURRENT_1_75 6
  60. #define CURRENT_2_00 7
  61. #define CURRENT_2_25 8
  62. #define CURRENT_2_50 9
  63. #define CURRENT_2_75 10
  64. #define CURRENT_3_00 11
  65. #define CURRENT_3_50 12
  66. #define CURRENT_4_00 13
  67. #define CURRENT_4_50 14
  68. #define CURRENT_5_00 15
  69.  
  70. // If enabled poll power source for supported current at set voltage and
  71. // pick highest supported current. When enabled set PDOx_CURRENT to
  72. // lowest current needed
  73. #define REQ_SRC_CURRENT false
  74.  
  75. // Flexible max. current value (0.005A resolution)
  76. #define FLEX_CURRENT 3.83
  77.  
  78. // Number of active PDO configs - between 1 and 3 inclusive.
  79. #define PDO_COUNT 2
  80.  
  81. // Define your power requirements below in order of priority.
  82. // PDOX_VOLTAGE_X_PERCENT can be whole numbers b/w 5 and 20 inclusive.
  83. // PDOX_VOLTAGE can be from 0-20V with 0.05V resolution.
  84. #define PDO3_VOLTAGE 20.00
  85. #define PDO3_VOLTAGE_LOWER_PERCENT 7
  86. #define PDO3_VOLTAGE_UPPER_PERCENT 9
  87. #define PDO3_CURRENT CURRENT_5_00
  88.  
  89. #define PDO2_VOLTAGE 15.00
  90. #define PDO2_VOLTAGE_LOWER_PERCENT 10
  91. #define PDO2_VOLTAGE_UPPER_PERCENT 10
  92. #define PDO2_CURRENT CURRENT_1_00
  93.  
  94. // PDO1's voltage is 5v and it cannot be changed.
  95. #define PDO1_CURRENT CURRENT_FLEX
  96. #define PDO1_VOLTAGE_UPPER_PERCENT 11
  97. #define PDO1_ENABLED false
  98.  
  99. // Consult datasheet for details.
  100. #define GPIO_FUNCTION_SW_CTRL_GPIO
  101. #define GPIO_FUNCTION_ERROR_RECOVERY
  102. #define GPIO_FUNCTION_DEBUG
  103. #define GPIO_FUNCTION_SINK_POWER
  104.  
  105. // Sets function of the GPIO pin.
  106. #define GPIO_FUNCTION GPIO_FUNCTION_SINK_POWER
  107.  
  108. // Discharge time in milliseconds between 84-1260ms inclusive.
  109. #define VBUS_TO_0V_DISCHARGE_TIME 1000
  110. // Discharge time in milliseconds between 24-360ms inclusive.
  111. #define VBUS_TO_LOWER_PDO_DISCHARGE_TIME 200
  112.  
  113. /////////////////////////////////////////////////////////////////
  114.  
  115. // Set to appropriate pin and port of your arduino board. SDA and SCL pins
  116. // need not be I2C pins of arduino as software I2C is used. Default values below
  117. // are for Arduino Nano.
  118. //
  119. // Pinout for current (default) configuration
  120. // Board   | Nano | Uno | Mega 2650
  121. // SDA pin |    4 |  A4 |        33
  122. // SCL pin |    5 |  A5 |        32
  123. //
  124. #define SDA_PIN 4
  125. #define SCL_PIN 5
  126. #define SDA_PORT PORTC
  127. #define SCL_PORT PORTC
  128.  
  129. // These sector values are derived from the config macros above.
  130. uint8_t Sector[5][8] = {
  131.   {0x00, 0x00, 0xB0, 0xAA, 0x00, 0x45, 0x00, 0x00},
  132.   {
  133.     0x10,
  134.     0x40,
  135.     0x00 | ((VBUS_TO_0V_DISCHARGE_TIME / 84) << 4) | (VBUS_TO_LOWER_PDO_DISCHARGE_TIME / 24),
  136.     0x1C,
  137.     0xFF,
  138.     0x01,
  139.     0x3C,
  140.     0xDF
  141.   },
  142.   {0x02, 0x40, 0x0F, 0x00, 0x32, 0x00, 0xFC, 0xF1},
  143.   {
  144.     0x00,
  145.     0x19,
  146.     0x00 | (PDO1_CURRENT << 4) | (PDO_COUNT << 1),
  147.     0x0F | ((PDO1_VOLTAGE_UPPER_PERCENT - 5) << 4),
  148.     0x00 | (PDO2_CURRENT) | ((PDO2_VOLTAGE_LOWER_PERCENT - 5) << 4),
  149.     0x00 | (PDO3_CURRENT << 4) | (PDO2_VOLTAGE_UPPER_PERCENT - 5),
  150.     0x00 | ((PDO3_VOLTAGE_UPPER_PERCENT - 5) << 4) | (PDO3_VOLTAGE_LOWER_PERCENT - 5),
  151.     0x00
  152.   },
  153.   {
  154.     0x00 | ((int)(PDO2_VOLTAGE * 20) & 0b11) << 6,
  155.     0x00 | ((int)(PDO2_VOLTAGE * 20) >> 2),
  156.     0x90 | ((int)(PDO3_VOLTAGE * 20) & 0xFF),
  157.     0x00 | (((int)(FLEX_CURRENT * 200) & 0b1111111) << 1) | ((int)(PDO3_VOLTAGE * 20) >> 8),
  158.     0x40 | ((int)(FLEX_CURRENT * 200) >> 7),
  159.     0x00,
  160.     0x40 | (PDO1_ENABLED ? 0 : 8) | (REQ_SRC_CURRENT ? 16 : 0),
  161.     0xFB
  162.   }
  163. };
  164.  
  165. #include <SoftWire.h>
  166.  
  167. #define FTP_CUST_PASSWORD_REG 0x95
  168. #define FTP_CUST_PASSWORD 0x47
  169. #define FTP_CTRL_0 0x96
  170. #define FTP_CUST_PWR 0x80
  171. #define FTP_CUST_RST_N 0x40
  172. #define FTP_CUST_REQ 0x10
  173. #define FTP_CUST_SECT 0x07
  174. #define FTP_CTRL_1 0x97
  175. #define FTP_CUST_SER 0xF8
  176. #define FTP_CUST_OPCODE 0x07
  177. #define RW_BUFFER 0x53
  178.  
  179. #define READ 0x00
  180. #define WRITE_PL 0x01
  181. #define WRITE_SER 0x02
  182. #define READ_PL 0x03
  183. #define READ_SER 0x04
  184. #define ERASE_SECTOR 0x05
  185. #define PROG_SECTOR 0x06
  186. #define SOFT_PROG_SECTOR 0x07
  187.  
  188. #define SECTOR_0 0x01
  189. #define SECTOR_1 0x02
  190. #define SECTOR_2 0x04
  191. #define SECTOR_3 0x08
  192. #define SECTOR_4 0x10
  193.  
  194. #define I2C_ADDRESS 0x28
  195.  
  196. #define DEBUG
  197.  
  198. SoftWire Wire = SoftWire();
  199.  
  200. void setup() {
  201.   Wire.begin();
  202.   Serial.begin(115200);
  203.  
  204. #ifdef DEBUG
  205.   for (int i = 0; i < 5; i++) {
  206.     for (int j = 0; j < 8; j++) {
  207.       printHex(Sector[i][j]);
  208.       Serial.print("\t");
  209.     }
  210.     Serial.println();
  211.   }
  212. #endif
  213. }
  214.  
  215. void loop() {
  216.   uint8_t buf[40];
  217.  
  218.   delay(1000);
  219.   Serial.println();
  220.   Serial.println("Press 'f' to flash the configuration ...");
  221.   while(!Serial.available() || Serial.read() != 'f');
  222.   Serial.println("Flashing - hang on ...");
  223.  
  224.   if (nvm_flash() != 0) {
  225.     Serial.println("FAILED flashing :(");
  226.     return;
  227.   }
  228.  
  229.   Serial.println("Verifying - hang on some more ...");
  230.   if (nvmRead(buf) != 0) {
  231.     Serial.println("Failed to read the flash :(");
  232.     return;
  233.   }
  234.   for (int i = 0; i < 5; i++) {
  235.     if (!verifySector(Sector[i], &buf[8 * i])) {
  236.       Serial.println("Verification failed :(");
  237.       return;
  238.     }
  239.   }
  240.   Serial.println("All done! Yayyyy! :)");
  241. }
  242.  
  243. bool verifySector(uint8_t* target, uint8_t* actual) {
  244.   for (int i = 0; i < 8; i++) {
  245.     if (actual[i] != target[i]) {
  246.       return false;
  247.     }
  248.   }
  249.   return true;
  250. }
  251.  
  252. int chipWrite(uint8_t reg, uint8_t* data, uint8_t len) {
  253.   Wire.beginTransmission((uint8_t) I2C_ADDRESS);
  254.   if (Wire.write(reg) != 1) {
  255.     return 1;
  256.   }
  257.   if (Wire.write(data, len) != len) {
  258.     return 1;
  259.   }
  260.   int endStatus = Wire.endTransmission(true);
  261.   if (endStatus != 0) {
  262.     Serial.print("chipWrite end tx failed (");
  263.     Serial.print(endStatus, HEX);
  264.     Serial.println(")");
  265.     return 1;
  266.   }
  267.   return 0;
  268. }
  269.  
  270. int chipRead(uint8_t reg, uint8_t* buf, uint8_t len) {
  271.   Wire.beginTransmission((uint8_t) I2C_ADDRESS);
  272.   if (Wire.write((uint8_t) reg) != 1) {
  273.     return 1;
  274.   }
  275.   if (Wire.endTransmission(false) != 0) {
  276.     return 1;
  277.   }
  278.   Wire.requestFrom((uint8_t) I2C_ADDRESS, (uint8_t) len, (uint8_t) true);
  279.   for (int i = 0; i < len; i++) {
  280.     while (!Wire.available());
  281.     buf[i] = Wire.read();
  282.   }
  283.   return 0;
  284. }
  285.  
  286. int enterNVMReadMode() {
  287.   uint8_t buf[2];
  288.   buf[0] = FTP_CUST_PASSWORD;
  289.   if (chipWrite(FTP_CUST_PASSWORD_REG, buf, 1) != 0) {
  290.     Serial.println("Failed to write customer password");
  291.     return 1;
  292.   }
  293.   buf[0] = 0;
  294.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0) {
  295.     Serial.println("Failed to reset NVM internal controller");
  296.     return 1;
  297.   }
  298.   buf[0] = FTP_CUST_PWR | FTP_CUST_RST_N;
  299.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0) {
  300.     Serial.println("Failed to set PWR and RST_N bits");
  301.     return 1;
  302.   }
  303.   return 0;
  304. }
  305.  
  306. int enterNVMWriteMode(uint8_t erasedSector) {
  307.   uint8_t buf[2];
  308.  
  309.   buf[0] = FTP_CUST_PASSWORD;
  310.   if (chipWrite(FTP_CUST_PASSWORD_REG, buf, 1) != 0 ) {
  311.     Serial.println("Failed to set user password");
  312.     return 1;
  313.   }
  314.  
  315.   buf[0] = 0 ;
  316.   if (chipWrite(RW_BUFFER, buf, 1) != 0) {
  317.     Serial.println("Failed to set null for partial erase feature");
  318.     return 1;
  319.   }
  320.  
  321.   buf[0] = 0;
  322.   if (chipWrite(FTP_CTRL_0,buf,1) != 0 ) {
  323.     Serial.println("Failed to reset NVM controller");
  324.     return 1;
  325.   }
  326.  
  327.   buf[0] = FTP_CUST_PWR | FTP_CUST_RST_N;
  328.   if (chipWrite(FTP_CTRL_0,buf,1) != 0) {
  329.     Serial.println("Failed to set PWR and RST_N bits");
  330.     return 1;
  331.   }
  332.  
  333.  
  334.   buf[0] = ((erasedSector << 3) & FTP_CUST_SER) | ( WRITE_SER & FTP_CUST_OPCODE) ;
  335.   if (chipWrite(FTP_CTRL_1, buf, 1) != 0) {
  336.     Serial.println("Failed to write SER opcode");
  337.     return 1;
  338.   }
  339.  
  340.   buf[0] = FTP_CUST_PWR | FTP_CUST_RST_N | FTP_CUST_REQ ;
  341.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0 ) {
  342.     Serial.println("Failed to write SER optcode");
  343.     return 1;
  344.   }
  345.  
  346.   do {
  347.     if (chipRead(FTP_CTRL_0, buf, 1) != 0 ) {
  348.       Serial.println("Failed to wait for execution");
  349.       return 1;
  350.     }
  351.   } while(buf[0] & FTP_CUST_REQ);
  352.  
  353.   buf[0] = SOFT_PROG_SECTOR & FTP_CUST_OPCODE;
  354.   if (chipWrite(FTP_CTRL_1, buf, 1) != 0 ) {
  355.     Serial.println("Failed to set soft prog opcode");
  356.     return 1;
  357.   }
  358.  
  359.   buf[0] = FTP_CUST_PWR | FTP_CUST_RST_N | FTP_CUST_REQ ;
  360.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0 ) {
  361.     Serial.println("Failed to load soft prog opcode");
  362.     return 1;
  363.   }
  364.  
  365.   do {
  366.     if (chipRead(FTP_CTRL_0, buf, 1) != 0 ) {
  367.       Serial.println("Failed waiting for execution");
  368.       return 1;
  369.     }
  370.   } while(buf[0] & FTP_CUST_REQ);
  371.  
  372.   buf[0] = ERASE_SECTOR & FTP_CUST_OPCODE;
  373.   if (chipWrite(FTP_CTRL_1, buf, 1) != 0) {
  374.     Serial.println("Failed to set erase sector opcode");
  375.     return 1;
  376.   }
  377.  
  378.   buf[0] = FTP_CUST_PWR | FTP_CUST_RST_N | FTP_CUST_REQ ;
  379.   if (chipWrite(FTP_CTRL_0, buf, 1)  != 0) {
  380.     Serial.println("Failed to load erase sectors opcode");
  381.     return 1;
  382.   }
  383.  
  384.   do {
  385.     if ( chipRead(FTP_CTRL_0, buf, 1) != 0 ) {
  386.       Serial.println("Failed waiting for execution");
  387.       return 1;
  388.     }
  389.   } while(buf[0] & FTP_CUST_REQ);
  390.  
  391.   return 0;
  392. }
  393.  
  394. int writeNVMSector(uint8_t SectorNum, uint8_t *SectorData)
  395. {
  396.   uint8_t Buffer[2];
  397.  
  398.   if (chipWrite(RW_BUFFER, SectorData, 8) != 0) {
  399.     return -1;
  400.   }
  401.  
  402.   Buffer[0] = FTP_CUST_PWR | FTP_CUST_RST_N;
  403.   if (chipWrite(FTP_CTRL_0, Buffer, 1) != 0) {
  404.     return -1;
  405.   }
  406.  
  407.   Buffer[0] = WRITE_PL & FTP_CUST_OPCODE;
  408.   if (chipWrite(FTP_CTRL_1, Buffer, 1) != 0) {
  409.     return -1;
  410.   }
  411.  
  412.   Buffer[0] = FTP_CUST_PWR |FTP_CUST_RST_N | FTP_CUST_REQ;
  413.   if (chipWrite(FTP_CTRL_0, Buffer, 1) != 0) {
  414.     return -1;
  415.   }
  416.  
  417.   do {
  418.     if ( chipRead(FTP_CTRL_0,Buffer,1) != 0 )return -1;
  419.   } while(Buffer[0] & FTP_CUST_REQ) ;
  420.  
  421.   Buffer[0] = PROG_SECTOR & FTP_CUST_OPCODE;
  422.   if (chipWrite(FTP_CTRL_1, Buffer, 1) != 0) {
  423.     return -1;
  424.   }
  425.  
  426.   Buffer[0] = (SectorNum & FTP_CUST_SECT) | FTP_CUST_PWR | FTP_CUST_RST_N | FTP_CUST_REQ;
  427.   if (chipWrite(FTP_CTRL_0, Buffer, 1) != 0) {
  428.     return -1;
  429.   }
  430.  
  431.   do {
  432.       if ( chipRead(FTP_CTRL_0,Buffer,1) != 0 )return -1;
  433.   } while(Buffer[0] & FTP_CUST_REQ);
  434.  
  435.   return 0;
  436. }
  437.  
  438. int nvm_flash() {
  439.   if (enterNVMWriteMode(SECTOR_0 | SECTOR_1 | SECTOR_2 | SECTOR_3 | SECTOR_4) != 0) {
  440.     return -1;
  441.   }
  442.   for (int i = 0; i < 5; i++) {
  443.     if (writeNVMSector(i, Sector[i]) != 0) {
  444.       return -1;
  445.     }
  446.   }
  447.   if (exitNVMMode() != 0) {
  448.     return -1;
  449.   }
  450.   return 0;
  451. }
  452.  
  453. int exitNVMMode() {
  454.   uint8_t buf[2];
  455.   buf[0] = FTP_CUST_RST_N;
  456.   buf[1] = 0;
  457.   if (chipWrite(FTP_CTRL_0, buf, 2) != 0) {
  458.     Serial.println("Failed to exit NVM mode");
  459.     return 1;
  460.   }
  461.   buf[0] = 0;
  462.   if (chipWrite(FTP_CUST_PASSWORD_REG, buf, 1) != 0) {
  463.     Serial.println("Failed to reset customer password");
  464.     return 1;
  465.   }
  466.   return 0;
  467. }
  468.  
  469. int readNVMSector(uint8_t num, uint8_t* data) {
  470.   uint8_t buf[2];
  471.   buf[0] = FTP_CUST_PWR | FTP_CUST_RST_N;
  472.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0) {
  473.     Serial.println("Failed to set PWR and RST_N bits");
  474.     return 1;
  475.   }
  476.   buf[0]= (READ & FTP_CUST_OPCODE);
  477.   if (chipWrite(FTP_CTRL_1, buf, 1) != 0) {
  478.     Serial.println("Failed to set read sectors opcode");
  479.     return 1;
  480.   }
  481.  
  482.   buf[0] = (num & FTP_CUST_SECT) | FTP_CUST_PWR | FTP_CUST_RST_N | FTP_CUST_REQ;
  483.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0 ) {
  484.     Serial.println("Failed to read sectors opcode");
  485.     return 1;
  486.   }
  487.   do {
  488.     if (chipRead(FTP_CTRL_0, buf, 1) != 0) {
  489.       Serial.println("Failed waiting for execution");
  490.       return 1;
  491.     }
  492.   } while(buf[0] & FTP_CUST_REQ);
  493.  
  494.   if (chipRead(RW_BUFFER, &data[0], 8) != 0) {
  495.     Serial.println("NVM read failed");
  496.     return 1;
  497.   }
  498.  
  499.   buf[0] = 0;
  500.   if (chipWrite(FTP_CTRL_0, buf, 1) != 0) {
  501.     Serial.println("Resetting controller failed");
  502.     return 1;
  503.   }
  504.  
  505.   return 0;
  506. }
  507.  
  508. int nvmRead(uint8_t* out) {
  509.   if (enterNVMReadMode() != 0) {
  510.     Serial.println("Failed to enter NVM read mode");
  511.     return 1;
  512.   }
  513.   for (int i = 0; i < 5; i++) {
  514.     if (readNVMSector(i, out + (i * 8)) != 0) {
  515.       Serial.println("Failed to read sector");
  516.       return 1;
  517.     }
  518.   }
  519.   if (exitNVMMode() != 0) {
  520.     Serial.println("Failed to exit NVM read mode");
  521.     return 1;
  522.   }
  523.   return 0;
  524. }
  525.  
  526. void printHex(int v) {
  527.   char tmp[10];
  528.   sprintf(tmp, "0x%.2X", v);
  529.   Serial.print(tmp);
  530. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement