amiro-os / components / power / bq27500.cpp @ f8cf404d
History | View | Annotate | Download (13.763 KB)
| 1 | 58fe0e0b | Thomas Schöpping | #include <amiro/power/bq27500.hpp> |
|---|---|---|---|
| 2 | |||
| 3 | #include <ch.hpp> |
||
| 4 | #include <chprintf.h> |
||
| 5 | f8cf404d | Thomas Schöpping | #include <global.hpp> |
| 6 | 58fe0e0b | Thomas Schöpping | |
| 7 | #include <cstring> |
||
| 8 | |||
| 9 | using namespace chibios_rt; |
||
| 10 | using namespace amiro; |
||
| 11 | using namespace BQ27500; |
||
| 12 | |||
| 13 | f8cf404d | Thomas Schöpping | extern Global global;
|
| 14 | |||
| 15 | 58fe0e0b | Thomas Schöpping | Driver::Driver(I2CDriver &i2c_driver, const GPIO_TypeDef &batgd_pingrp, const uint8_t batgd_pin, const GPIO_TypeDef &batlow_pingrp, const uint8_t batlow_pin) : |
| 16 | BaseSensor<BQ27500::InitData,BQ27500::CalibData>(), i2c_driver(&i2c_driver), tx_params({I2C_ADDR, NULL, 0, NULL, 0}),
|
||
| 17 | batgd_pingrp(&batgd_pingrp), batgd_pin(batgd_pin), batlow_pingrp(&batlow_pingrp), batlow_pin(batlow_pin) |
||
| 18 | {}
|
||
| 19 | |||
| 20 | Driver::~Driver() |
||
| 21 | {}
|
||
| 22 | |||
| 23 | chibios_rt::EvtSource* |
||
| 24 | Driver::getEventSource() |
||
| 25 | {
|
||
| 26 | return &this->eventSource; |
||
| 27 | } |
||
| 28 | |||
| 29 | msg_t |
||
| 30 | Driver::init(InitData* initialization_data) |
||
| 31 | {
|
||
| 32 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): TODO\n", __FILE__, __LINE__);
|
| 33 | 58fe0e0b | Thomas Schöpping | return NOT_IMPLEMENTED;
|
| 34 | } |
||
| 35 | |||
| 36 | msg_t |
||
| 37 | Driver::update() |
||
| 38 | {
|
||
| 39 | msg_t res = SUCCESS; |
||
| 40 | res |= this->stdCommand(STD_CMD_TimeToEmpty, this->status.minutes_to_empty); |
||
| 41 | res |= this->stdCommand(STD_CMD_TimeToFull, this->status.minutes_to_full); |
||
| 42 | res |= this->stdCommand(STD_CMD_AveragePower, this->status.average_power_mW); |
||
| 43 | uint16_t tmp; |
||
| 44 | res |= this->stdCommand(STD_CMD_StateOfCharge, tmp);
|
||
| 45 | this->status.state_of_charge = tmp;
|
||
| 46 | return (res == SUCCESS)? SUCCESS : ERROR;
|
||
| 47 | } |
||
| 48 | |||
| 49 | msg_t |
||
| 50 | Driver::wakeup() |
||
| 51 | {
|
||
| 52 | const msg_t res = this->subCommand(SUB_CMD_CLEAR_HIBERNATE); |
||
| 53 | return (res? ERROR : SUCCESS);
|
||
| 54 | } |
||
| 55 | |||
| 56 | msg_t |
||
| 57 | Driver::hibernate() |
||
| 58 | {
|
||
| 59 | const msg_t res = this->subCommand(SUB_CMD_SET_HIBERNATE); |
||
| 60 | return (res? ERROR : SUCCESS);
|
||
| 61 | } |
||
| 62 | |||
| 63 | #ifndef AMIRO_NCALIBRATION
|
||
| 64 | msg_t |
||
| 65 | Driver::calibration(CalibData* calibration_data) |
||
| 66 | {
|
||
| 67 | DataFlashBlock block; |
||
| 68 | this->readDataFlashBlock(block, CONFIGURATION_Safety);
|
||
| 69 | |||
| 70 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d):\n", __FILE__, __LINE__);
|
| 71 | 58fe0e0b | Thomas Schöpping | for(uint8_t i = 0; i < 32; ++i) { |
| 72 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%02X ", block.content.data[i]);
|
| 73 | 58fe0e0b | Thomas Schöpping | } |
| 74 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
|
| 75 | chprintf((BaseSequentialStream*) &global.sercanmux1, "%02X\n", block.content.checksum);
|
||
| 76 | 58fe0e0b | Thomas Schöpping | |
| 77 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): TODO\n", __FILE__, __LINE__);
|
| 78 | 58fe0e0b | Thomas Schöpping | return NOT_IMPLEMENTED;
|
| 79 | } |
||
| 80 | #endif
|
||
| 81 | |||
| 82 | #ifndef AMIRO_NSELFTEST
|
||
| 83 | msg_t |
||
| 84 | Driver::selftest() |
||
| 85 | {
|
||
| 86 | uint16_t val = 0;
|
||
| 87 | Version version; |
||
| 88 | |||
| 89 | // read hardware version
|
||
| 90 | version.value = 0;
|
||
| 91 | if (this->subCommand(SUB_CMD_HW_VERSION, &version.value)) |
||
| 92 | {
|
||
| 93 | return ST_FAIL_READ_HW_VERSION;
|
||
| 94 | } |
||
| 95 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "hardware version: %X%X-%X%X (0x%04X)\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low, version.value);
|
| 96 | 58fe0e0b | Thomas Schöpping | |
| 97 | // read firmware version
|
||
| 98 | version.value = 0;
|
||
| 99 | if (this->subCommand(SUB_CMD_FW_VERSION, &version.value)) |
||
| 100 | {
|
||
| 101 | return ST_FAIL_READ_FW_VERSION;
|
||
| 102 | } |
||
| 103 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "firmware version: %X%X-%X%X (0x%04X)\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low, version.value);
|
| 104 | 58fe0e0b | Thomas Schöpping | |
| 105 | // read device name
|
||
| 106 | uint8_t name_length = 0;
|
||
| 107 | if (this->extCommand(EXT_CMD_DNAMELEN, EXT_CMD_READ, &name_length)) |
||
| 108 | {
|
||
| 109 | return ST_FAIL_READ_DEVICENAMELENGTH;
|
||
| 110 | } |
||
| 111 | char name_buffer[9]; // maximum name length is 8 |
||
| 112 | if (this->extCommand(EXT_CMD_DNAME, EXT_CMD_READ, (uint8_t*)name_buffer, name_length)) |
||
| 113 | {
|
||
| 114 | return ST_FAIL_READ_DEVICENAME;
|
||
| 115 | } |
||
| 116 | name_buffer[name_length] = '\0';
|
||
| 117 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "device name: %s (%u characters)\n", name_buffer, name_length);
|
| 118 | 58fe0e0b | Thomas Schöpping | |
| 119 | // read the current flags
|
||
| 120 | Flags flags; |
||
| 121 | if (this->stdCommand(STD_CMD_FLAGS, flags.value)) |
||
| 122 | {
|
||
| 123 | return ST_FAIL_READ_FLAGS;
|
||
| 124 | } |
||
| 125 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "flags: 0x%04X\n", flags.value);
|
| 126 | chprintf((BaseSequentialStream*) &global.sercanmux1, " OTC : %u\n", flags.content.otc);
|
||
| 127 | chprintf((BaseSequentialStream*) &global.sercanmux1, " OTD : %u\n", flags.content.otd);
|
||
| 128 | chprintf((BaseSequentialStream*) &global.sercanmux1, " CHG_INH : %u\n", flags.content.chg_inh);
|
||
| 129 | chprintf((BaseSequentialStream*) &global.sercanmux1, " XCHG : %u\n", flags.content.xchg);
|
||
| 130 | chprintf((BaseSequentialStream*) &global.sercanmux1, " FC : %u\n", flags.content.fc);
|
||
| 131 | chprintf((BaseSequentialStream*) &global.sercanmux1, " CHG : %u\n", flags.content.chg);
|
||
| 132 | chprintf((BaseSequentialStream*) &global.sercanmux1, " OCV_GD : %u\n", flags.content.ocv_gd);
|
||
| 133 | chprintf((BaseSequentialStream*) &global.sercanmux1, " WAIT_ID : %u\n", flags.content.wait_id);
|
||
| 134 | chprintf((BaseSequentialStream*) &global.sercanmux1, " BAT_DET : %u\n", flags.content.bat_det);
|
||
| 135 | chprintf((BaseSequentialStream*) &global.sercanmux1, " SOC1 : %u\n", flags.content.soc1);
|
||
| 136 | chprintf((BaseSequentialStream*) &global.sercanmux1, " SOCF : %u\n", flags.content.socf);
|
||
| 137 | chprintf((BaseSequentialStream*) &global.sercanmux1, " DSG : %u\n", flags.content.dsg);
|
||
| 138 | 58fe0e0b | Thomas Schöpping | |
| 139 | // read the current controller status
|
||
| 140 | ControlStatus ctrl_status; |
||
| 141 | if (this->subCommand(SUB_CMD_CONTROL_STATUS, &ctrl_status.value)) |
||
| 142 | {
|
||
| 143 | return ST_FAIL_READ_STATUS;
|
||
| 144 | } |
||
| 145 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "control status: 0x%04X\n", ctrl_status.value);
|
| 146 | chprintf((BaseSequentialStream*) &global.sercanmux1, " FAS : %u\n", ctrl_status.content.fas);
|
||
| 147 | chprintf((BaseSequentialStream*) &global.sercanmux1, " SS : %u\n", ctrl_status.content.ss);
|
||
| 148 | chprintf((BaseSequentialStream*) &global.sercanmux1, " CSV : %u\n", ctrl_status.content.csv);
|
||
| 149 | chprintf((BaseSequentialStream*) &global.sercanmux1, " CSA : %u\n", ctrl_status.content.cca);
|
||
| 150 | chprintf((BaseSequentialStream*) &global.sercanmux1, " BCA : %u\n", ctrl_status.content.bca);
|
||
| 151 | chprintf((BaseSequentialStream*) &global.sercanmux1, " HIBERNATE : %u\n", ctrl_status.content.hibernate);
|
||
| 152 | chprintf((BaseSequentialStream*) &global.sercanmux1, " SNOOZE : %u\n", ctrl_status.content.snooze);
|
||
| 153 | chprintf((BaseSequentialStream*) &global.sercanmux1, " SLEEP : %u\n", ctrl_status.content.sleep);
|
||
| 154 | chprintf((BaseSequentialStream*) &global.sercanmux1, " LDMD : %u\n", ctrl_status.content.ldmd);
|
||
| 155 | chprintf((BaseSequentialStream*) &global.sercanmux1, " RUP_DIS : %u\n", ctrl_status.content.rup_dis);
|
||
| 156 | chprintf((BaseSequentialStream*) &global.sercanmux1, " VOK : %u\n", ctrl_status.content.vok);
|
||
| 157 | chprintf((BaseSequentialStream*) &global.sercanmux1, " QEN : %u\n", ctrl_status.content.qen);
|
||
| 158 | 58fe0e0b | Thomas Schöpping | |
| 159 | // if no battery was detected, abort
|
||
| 160 | if (!flags.content.bat_det)
|
||
| 161 | {
|
||
| 162 | return ST_ABORT_NO_BAT;
|
||
| 163 | } |
||
| 164 | |||
| 165 | // read the BATGD_N pin
|
||
| 166 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "battery good: %s\n", (this->isBatteryGood()? "yes" : "no")); |
| 167 | 58fe0e0b | Thomas Schöpping | |
| 168 | // read temperature
|
||
| 169 | if (this->stdCommand(STD_CMD_TEMP, val)) |
||
| 170 | {
|
||
| 171 | return ST_FAIL_READ_TEMP;
|
||
| 172 | } |
||
| 173 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "temperature: %fK (%fC)\n", float(val)/10.0f, float(val)/10.0f - 273.15f); |
| 174 | 58fe0e0b | Thomas Schöpping | |
| 175 | // read the full available capacity
|
||
| 176 | if (this->stdCommand(STD_CMD_FAC, val)) |
||
| 177 | {
|
||
| 178 | return ST_FAIL_READ_FAC;
|
||
| 179 | } |
||
| 180 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "full available capacity: %umAh\n", val);
|
| 181 | 58fe0e0b | Thomas Schöpping | |
| 182 | // read the full charge capacity
|
||
| 183 | if (this->stdCommand(STD_CMD_FCC, val)) |
||
| 184 | {
|
||
| 185 | return ST_FAIL_READ_FCC;
|
||
| 186 | } |
||
| 187 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "full charge capacity: %umAh\n", val);
|
| 188 | 58fe0e0b | Thomas Schöpping | |
| 189 | // read the remaining capacity
|
||
| 190 | if (this->stdCommand(STD_CMD_RM, val)) |
||
| 191 | {
|
||
| 192 | return ST_FAIL_READ_RM;
|
||
| 193 | } |
||
| 194 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "remaining capacity capacity: %umAh\n", val);
|
| 195 | 58fe0e0b | Thomas Schöpping | |
| 196 | // read the state of charge
|
||
| 197 | if (this->stdCommand(STD_CMD_SOC, val)) |
||
| 198 | {
|
||
| 199 | return ST_FAIL_READ_SOC;
|
||
| 200 | } |
||
| 201 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "state of charge: %3u%%\n", val);
|
| 202 | 58fe0e0b | Thomas Schöpping | |
| 203 | // read voltage
|
||
| 204 | if (this->stdCommand(STD_CMD_VOLT, val)) |
||
| 205 | {
|
||
| 206 | return ST_FAIL_READ_VOLT;
|
||
| 207 | } |
||
| 208 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "voltage: %umV\n", val);
|
| 209 | 58fe0e0b | Thomas Schöpping | |
| 210 | // read average current
|
||
| 211 | if (this->stdCommand(STD_CMD_AI, val)) |
||
| 212 | {
|
||
| 213 | return ST_FAIL_READ_AI;
|
||
| 214 | } |
||
| 215 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "average current: %dmA\n", *reinterpret_cast<int8_t*>(&val)); |
| 216 | 58fe0e0b | Thomas Schöpping | |
| 217 | // read average power
|
||
| 218 | if (this->stdCommand(STD_CMD_AP, val)) |
||
| 219 | {
|
||
| 220 | return ST_FAIL_READ_AP;
|
||
| 221 | } |
||
| 222 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "average power: %dmW\n", *reinterpret_cast<int8_t*>(&val)); |
| 223 | 58fe0e0b | Thomas Schöpping | |
| 224 | // read the BATLOW pin
|
||
| 225 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "battery low: %s\n", (this->isBatteryLow()? "yes" : "no")); |
| 226 | 58fe0e0b | Thomas Schöpping | |
| 227 | // read the time to empty
|
||
| 228 | if (this->stdCommand(STD_CMD_TTE, val)) |
||
| 229 | {
|
||
| 230 | return ST_FAIL_READ_TTE;
|
||
| 231 | } |
||
| 232 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "time to empty: ");
|
| 233 | 58fe0e0b | Thomas Schöpping | if (uint16_t(~val)) {
|
| 234 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%u minutes", val);
|
| 235 | 58fe0e0b | Thomas Schöpping | } else {
|
| 236 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "(not discharging)");
|
| 237 | 58fe0e0b | Thomas Schöpping | } |
| 238 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
|
| 239 | 58fe0e0b | Thomas Schöpping | |
| 240 | // read the time to full
|
||
| 241 | if (this->stdCommand(STD_CMD_TTF, val)) |
||
| 242 | {
|
||
| 243 | return ST_FAIL_READ_TTF;
|
||
| 244 | } |
||
| 245 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "time to full: ");
|
| 246 | 58fe0e0b | Thomas Schöpping | if (uint16_t(~val)) {
|
| 247 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%u minutes", val);
|
| 248 | 58fe0e0b | Thomas Schöpping | } else {
|
| 249 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "(not charging)");
|
| 250 | 58fe0e0b | Thomas Schöpping | } |
| 251 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
|
| 252 | 58fe0e0b | Thomas Schöpping | |
| 253 | return ST_OK;
|
||
| 254 | } |
||
| 255 | #endif
|
||
| 256 | |||
| 257 | bool
|
||
| 258 | Driver::isBatteryGood() const
|
||
| 259 | {
|
||
| 260 | return (palReadPad(this->batgd_pingrp, this->batgd_pin) == PAL_LOW); |
||
| 261 | } |
||
| 262 | |||
| 263 | bool
|
||
| 264 | Driver::isBatteryLow() const
|
||
| 265 | {
|
||
| 266 | return (palReadPad(this->batlow_pingrp, this->batlow_pin) == PAL_HIGH); |
||
| 267 | } |
||
| 268 | |||
| 269 | const Driver::UpdateData&
|
||
| 270 | Driver::getStatus() const
|
||
| 271 | {
|
||
| 272 | return this->status; |
||
| 273 | } |
||
| 274 | |||
| 275 | msg_t |
||
| 276 | Driver::main(void)
|
||
| 277 | {
|
||
| 278 | while (!this->shouldTerminate()) |
||
| 279 | {
|
||
| 280 | this->update();
|
||
| 281 | this->eventSource.broadcastFlags(0); |
||
| 282 | |||
| 283 | this->waitAnyEventTimeout(ALL_EVENTS, MS2ST(1000)); |
||
| 284 | } |
||
| 285 | |||
| 286 | return RDY_OK;
|
||
| 287 | } |
||
| 288 | |||
| 289 | msg_t |
||
| 290 | Driver::stdCommand(const StandardCommand cmd, uint16_t &dst)
|
||
| 291 | {
|
||
| 292 | uint8_t buffer[2];
|
||
| 293 | this->tx_params.txbuf = reinterpret_cast<const uint8_t*>(&cmd); |
||
| 294 | this->tx_params.txbytes = 1; |
||
| 295 | this->tx_params.rxbuf = buffer;
|
||
| 296 | this->tx_params.rxbytes = 2; |
||
| 297 | |||
| 298 | this->i2c_driver->acquireBus();
|
||
| 299 | const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params); |
||
| 300 | this->i2c_driver->releaseBus();
|
||
| 301 | |||
| 302 | if (!res) {
|
||
| 303 | dst = uint16_t((buffer[1] << 8) | buffer[0]); |
||
| 304 | #ifndef NDEBUG
|
||
| 305 | } else {
|
||
| 306 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d)\n", __FILE__ , __LINE__ , res);
|
| 307 | 58fe0e0b | Thomas Schöpping | #endif
|
| 308 | } |
||
| 309 | |||
| 310 | return res;
|
||
| 311 | } |
||
| 312 | |||
| 313 | msg_t |
||
| 314 | Driver::readName() |
||
| 315 | {
|
||
| 316 | uint8_t buffer[9];
|
||
| 317 | uint8_t reg = 0x62u;
|
||
| 318 | this->tx_params.txbuf = ®
|
||
| 319 | this->tx_params.txbytes = 1; |
||
| 320 | this->tx_params.rxbuf = &buffer[0]; |
||
| 321 | this->tx_params.rxbytes = 8; |
||
| 322 | |||
| 323 | this->i2c_driver->acquireBus();
|
||
| 324 | const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params); |
||
| 325 | this->i2c_driver->releaseBus();
|
||
| 326 | |||
| 327 | buffer[buffer[0] + 1] = '\0'; |
||
| 328 | |||
| 329 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "name: %u - %s\n", buffer[0], (char*)&buffer[1]); |
| 330 | 58fe0e0b | Thomas Schöpping | |
| 331 | return res;
|
||
| 332 | } |
||
| 333 | |||
| 334 | msg_t |
||
| 335 | Driver::subCommand(const ControlSubcommand cmd, uint16_t *dst)
|
||
| 336 | {
|
||
| 337 | uint8_t buffer[3] = {STD_CMD_CNTL, uint8_t(cmd & 0x00FFu), uint8_t((cmd & 0xFF00u) >> 8)}; |
||
| 338 | this->tx_params.txbuf = buffer;
|
||
| 339 | this->tx_params.txbytes = 3; |
||
| 340 | this->tx_params.rxbytes = 0; |
||
| 341 | |||
| 342 | this->i2c_driver->acquireBus();
|
||
| 343 | msg_t res = this->i2c_driver->masterTransmit(&this->tx_params); |
||
| 344 | this->i2c_driver->releaseBus();
|
||
| 345 | if (dst) {
|
||
| 346 | this->tx_params.txbytes = 1; |
||
| 347 | |||
| 348 | this->tx_params.rxbuf = &buffer[1]; |
||
| 349 | this->tx_params.rxbytes = 2; |
||
| 350 | |||
| 351 | BaseThread::sleep(US2ST(2));
|
||
| 352 | this->i2c_driver->acquireBus();
|
||
| 353 | res |= this->i2c_driver->masterTransmit(&this->tx_params); |
||
| 354 | this->i2c_driver->releaseBus();
|
||
| 355 | } |
||
| 356 | |||
| 357 | #ifndef NDEBUG
|
||
| 358 | if (res) {
|
||
| 359 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d)\n", __FILE__ , __LINE__ , res);
|
| 360 | 58fe0e0b | Thomas Schöpping | } |
| 361 | #endif
|
||
| 362 | |||
| 363 | if (dst && !res) {
|
||
| 364 | *dst = uint16_t((buffer[2] << 8) | buffer[1]); |
||
| 365 | } |
||
| 366 | |||
| 367 | return res;
|
||
| 368 | } |
||
| 369 | |||
| 370 | msg_t |
||
| 371 | Driver::extCommand(const ExtendedCommand cmd, const ExtendedCommandAccess rw, uint8_t* buf, const uint8_t length, const uint8_t offset) |
||
| 372 | {
|
||
| 373 | if (!buf) {
|
||
| 374 | #ifndef NDEBUG
|
||
| 375 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: received NULL-pointer as buffer\n", __FILE__ , __LINE__);
|
| 376 | 58fe0e0b | Thomas Schöpping | #endif
|
| 377 | return ~RDY_OK;
|
||
| 378 | } |
||
| 379 | if (rw != EXT_CMD_WRITE && rw != EXT_CMD_READ) {
|
||
| 380 | #ifndef NDEBUG
|
||
| 381 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: invalid access mode selected\n", __FILE__ , __LINE__);
|
| 382 | 58fe0e0b | Thomas Schöpping | #endif
|
| 383 | return ~RDY_OK;
|
||
| 384 | } |
||
| 385 | if (length > 33) { |
||
| 386 | #ifndef NDEBUG
|
||
| 387 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: length exceeds maximum of 33 bytes\n", __FILE__ , __LINE__);
|
| 388 | 58fe0e0b | Thomas Schöpping | #endif
|
| 389 | return ~RDY_OK;
|
||
| 390 | } |
||
| 391 | |||
| 392 | uint8_t in_buffer[34];
|
||
| 393 | in_buffer[0] = cmd + offset;
|
||
| 394 | if (rw == EXT_CMD_WRITE) {
|
||
| 395 | strncpy((char*)&in_buffer[1], (char*)buf, length); |
||
| 396 | } |
||
| 397 | this->tx_params.txbuf = in_buffer;
|
||
| 398 | this->tx_params.txbytes = 1 + ((rw == EXT_CMD_WRITE)? length : 0); |
||
| 399 | this->tx_params.rxbuf = (rw == EXT_CMD_READ)? buf : NULL; |
||
| 400 | this->tx_params.rxbytes = (rw == EXT_CMD_READ)? length : 0; |
||
| 401 | |||
| 402 | this->i2c_driver->acquireBus();
|
||
| 403 | const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params); |
||
| 404 | this->i2c_driver->releaseBus();
|
||
| 405 | |||
| 406 | #ifndef NDEBUG
|
||
| 407 | if (res) {
|
||
| 408 | f8cf404d | Thomas Schöpping | chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d)\n", __FILE__ , __LINE__ , res);
|
| 409 | 58fe0e0b | Thomas Schöpping | } |
| 410 | #endif
|
||
| 411 | |||
| 412 | return res;
|
||
| 413 | } |
||
| 414 | |||
| 415 | msg_t |
||
| 416 | Driver::readDataFlashBlock(DataFlashBlock &block, const DataFlashSubClassID sub_id, const uint8_t sub_block) |
||
| 417 | {
|
||
| 418 | block.raw[0] = sub_id;
|
||
| 419 | block.raw[1] = sub_block;
|
||
| 420 | msg_t res = this->extCommand(EXT_CMD_DFCLS, EXT_CMD_WRITE, &block.raw[0]); |
||
| 421 | res |= this->extCommand(EXT_CMD_DFBLK, EXT_CMD_WRITE, &block.raw[1]); |
||
| 422 | |||
| 423 | BaseThread::sleep(US2ST(1)); // Without this delay the whole block is shifted and the first byte is lost. TODO: investigate |
||
| 424 | res |= this->extCommand(EXT_CMD_DFD, EXT_CMD_READ, block.raw, 33); |
||
| 425 | |||
| 426 | return res;
|
||
| 427 | } |