Example for updating the MTi-1's firmware. Uses a platform independent, retargetable pure C implementation of the firmware updater protocol.
main.cpp
00001 /*! \file 00002 \copyright Copyright (C) Xsens Technologies B.V., 2015. 00003 00004 Licensed under the Apache License, Version 2.0 (the "License"); you may not 00005 use this file except in compliance with the License. You may obtain a copy 00006 of the License at 00007 00008 http://www.apache.org/licenses/LICENSE-2.0 00009 00010 Unless required by applicable law or agreed to in writing, software 00011 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00012 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 00013 License for the specific language governing permissions and limitations 00014 under the License. 00015 00016 \page Embedded firmware example 00017 The purpose of this example is to demonstrate how to update the firmware of a MTi-1 series module using the FwUpdate library. 00018 The example embeds an Xsens firmware file (xff) which is converted to a data array with srecord (http://srecord.sourceforge.net). 00019 The example is designed to run on a Nucleo F401 board. Porting to other mbed platforms should be easy but not all boards may 00020 have enough flash memory to hold the full xff 00021 00022 \section Software setup 00023 Select the required bus mode by uncommenting one of the following defines at the top of main.cpp 00024 \verbatim 00025 BUS_MODE_SPI 00026 BUS_MODE_I2C 00027 BUS_MODE_UART 00028 \endverbatim 00029 Next, build the example and program it in the Nucleo F401 board. 00030 00031 \section Development board setup 00032 Configure the required bus mode (UART, I2C, SPI) with the dip switches on the MTi-1 development board. 00033 (At the bottom of the development board a table with switch settings is shown) 00034 00035 \section Hardware setup 00036 00037 Unpower the board and make the following connections between the Nucleo F401 board and the 00038 MTi 1 series development board (depending on the selected bus mode, the unused connections may be 00039 left unconnected) 00040 00041 Power supply and reset: 00042 \verbatim 00043 |----------------|---------------|-------------------------| 00044 | Signal | Nucleo F401 | Mti-1s Dev board header | 00045 |----------------|---------------|-------------------------| 00046 | 5V | 5V | 1 | 00047 | 3V3 | 3V3 | 2 | 00048 | GND | GND | 3 | 00049 | RESET | PC9 | 5 | 00050 |----------------|---------------|-------------------------| 00051 \endverbatim 00052 00053 Uart: 00054 \verbatim 00055 |----------------|---------------|-------------------------| 00056 | Signal | Nucleo F401 | Mti-1s Dev board header | 00057 |----------------|---------------|-------------------------| 00058 | Tx of Nucleo | PA9 | 11 | 00059 | Tx of MTi | PA10 | 9 | 00060 |----------------|---------------|-------------------------| 00061 \endverbatim 00062 00063 I2C: 00064 \verbatim 00065 |----------------|---------------|-------------------------| 00066 | Signal | Nucleo F401 | Mti-1s Dev board header | 00067 |----------------|---------------|-------------------------| 00068 | SCL | PB8 | 9 | 00069 | SDA | PB9 | 11 | 00070 | DRDY | PB3 | 15 | 00071 | ADD0 | PB13 | 17 | 00072 | ADD1 | PB14 | 19 | 00073 | ADD2 | PB15 | 21 | 00074 |----------------|---------------|-------------------------| 00075 \endverbatim 00076 00077 SPI: 00078 \verbatim 00079 |----------------|---------------|-------------------------| 00080 | Signal | Nucleo F401 | Mti-1s Dev board header | 00081 |----------------|---------------|-------------------------| 00082 | SCK | PB13 | 17 | 00083 | MISO | PB14 | 19 | 00084 | MOSI | PB15 | 21 | 00085 | nCS | PB6 | 23 | 00086 | DRDY | PB3 | 15 | 00087 |----------------|---------------|-------------------------| 00088 \endverbatim 00089 00090 \section Connection with host PC 00091 Connect the Nucleo board with a USB cable to the host PC. Find out on which 00092 COM port the Nucleo board is mapped by the OS, and open a terminal emulator (e.g. PuTTY) 00093 on this port. The default baud rate of the example is 921600. Pressing 'h' in the terminal 00094 window should return the following usage text: 00095 00096 \verbatim 00097 Embedded firmware updater example 00098 Interface: SPI 00099 00100 h: Print this text 00101 c: GotoConfig 00102 m: GotoMeasurement 00103 r: Soft reset the module 00104 b: GotoBootloader 00105 v: Request firmware revision 00106 d: Request deviceId 00107 u: Start firmware update (make sure module is in bootloader mode) 00108 x: Hard reset the module and make it stay in bootloader 00109 \endverbatim 00110 00111 After power-up the module automatically goes to measurement mode. In this mode 00112 only a limited set of commands is supported. Therefore, the module must first be 00113 switched to config mode by pressing 'c'. The module should response with XMID_GotoConfigAck. 00114 00115 Next, the firmware revision can be requested by pressing 'v'. This should return 00116 the firmware revision in the format Major.Minor.Patch. If the Major version number is 255, the 00117 module is in bootloader mode. Any other Major version number means that the MTi-1s main firmware is 00118 running. In this case the module must be set in bootloader mode before a firmware update can be done. 00119 The module can be placed in bootloader mode by pressing either the 'b' or 'x' key 00120 */ 00121 00122 00123 #include "mbed.h" 00124 #include "rtos.h" 00125 #include "board.h " 00126 #include "xbusmessage.h " 00127 #include "xbusparser.h " 00128 #include "xbusmessageid.h " 00129 #include "mtinterface_mtssp.h " 00130 #include "mtinterface_uart.h " 00131 #include "mtssp_i2c_driver.h " 00132 #include "mtssp_spi_driver.h " 00133 #include "fwupdate.h " 00134 #include "xffdata.h" 00135 00136 00137 /*! \brief Bus mode to use by this example. 00138 */ 00139 //#define BUS_MODE_SPI 00140 #define BUS_MODE_I2C 00141 //#define BUS_MODE_UART 00142 00143 static void updateUartBaudrate(); 00144 00145 /*! \brief Instance of MtInterface. Should be initialized by createMtInterface(). 00146 */ 00147 static MtInterface* mtInterface = 0; 00148 00149 00150 /*! \brief Serial object for communicating with the PC. 00151 */ 00152 static Serial pc(PC_TX, PC_RX); 00153 00154 /*! \brief Reset line towards the module. Pulling this line down keeps the module in reset. 00155 */ 00156 static DigitalInOut resetLine(MT_RESET, PIN_INPUT, OpenDrain, 1); 00157 00158 00159 /*! \brief Instance of the firmware updater 00160 */ 00161 static FwUpdate *g_fwUpdate = NULL; 00162 00163 00164 /*! \brief Create an instance of MtInterface. 00165 */ 00166 static void createMtInterface() 00167 { 00168 #ifdef BUS_MODE_SPI 00169 MtsspDriver* mtsspDriver = new MtsspSpiDriver; 00170 mtInterface = new MtInterfaceMtssp(mtsspDriver); 00171 #endif 00172 00173 #ifdef BUS_MODE_I2C 00174 MtsspDriver* mtsspDriver = new MtsspI2cDriver; 00175 mtInterface = new MtInterfaceMtssp(mtsspDriver); 00176 #endif 00177 00178 #ifdef BUS_MODE_UART 00179 mtInterface = new MtInterfaceUart(115200); 00180 #endif 00181 } 00182 00183 00184 /*! \brief Callback function for FwUpdate for reading data from the xff (xsens firmware file) file. 00185 \param buffer Target buffer in which the xff data should be written 00186 \param offset Offset in the xff file where reading should start 00187 \param length Number of bytes which is requested 00188 \returns Number of bytes which is actually written to the buffer 00189 */ 00190 static int readXffData(uint8_t *buffer, int offset, int length) 00191 { 00192 static int lastOffset = 0; 00193 int n; 00194 if (offset == 0) 00195 lastOffset = 0; 00196 00197 if ((offset == 0) || ((offset - lastOffset) > 4096)) 00198 { 00199 pc.printf("%05d\r", offset); 00200 lastOffset = offset; 00201 } 00202 00203 for (n = 0; n < length; n++) 00204 { 00205 if (offset + n == g_xffData_length) 00206 break; 00207 buffer[n] = g_xffData[offset + n]; 00208 } 00209 return n; 00210 } 00211 00212 00213 /*! \brief Callback function for FwUpdate for signaling that a firmware update has completed. 00214 \param result Result of the firmware update, either FWU_Success or FWU_Failed 00215 */ 00216 static void readyHandler(FWU_Result result) 00217 { 00218 if (result == FWU_Success) 00219 pc.printf("\r\nFirmware update ready\r\n"); 00220 else if (result == FWU_Failed) 00221 pc.printf("\r\nFirmware update failed\r\n"); 00222 00223 if (mtInterface->busFormat() == XBF_Uart) 00224 updateUartBaudrate(); 00225 } 00226 00227 00228 /*! \brief Sends a XMID_GotoConfig message to the Module 00229 */ 00230 static void gotoConfig() 00231 { 00232 XbusMessage xbusMessage(XMID_GotoConfig); 00233 mtInterface->sendXbusMessage(&xbusMessage); 00234 } 00235 00236 /*! \brief Handles xbus messages from the module. 00237 \param xbusMessage The xbus message received from the module 00238 00239 Messages with message identifier XMID_FirmwareUpdate are passed to the firmware updater, other messages are just printed. 00240 */ 00241 static void handleXbusMessage(XbusMessage *xbusMessage) 00242 { 00243 switch (xbusMessage->m_mid) 00244 { 00245 case XMID_Wakeup: 00246 { 00247 //If the wakeup message is received we force the module in config mode 00248 gotoConfig(); 00249 pc.printf("XMID_Wakeup\r\n"); 00250 } break; 00251 00252 case XMID_GotoConfigAck: 00253 { 00254 pc.printf("XMID_GotoConfigAck\r\n"); 00255 } break; 00256 00257 case XMID_GotoMeasurementAck: 00258 { 00259 pc.printf("XMID_GotoMeasurementAck\r\n"); 00260 } break; 00261 00262 case XMID_ResetAck: 00263 { 00264 pc.printf("XMID_ResetAck\r\n"); 00265 } break; 00266 00267 case XMID_GotoBootLoaderAck: 00268 { 00269 pc.printf("XMID_GotoBootLoaderAck\r\n"); 00270 } break; 00271 00272 case XMID_Error: 00273 { 00274 pc.printf("XMID_Error\r\n"); 00275 } break; 00276 00277 case XMID_FirmwareUpdate: 00278 { 00279 if (g_fwUpdate != NULL) 00280 { 00281 FwUpdate_handleXbus(g_fwUpdate, xbusMessage); 00282 } 00283 } break; 00284 00285 case XMID_FirmwareRevision: 00286 { 00287 pc.printf("XMID_FirmwareRevision: %d.%d.%d\r\n", xbusMessage->m_data[0], xbusMessage->m_data[1], xbusMessage->m_data[2]); 00288 } break; 00289 00290 case XMID_DeviceId: 00291 { 00292 uint32_t deviceId = (xbusMessage->m_data[0] << 24) | (xbusMessage->m_data[1] << 16) | (xbusMessage->m_data[2] << 8) | xbusMessage->m_data[3]; 00293 pc.printf("XMID_DeviceId: %08X\r\n", deviceId); 00294 } break; 00295 00296 case XMID_MtData2: 00297 { 00298 pc.printf("XMID_MtData2\r\n"); 00299 } break; 00300 00301 default: 00302 { 00303 pc.printf("Unhandled xbus message, mid = 0x%02X, len = %d", xbusMessage->m_mid, xbusMessage->m_length); 00304 if (xbusMessage->m_length > 0) 00305 { 00306 pc.printf(", data = "); 00307 for (int n = 0; n < xbusMessage->m_length; n++) 00308 { 00309 pc.printf("%02X ", xbusMessage->m_data[n]); 00310 } 00311 } 00312 pc.printf("\r\n"); 00313 } 00314 } 00315 } 00316 00317 00318 /*! \brief Reset the module via the hardware reset line. 00319 \param stayInBootloader: If stayInBootloader is true, an XMID_GotoBootLoader is sent immediately after the reset. 00320 00321 By sending an XMID_GotoBootLoader within 100 ms after reset the module stays in bootloader mode 00322 instead of booting the application. This can be used if the normal GotoBootloader command fails to put 00323 the module in bootloader mode, e.g. because of a faulty firmware. 00324 */ 00325 static void hardwareReset(bool stayInBootloader) 00326 { 00327 resetLine = 1; 00328 resetLine.output(); 00329 wait(0.001); 00330 resetLine = 0; 00331 wait(0.001); 00332 resetLine.input(); // (configure the line as input because the OpenDrain setting of the mbed gpio pin does not seem to work correctly) 00333 00334 if (stayInBootloader) 00335 { 00336 wait(0.02); 00337 XbusMessage xbusMessage(XMID_GotoBootLoader); 00338 mtInterface->sendXbusMessage(&xbusMessage); 00339 } else 00340 { 00341 wait(0.2); 00342 } 00343 } 00344 00345 00346 /*! \brief Try to find the correct uart baudrate 00347 */ 00348 static void updateUartBaudrate() 00349 { 00350 if (mtInterface->busFormat() != XBF_Uart) 00351 return; 00352 00353 pc.printf("Detecting uart baudrate of module\r\n"); 00354 00355 const int nofBaudrates = 2; 00356 int baudrates[nofBaudrates] = {921600, 115200}; 00357 00358 bool success = false; 00359 for (int n = 0; n < nofBaudrates; n++) 00360 { 00361 ((MtInterfaceUart*)mtInterface)->setBaudrate(baudrates[n]); 00362 pc.printf("Baudrate set to %d\r\n", baudrates[n]); 00363 XbusMessage gotoConfigMessage(XMID_GotoConfig); 00364 XbusMessage* result = mtInterface->sendAndWait(&gotoConfigMessage); 00365 success = result && result->m_mid == XMID_GotoConfigAck; 00366 mtInterface->releaseXbusMessage(result); 00367 if (success) 00368 break; 00369 } 00370 if (success) 00371 pc.printf("Detecting uart baudrate of module done\r\n"); 00372 else 00373 pc.printf("Detecting uart baudrate of module failed\r\n"); 00374 } 00375 00376 bool isInBootloader() 00377 { 00378 XbusMessage fwRevisionMessage(XMID_ReqFirmwareRevision); 00379 XbusMessage* ack = mtInterface->sendAndWait(&fwRevisionMessage); 00380 00381 bool result = false; 00382 if (ack && ack->m_mid == XMID_FirmwareRevision) 00383 result = ack->m_data[0] == 255; 00384 00385 mtInterface->releaseXbusMessage(ack); 00386 return result; 00387 } 00388 00389 /*! \brief C-wrapper for sendXbusMessage callback function of FwUpdate. 00390 */ 00391 static void sendXbusMessageWrapper(XbusMessage const* xbusMessage) 00392 { 00393 if (mtInterface) 00394 mtInterface->sendXbusMessage(xbusMessage); 00395 } 00396 00397 00398 /*! \brief Helper function for converting a XbusLowLevelFormat to string. 00399 */ 00400 static char* lowLevelFormatToString(XbusBusFormat format) 00401 { 00402 switch (format) 00403 { 00404 case XBF_I2c: 00405 return "I2C"; 00406 case XBF_Spi: 00407 return "SPI"; 00408 case XBF_Uart: 00409 return "UART"; 00410 } 00411 return "unknown"; 00412 } 00413 00414 00415 /*! \brief Print usage info of this example. 00416 */ 00417 static void printUsageInfo() 00418 { 00419 pc.printf("\r\nEmbedded firmware updater example\r\n"); 00420 pc.printf("Interface: %s\r\n\r\n", lowLevelFormatToString(mtInterface->busFormat())); 00421 pc.printf("h: Print this text\r\n"); 00422 pc.printf("c: GotoConfig\r\n"); 00423 pc.printf("m: GotoMeasurement\r\n"); 00424 pc.printf("r: Soft reset the module\r\n"); 00425 pc.printf("b: GotoBootloader\r\n"); 00426 pc.printf("v: Request firmware revision\r\n"); 00427 pc.printf("d: Request deviceId\r\n"); 00428 pc.printf("u: Start firmware update (make sure module is in bootloader mode)\r\n"); 00429 pc.printf("x: Hard reset the module and make it stay in bootloader\r\n"); 00430 pc.printf("\r\n"); 00431 } 00432 00433 /*! \brief Main entry point of the embedded firmware updater example. 00434 */ 00435 int main() 00436 { 00437 resetLine.mode(OpenDrain); 00438 // Configure communication with the pc: 00439 pc.baud(921600); 00440 pc.format(8, Serial::None, 1); 00441 pc.printf("\r\n\r\n\r\n--------------------------------------\r\n"); 00442 00443 // Initialize the mtInterface object for communicating with the module: 00444 createMtInterface(); 00445 00446 // If Uart mode is used update the baudrate to match the baudrate of the module: 00447 if (mtInterface->busFormat() == XBF_Uart) 00448 updateUartBaudrate(); 00449 00450 // Reset the module 00451 hardwareReset(false); 00452 00453 // Initialize the firmware updater: 00454 g_fwUpdate = new FwUpdate(); 00455 uint8_t* fwuTxBuffer = new uint8_t[FWU_REQUIRED_TXBUFFER_SIZE]; 00456 g_fwUpdate->m_readXffData = readXffData; 00457 g_fwUpdate->m_sendXbusMessage = sendXbusMessageWrapper; 00458 g_fwUpdate->m_readyHandler = readyHandler; 00459 g_fwUpdate->m_txBuffer = fwuTxBuffer; 00460 FwUpdate_init(g_fwUpdate); 00461 00462 printUsageInfo(); 00463 00464 // Main loop: 00465 bool running = true; 00466 while (running) 00467 { 00468 mtInterface->process(); 00469 00470 XbusMessage* xbusMessage = mtInterface->getXbusMessage(); 00471 bool updateUartBaudrateRequired = false; 00472 if (xbusMessage != NULL) 00473 { 00474 handleXbusMessage(xbusMessage); 00475 updateUartBaudrateRequired = (mtInterface->busFormat() == XBF_Uart && (xbusMessage->m_mid == XMID_ResetAck || xbusMessage->m_mid == XMID_GotoBootLoaderAck)); 00476 mtInterface->releaseXbusMessage(xbusMessage); 00477 } 00478 00479 if (updateUartBaudrateRequired) 00480 { 00481 wait(0.2); 00482 updateUartBaudrate(); 00483 } 00484 00485 if (pc.readable()) 00486 { 00487 char cmd = pc.getc(); 00488 switch (cmd) 00489 { 00490 case 'h': 00491 { 00492 printUsageInfo(); 00493 } break; 00494 00495 case 'c': 00496 { 00497 gotoConfig(); 00498 } break; 00499 00500 case 'm': 00501 { 00502 XbusMessage xbusMessage(XMID_GotoMeasurement); 00503 mtInterface->sendXbusMessage(&xbusMessage); 00504 } break; 00505 00506 case 'r': 00507 { 00508 XbusMessage xbusMessage(XMID_Reset); 00509 mtInterface->sendXbusMessage(&xbusMessage); 00510 } break; 00511 00512 case 'b': 00513 { 00514 XbusMessage xbusMessage(XMID_GotoBootLoader); 00515 mtInterface->sendXbusMessage(&xbusMessage); 00516 } break; 00517 00518 case 'v': 00519 { 00520 XbusMessage xbusMessage(XMID_ReqFirmwareRevision); 00521 mtInterface->sendXbusMessage(&xbusMessage); 00522 } break; 00523 00524 case 'd': 00525 { 00526 XbusMessage xbusMessage(XMID_ReqDid); 00527 mtInterface->sendXbusMessage(&xbusMessage); 00528 } break; 00529 00530 case 'u': 00531 { 00532 if (isInBootloader()) 00533 { 00534 pc.printf("Starting firmware update\r\n"); 00535 FwUpdate_init(g_fwUpdate); 00536 FwUpdate_start(g_fwUpdate); 00537 } 00538 else 00539 { 00540 pc.printf("Firmware update not possible now. First switch module to bootloader.\r\n"); 00541 } 00542 } break; 00543 00544 case 'x': 00545 { 00546 hardwareReset(true); 00547 } break; 00548 } 00549 } 00550 } 00551 00552 delete g_fwUpdate; 00553 delete[] fwuTxBuffer; 00554 return -1; 00555 } 00556
Generated on Wed Jul 13 2022 07:56:15 by 1.7.2