PD Buddy Sink Firmware
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

storage.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * PD Buddy - USB Power Delivery for everyone
  3. * Copyright (C) 2017 Clayton G. Hobbs <clay@lakeserv.net>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "storage.h"
  19. #include "chprintf.h"
  20. #include "pd.h"
  21. struct pdb_config *pdb_config_array = (struct pdb_config *) PDB_CONFIG_BASE;
  22. void pdb_config_print(BaseSequentialStream *chp, const struct pdb_config *cfg)
  23. {
  24. /* Print the status */
  25. chprintf(chp, "status: ");
  26. switch (cfg->status) {
  27. case PDB_CONFIG_STATUS_INVALID:
  28. chprintf(chp, "in");
  29. /* fall-through */
  30. case PDB_CONFIG_STATUS_VALID:
  31. chprintf(chp, "valid\r\n");
  32. break;
  33. case PDB_CONFIG_STATUS_EMPTY:
  34. chprintf(chp, "empty\r\n");
  35. /* Stop early because the rest of the information is meaningless in
  36. * this case. */
  37. return;
  38. default:
  39. chprintf(chp, "%04X\r\n", cfg->status);
  40. break;
  41. }
  42. /* Print the flags */
  43. chprintf(chp, "flags: ");
  44. if (cfg->flags == 0) {
  45. chprintf(chp, "(none)");
  46. }
  47. if (cfg->flags & PDB_CONFIG_FLAGS_GIVEBACK) {
  48. chprintf(chp, "GiveBack ");
  49. }
  50. if (cfg->flags & PDB_CONFIG_FLAGS_VAR_BAT) {
  51. chprintf(chp, "Var/Bat ");
  52. }
  53. chprintf(chp, "\r\n");
  54. /* Print voltages and current */
  55. chprintf(chp, "v: %d.%02d V\r\n", PD_PDV_V(cfg->v), PD_PDV_CV(cfg->v));
  56. chprintf(chp, "i: %d.%02d A\r\n", PD_PDI_A(cfg->i), PD_PDI_CA(cfg->i));
  57. if (cfg->flags & PDB_CONFIG_FLAGS_VAR_BAT) {
  58. chprintf(chp, "v_min: %d.%02d V\r\n", PD_PDV_V(cfg->v_min),
  59. PD_PDV_CV(cfg->v_min));
  60. chprintf(chp, "v_max: %d.%02d V\r\n", PD_PDV_V(cfg->v_max),
  61. PD_PDV_CV(cfg->v_max));
  62. }
  63. }
  64. /*
  65. * Unlock the flash interface
  66. */
  67. static void flash_unlock(void)
  68. {
  69. /* Wait till no operation is on going */
  70. while ((FLASH->SR & FLASH_SR_BSY) != 0) {
  71. /* Note: we might want a timeout here */
  72. }
  73. /* Check that the Flash is locked */
  74. if ((FLASH->CR & FLASH_CR_LOCK) != 0) {
  75. /* Perform unlock sequence */
  76. FLASH->KEYR = FLASH_KEY1;
  77. FLASH->KEYR = FLASH_KEY2;
  78. }
  79. }
  80. /*
  81. * Lock the flash interface
  82. */
  83. static void flash_lock(void)
  84. {
  85. /* Wait till no operation is on going */
  86. while ((FLASH->SR & FLASH_SR_BSY) != 0) {
  87. /* Note: we might want a timeout here */
  88. }
  89. /* Check that the Flash is unlocked */
  90. if ((FLASH->CR & FLASH_CR_LOCK) == 0) {
  91. /* Lock the flash */
  92. FLASH->CR |= FLASH_CR_LOCK;
  93. }
  94. }
  95. /*
  96. * Write one halfword to flash
  97. */
  98. static void flash_write_halfword(uint16_t *addr, uint16_t data)
  99. {
  100. /* Set the PG bit in the FLASH_CR register to enable programming */
  101. FLASH->CR |= FLASH_CR_PG;
  102. /* Perform the data write (half-word) at the desired address */
  103. *(__IO uint16_t*)(addr) = data;
  104. /* Wait until the BSY bit is reset in the FLASH_SR register */
  105. while ((FLASH->SR & FLASH_SR_BSY) != 0) {
  106. /* For robust implementation, add here time-out management */
  107. }
  108. /* Check the EOP flag in the FLASH_SR register */
  109. if ((FLASH->SR & FLASH_SR_EOP) != 0) {
  110. /* clear it by software by writing it at 1 */
  111. FLASH->SR = FLASH_SR_EOP;
  112. } else {
  113. /* Manage the error cases */
  114. }
  115. /* Reset the PG Bit to disable programming */
  116. FLASH->CR &= ~FLASH_CR_PG;
  117. }
  118. /*
  119. * Erase the configuration page, without any locking
  120. */
  121. static void flash_erase(void)
  122. {
  123. /* Set the PER bit in the FLASH_CR register to enable page erasing */
  124. FLASH->CR |= FLASH_CR_PER;
  125. /* Program the FLASH_AR register to select a page to erase */
  126. FLASH->AR = (int) pdb_config_array;
  127. /* Set the STRT bit in the FLASH_CR register to start the erasing */
  128. FLASH->CR |= FLASH_CR_STRT;
  129. /* Wait till no operation is on going */
  130. while ((FLASH->SR & FLASH_SR_BSY) != 0) {
  131. /* Note: we might want a timeout here */
  132. }
  133. /* Check the EOP flag in the FLASH_SR register */
  134. if ((FLASH->SR & FLASH_SR_EOP) != 0) {
  135. /* Clear EOP flag by software by writing EOP at 1 */
  136. FLASH->SR = FLASH_SR_EOP;
  137. } else {
  138. /* Manage the error cases */
  139. }
  140. /* Reset the PER Bit to disable the page erase */
  141. FLASH->CR &= ~FLASH_CR_PER;
  142. }
  143. void pdb_config_flash_erase(void)
  144. {
  145. /* Enter a critical zone */
  146. chSysLock();
  147. flash_unlock();
  148. /* Erase the flash page */
  149. flash_erase();
  150. flash_lock();
  151. /* Exit the critical zone */
  152. chSysUnlock();
  153. }
  154. void pdb_config_flash_update(const struct pdb_config *cfg)
  155. {
  156. /* Enter a critical zone */
  157. chSysLock();
  158. flash_unlock();
  159. /* If there is an old entry, invalidate it. */
  160. struct pdb_config *old = pdb_config_flash_read();
  161. if (old != NULL) {
  162. flash_write_halfword(&(old->status), PDB_CONFIG_STATUS_INVALID);
  163. }
  164. /* Find the first empty entry */
  165. struct pdb_config *empty = NULL;
  166. for (int i = 0; i < PDB_CONFIG_ARRAY_LEN; i++) {
  167. /* If we've found it, return it. */
  168. if (pdb_config_array[i].status == PDB_CONFIG_STATUS_EMPTY) {
  169. empty = &pdb_config_array[i];
  170. break;
  171. }
  172. }
  173. /* If empty is still NULL, the page is full. Erase it. */
  174. if (empty == NULL) {
  175. flash_erase();
  176. /* Write to the first element */
  177. empty = &pdb_config_array[0];
  178. }
  179. /* Write the new configuration */
  180. flash_write_halfword(&(empty->status), cfg->status);
  181. flash_write_halfword(&(empty->flags), cfg->flags);
  182. flash_write_halfword(&(empty->v), cfg->v);
  183. flash_write_halfword(&(empty->i), cfg->i);
  184. flash_write_halfword(&(empty->v_min), cfg->v_min);
  185. flash_write_halfword(&(empty->v_max), cfg->v_max);
  186. flash_lock();
  187. /* Exit the critical zone */
  188. chSysUnlock();
  189. }
  190. struct pdb_config *pdb_config_flash_read(void)
  191. {
  192. /* If the first element is empty, there is no valid structure. */
  193. if (pdb_config_array[0].status == PDB_CONFIG_STATUS_EMPTY) {
  194. return NULL;
  195. }
  196. /* Find the valid structure, if there is one. */
  197. for (int i = 0; i < PDB_CONFIG_ARRAY_LEN; i++) {
  198. /* If we've found it, return it. */
  199. if (pdb_config_array[i].status == PDB_CONFIG_STATUS_VALID) {
  200. return &pdb_config_array[i];
  201. }
  202. }
  203. /* If we got to the end, none of the structures is valid. */
  204. return NULL;
  205. }