Line data Source code
1 : // --------------------------------------------------------------------------- 2 : // USB EPROM/Flash Programmer 3 : // 4 : // Copyright (2022) Robson Martins 5 : // 6 : // This work is licensed under a Creative Commons Attribution-NonCommercial- 7 : // ShareAlike 4.0 International License. 8 : // --------------------------------------------------------------------------- 9 : /** 10 : * @ingroup Firmware 11 : * @file modules/vgenerator.cpp 12 : * @brief Implementation of the Voltage Generator Classes. 13 : * 14 : * @author Robson Martins (https://www.robsonmartins.com) 15 : */ 16 : // --------------------------------------------------------------------------- 17 : 18 : #include <cstring> 19 : 20 : #include "modules/vgenerator.hpp" 21 : #include "config.hpp" 22 : #include "hal/flash.hpp" 23 : 24 : // --------------------------------------------------------------------------- 25 : 26 : void second_core(MultiCore& core); // NOLINT 27 : 28 : // --------------------------------------------------------------------------- 29 : 30 82 : VddConfig::VddConfig() : Dc2DcConfig(), ctrlPin(0xFF), onVppPin(0xFF) {} 31 : 32 8 : VddConfig& VddConfig::operator=(const VddConfig& src) { 33 8 : Dc2DcConfig::operator=(src); 34 8 : this->ctrlPin = src.ctrlPin; 35 8 : this->onVppPin = src.onVppPin; 36 8 : return *this; 37 : } 38 : 39 3 : bool operator==(const VddConfig& a, const VddConfig& b) { 40 3 : return (operator==((Dc2DcConfig&)a, (Dc2DcConfig&)b) && 41 3 : a.ctrlPin == b.ctrlPin && a.onVppPin == b.onVppPin); 42 : } 43 : 44 : // --------------------------------------------------------------------------- 45 : 46 82 : VppConfig::VppConfig() 47 : : Dc2DcConfig(), 48 82 : ctrlPin(0xFF), 49 82 : vcSinPin(0xFF), 50 82 : vcClkPin(0xFF), 51 82 : vcClrPin(0xFF), 52 82 : vcRckPin(0xFF) {} 53 : 54 8 : VppConfig& VppConfig::operator=(const VppConfig& src) { 55 8 : Dc2DcConfig::operator=(src); 56 8 : this->ctrlPin = src.ctrlPin; 57 8 : this->vcSinPin = src.vcSinPin; 58 8 : this->vcClkPin = src.vcClkPin; 59 8 : this->vcClrPin = src.vcClrPin; 60 8 : this->vcRckPin = src.vcRckPin; 61 8 : return *this; 62 : } 63 : 64 5 : bool operator==(const VppConfig& a, const VppConfig& b) { 65 5 : return (operator==((Dc2DcConfig&)a, (Dc2DcConfig&)b) && 66 3 : a.ctrlPin == b.ctrlPin && a.vcSinPin == b.vcSinPin && 67 11 : a.vcClkPin == b.vcClkPin && a.vcClrPin == b.vcClrPin && 68 8 : a.vcRckPin == b.vcRckPin); 69 : } 70 : 71 : // --------------------------------------------------------------------------- 72 : 73 8 : VGenConfig& VGenConfig::operator=(const VGenConfig& src) { 74 8 : this->vpp = src.vpp; 75 8 : this->vdd = src.vdd; 76 8 : return *this; 77 : } 78 : 79 3 : bool operator==(const VGenConfig& a, const VGenConfig& b) { 80 3 : return (a.vpp == b.vpp && a.vdd == b.vdd); 81 : } 82 : 83 2 : bool operator!=(const VGenConfig& a, const VGenConfig& b) { 84 2 : return (!(a.vpp == b.vpp) || !(a.vdd == b.vdd)); 85 : } 86 : 87 : // --------------------------------------------------------------------------- 88 : 89 84 : GenericGenerator::GenericGenerator(const VGenerator* owner) 90 84 : : owner_(const_cast<VGenerator*>(owner)), on_(false) {} 91 : 92 6 : bool GenericGenerator::isRunning() const { 93 6 : return dc2dc_.isRunning(); 94 : } 95 : 96 12 : void GenericGenerator::setV(float value) { 97 12 : dc2dc_.setV(value); 98 12 : } 99 : 100 4 : float GenericGenerator::getVTarget() const { 101 4 : return dc2dc_.getVTarget(); 102 : } 103 : 104 10 : float GenericGenerator::getV() const { 105 10 : if (!owner_->isRunning() || dc2dc_.getV() < 0.0f) { 106 2 : return 0.0f; 107 : } 108 8 : return dc2dc_.getV(); 109 : } 110 : 111 4 : float GenericGenerator::getCalibration() const { 112 4 : return dc2dc_.getCalibration(); 113 : } 114 : 115 2 : float GenericGenerator::getDuty() const { 116 2 : return dc2dc_.getDuty(); 117 : } 118 : 119 2 : void GenericGenerator::initCalibration(float reference) { 120 2 : if (!owner_->isRunning()) { 121 0 : return; 122 : } 123 2 : if (reference <= 0.0f) { 124 0 : return; 125 : } 126 2 : dc2dc_.setCalibration(0.0f); 127 2 : setV(reference); 128 2 : on(); 129 : } 130 : 131 2 : void GenericGenerator::saveCalibration(float measure) { 132 2 : if (!owner_->isRunning()) { 133 0 : return; 134 : } 135 2 : float v = dc2dc_.getV(); 136 2 : if (measure <= 0.0f || v <= 0.0f) { 137 0 : dc2dc_.setCalibration(0.0f); 138 : } else { 139 2 : dc2dc_.setCalibration(measure - v); 140 : } 141 2 : owner_->stop(); 142 2 : owner_->writeCalData_(); 143 2 : setV(0.0f); 144 2 : off(); 145 2 : owner_->start(); 146 : } 147 : 148 4 : void GenericGenerator::toggle() { 149 4 : if (isOn()) { 150 2 : off(); 151 : } else { 152 2 : on(); 153 : } 154 4 : } 155 : 156 14 : bool GenericGenerator::isOn() const { 157 14 : return on_; 158 : } 159 : 160 12 : bool GenericGenerator::start_() { 161 12 : return dc2dc_.start(); 162 : } 163 : 164 12 : void GenericGenerator::stop_() { 165 12 : dc2dc_.stop(); 166 12 : } 167 : 168 225396 : void GenericGenerator::adjust_() { 169 225396 : dc2dc_.adjust(); 170 225396 : } 171 : 172 : // --------------------------------------------------------------------------- 173 : 174 42 : VddGenerator::VddGenerator(const VGenerator* owner) 175 42 : : GenericGenerator(owner), onVpp_(false) {} 176 : 177 4 : void VddGenerator::on() { 178 4 : gpio_.setPin(owner_->config_.vdd.ctrlPin); 179 4 : on_ = true; 180 4 : } 181 : 182 9 : void VddGenerator::off() { 183 9 : gpio_.resetPin(owner_->config_.vdd.ctrlPin); 184 9 : on_ = false; 185 9 : } 186 : 187 1 : void VddGenerator::initCalibration(float reference) { 188 1 : GenericGenerator::initCalibration(reference); 189 1 : } 190 : 191 2 : void VddGenerator::onVpp(bool status) { 192 2 : gpio_.setPin(owner_->config_.vdd.onVppPin, status); 193 2 : onVpp_ = status; 194 2 : } 195 : 196 3 : bool VddGenerator::isOnVpp() const { 197 3 : return onVpp_; 198 : } 199 : 200 : // --------------------------------------------------------------------------- 201 : 202 42 : VppGenerator::VppGenerator(const VGenerator* owner) : GenericGenerator(owner) {} 203 : 204 4 : void VppGenerator::on() { 205 4 : gpio_.setPin(owner_->config_.vpp.ctrlPin); 206 4 : on_ = true; 207 4 : } 208 : 209 9 : void VppGenerator::off() { 210 9 : gpio_.resetPin(owner_->config_.vpp.ctrlPin); 211 9 : on_ = false; 212 9 : } 213 : 214 1 : void VppGenerator::initCalibration(float reference) { 215 1 : GenericGenerator::initCalibration(reference); 216 1 : } 217 : 218 2 : void VppGenerator::onA9(bool status) { 219 2 : vcRegister_.setBit(kVppOnA9VcRegisterBit, status); 220 2 : } 221 : 222 2 : void VppGenerator::onA18(bool status) { 223 2 : vcRegister_.setBit(kVppOnA18VcRegisterBit, status); 224 2 : } 225 : 226 2 : void VppGenerator::onCE(bool status) { 227 2 : vcRegister_.setBit(kVppOnCEVcRegisterBit, status); 228 2 : } 229 : 230 2 : void VppGenerator::onOE(bool status) { 231 2 : vcRegister_.setBit(kVppOnOEVcRegisterBit, status); 232 2 : } 233 : 234 2 : void VppGenerator::onWE(bool status) { 235 2 : vcRegister_.setBit(kVppOnWEVcRegisterBit, status); 236 2 : } 237 : 238 3 : bool VppGenerator::isOnA9() const { 239 3 : return vcRegister_.getBit(kVppOnA9VcRegisterBit); 240 : } 241 : 242 3 : bool VppGenerator::isOnA18() const { 243 3 : return vcRegister_.getBit(kVppOnA18VcRegisterBit); 244 : } 245 : 246 3 : bool VppGenerator::isOnCE() const { 247 3 : return vcRegister_.getBit(kVppOnCEVcRegisterBit); 248 : } 249 : 250 3 : bool VppGenerator::isOnOE() const { 251 3 : return vcRegister_.getBit(kVppOnOEVcRegisterBit); 252 : } 253 : 254 3 : bool VppGenerator::isOnWE() const { 255 3 : return vcRegister_.getBit(kVppOnWEVcRegisterBit); 256 : } 257 : 258 6 : bool VppGenerator::start_() { 259 6 : vcRegister_.configure( 260 6 : owner_->config_.vpp.vcSinPin, owner_->config_.vpp.vcClkPin, 261 6 : owner_->config_.vpp.vcClrPin, owner_->config_.vpp.vcRckPin); 262 6 : vcRegister_.clear(); 263 6 : vcRegister_.outputEnable(); 264 6 : return GenericGenerator::start_(); 265 : } 266 : 267 6 : void VppGenerator::stop_() { 268 6 : vcRegister_.clear(); 269 6 : GenericGenerator::stop_(); 270 6 : } 271 : 272 : // --------------------------------------------------------------------------- 273 : 274 42 : VGenerator::VGenerator() 275 42 : : status_(MultiCore::csStopped), 276 42 : vpp(this), 277 42 : vdd(this), 278 42 : multicore_(second_core) { 279 42 : readCalData_(); 280 42 : } 281 : 282 1 : VGenerator::VGenerator(const VGenConfig& config) : VGenerator() { 283 1 : configure(config); 284 1 : } 285 : 286 42 : VGenerator::~VGenerator() { 287 42 : stop(); 288 42 : } 289 : 290 7 : void VGenerator::configure(const VGenConfig& config) { 291 7 : if (isRunning()) { 292 0 : stop(); 293 : } 294 7 : config_ = config; 295 7 : vpp.dc2dc_.configure(config_.vpp); 296 7 : vdd.dc2dc_.configure(config_.vdd); 297 7 : } 298 : 299 5 : VGenConfig VGenerator::getConfig() const { 300 5 : return config_; 301 : } 302 : 303 6 : bool VGenerator::start() { 304 6 : if (status_ != MultiCore::csStopped) { 305 0 : return true; 306 : } 307 6 : if (!isValidConfig_()) { 308 0 : return false; 309 : } 310 6 : status_ = MultiCore::csStarting; 311 6 : bool vppRes = vpp.start_(); 312 6 : bool vddRes = vdd.start_(); 313 6 : multicore_.launch(); 314 6 : multicore_.putParam(reinterpret_cast<uintptr_t>(&vpp)); 315 6 : multicore_.putParam(reinterpret_cast<uintptr_t>(&vdd)); 316 111 : while (status_ == MultiCore::csStarting) { 317 105 : MultiCore::usleep(1); 318 : } 319 6 : MultiCore::msleep(200); 320 6 : return (vppRes && vddRes); 321 : } 322 : 323 45 : void VGenerator::stop() { 324 45 : if (status_ != MultiCore::csRunning) { 325 39 : return; 326 : } 327 6 : multicore_.lock(); 328 6 : status_ = MultiCore::csStopping; 329 6 : multicore_.unlock(); 330 6 : vpp.off(); 331 6 : vdd.off(); 332 6 : vpp.stop_(); 333 6 : vdd.stop_(); 334 6 : multicore_.stop(); 335 : #ifdef __arm__ 336 : multicore_.lock(); 337 : status_ = MultiCore::csStopped; 338 : multicore_.unlock(); 339 : #endif 340 : } 341 : 342 27 : bool VGenerator::isRunning() const { 343 27 : return (status_ != MultiCore::csStopped); 344 : } 345 : 346 6 : bool VGenerator::isValidConfig_() const { 347 6 : return (config_.vdd.pwmPin != 0xFF && config_.vdd.pwmFreq != 0.0f && 348 6 : config_.vdd.adcChannel != 0xFF && config_.vdd.ctrlPin != 0xFF && 349 6 : config_.vdd.onVppPin != 0xFF && config_.vpp.pwmPin != 0xFF && 350 6 : config_.vpp.pwmFreq != 0.0f && config_.vpp.adcChannel != 0xFF && 351 6 : config_.vpp.ctrlPin != 0xFF && config_.vpp.vcSinPin != 0xFF && 352 18 : config_.vpp.vcClkPin != 0xFF && config_.vpp.vcClrPin != 0xFF && 353 12 : config_.vpp.vcRckPin != 0xFF); 354 : } 355 : 356 42 : void VGenerator::readCalData_() { 357 42 : size_t len = sizeof(float) * 2; 358 420 : uint8_t* buf = new uint8_t[len + 1](); 359 42 : Flash::read(buf, len + 1); 360 : float vddCal, vppCal; 361 42 : if (checksum_(buf, len) == buf[len]) { 362 2 : vddCal = *(reinterpret_cast<float*>(buf)); 363 2 : vppCal = *(reinterpret_cast<float*>(buf + sizeof(float))); 364 : } else { 365 40 : vddCal = 0.0f; 366 40 : vppCal = 0.0f; 367 : } 368 42 : vdd.dc2dc_.setCalibration(vddCal); 369 42 : vpp.dc2dc_.setCalibration(vppCal); 370 42 : delete[] buf; 371 42 : } 372 : 373 2 : void VGenerator::writeCalData_() { 374 2 : size_t len = sizeof(float) * 2; 375 20 : uint8_t* buf = new uint8_t[len + 1](); 376 2 : float vddCal = vdd.getCalibration(); 377 2 : float vppCal = vpp.getCalibration(); 378 2 : std::memcpy(buf, &vddCal, sizeof(float)); 379 2 : std::memcpy(buf + sizeof(float), &vppCal, sizeof(float)); 380 2 : buf[len] = checksum_(buf, len); 381 2 : Flash::write(buf, len + 1); 382 2 : delete[] buf; 383 2 : } 384 : 385 44 : uint8_t VGenerator::checksum_(const uint8_t* buf, size_t len) { 386 44 : uint8_t cs = 0; 387 396 : for (size_t i = 0; i < len; i++) { 388 352 : cs += buf[i]; 389 : } 390 44 : return cs; 391 : } 392 : 393 : // --------------------------------------------------------------------------- 394 : 395 6 : void second_core(MultiCore& core) { // NOLINT 396 6 : VppGenerator* vpp = reinterpret_cast<VppGenerator*>(core.getParam()); 397 6 : VddGenerator* vdd = reinterpret_cast<VddGenerator*>(core.getParam()); 398 6 : core.lock(); 399 6 : vpp->owner_->status_ = MultiCore::csRunning; 400 6 : core.unlock(); 401 112704 : while (!core.isStopRequested()) { 402 112698 : vpp->adjust_(); 403 112698 : vdd->adjust_(); 404 : } 405 6 : core.lock(); 406 6 : vpp->owner_->status_ = MultiCore::csStopped; 407 6 : core.unlock(); 408 6 : }