乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      物聯(lián)網(wǎng)應用中,STM32在線升級的設計思路

       袁先森lemon 2019-04-11

      在線升級流程:stm32程序的第一條指令,存儲地址的基地址0x8000000開始執(zhí)行。IAP程序升級的執(zhí)行是在BootLoader引導文件執(zhí)行后,進行加載、跳轉APP程序。所以每次上電后進入BootLoader判斷是否升級,如果升級則將外部FLASH中的bin文件復制寫入到ROM中,再接跳轉,如果不升級則直接跳轉app程序。

      BootLoader和app程序的FLASH大小需要根據(jù)自己的程序情況自由的分配大小就可以了。

      一、在線獲取BIN文件

              獲取bin文件方式:設備端利用wifi或者gprs通訊模組,使用MQTT協(xié)議(基于TCP/IP),通過消息隊列的方式接受服務端的升級命令。當接收到升級指令時,設備端會新增一個TCP/IP通道,專門用來傳輸bin文件數(shù)據(jù),并將接收的bin文件存入外部flash中,同時將升級標志位置1。升級標志位存儲在外部flash中。

      二、IAP到APP應用程序的跳轉   

      STM32的內部閃存(FLASH)地址起始于0x08000000,一般情況下,程序文件就從此地址開始寫入。

      STM32F103ZET6的內部閃存(FLASH)地址為0x8000000-0x0807ffff,一共512KB空間。將512KB的空間分成兩塊,一塊存放BootLoader的程序,用來判斷升級跳轉APP,根據(jù)實際代碼量來合理分配空間。本例程BootLoader分配了0x8000000-0x0800ffff的地址,64KB大小的空間。用戶程序APP地址為0x8010000-0x807ffff。

          IAP(BootLoader)程序運行先判斷外部flash的升級標志位是否有置1,若為1,將外部flash存儲的bin文件復制到內部ROM中,同時將升級標志位清0。然后判斷寫入ROM的文件是否為正確的應用程序,再完成跳轉。

      三、IAP程序代碼

      1.讀取升級標志位和bin文件的大小

      // 讀升級標志位  

       W25QXX_Read(ADDR_UPDATE_TAG,tagBuff1,1);

       printf(' ADDR_UPDATE_TAG is 0x%04X \r\n',tagBuff1[0]);

      delay_ms(100);

      // 讀bin文件長度                

       W25QXX_Read(ADDR_UPDATE_length,lengthBuff,3);

       for(i=0;i<3;i++)

               {

                len=(u32)lengthBuff[0]<<16;

          len|=(u32)lengthBuff[1]<<8;

          len|=(u32)lengthBuff[2]<<0;                 

               }

       printf(' len is %d \r\n',len);

      2.判斷是否升級。如果升級則開始將外部flash的程序復制到內部ROM中

      // 如果升級標志位等于1開始轉移程序

                if(tagBuff1[0]==0x31)

               {

                   u16 filelen=0;

                        u16 filepacketnum=0;

                        u16 remain = 0;

                        filepacketnum=len/2048;

                        if(len%2048) filepacketnum++;

                        for(i=0; i<filepacketnum; i++)

                        {

                                          if(len / 2048)

                                          {

                                                   remain= 2048;       

                                          }

                                          else

                                          {

                                                   remain= len % 2048;

                                          }

                                          printf('read flash to  rBuff1 \r\n');

                                          W25QXX_Read(ADDR_CODE+i*2048,rBuff1,remain);

      //判斷是否為flash應用程序,如果是就執(zhí)行更新,如果不是不更新

       if(i==0)

               {     printf('Theaddress of 20001000 is %08x\r\n',(*(vu32*)0X20001000));

      if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)

                        {        

                                    printf('UpdateFirmware...\r\n'); 

                        }

      else

                      {

                                  printf('Non-flashapplications!\r\n');

                                  tagBuff1[0]=0x30;

                           W25QXX_Write(ADDR_UPDATE_TAG,tagBuff1,1);

                                                            break;

                        }

                     }      

      //如果是應用程序,將數(shù)據(jù)寫入STMflash

                                 iap_write_appbin(FLASH_APP1_ADDR+i*2048,rBuff1,remain);  

                           filelen -= 2048;

               }      

       3.升級到內部ROM完成,將標志位清除

                        if(i == filepacketnum)

                        {

                               printf('-----Updatecompleted-------!\r\n');                

                                          tagBuff1[0]=0x30;

                                          W25QXX_WAKEUP();

                                          W25QXX_Erase_Sector(ADDR_UPDATE_TAG); 

                     W25QXX_Write(ADDR_UPDATE_TAG,tagBuff1,1);

               //測試寫入標志位是否成功

                                          W25QXX_Read(ADDR_UPDATE_TAG,tagBuff2,1);

                      printf(' ADDR_UPDATE_TAGis 0x%04X \r\n',tagBuff2[0]);

                           delay_ms(200);

                        }      

               4.升級完成后判斷寫入的bin文件是否正確,若正確則跳轉到FLASH_APP1_ADDR

                                 delay_ms(200);

                                 printf('Judgingwhether the application is correct!\r\n');

       if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)

                {      

                  printf('Firmware packagecorrect!\r\n');

                  iap_load_app(FLASH_APP1_ADDR);

                 }else

                  {

                   printf('Firmware packageerror\r\n');

                  }      

      5.跳轉之前,需要將使用過的外設關閉,如中斷定時器串口等

      voidiap_load_app(u32 appxaddr)

      {

               if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//檢查棧頂?shù)刂肥欠窈戏?/p>

               {

                        jump2app=(iapfun)*(vu32*)(appxaddr+4);                              

                        MSR_MSP(*(vu32*)appxaddr);                                          

              __disable_irq();

                        TIM_DeInit(TIM3);

                        USART_DeInit(USART1);

                        SPI_I2S_DeInit(SPI1);

                        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,DISABLE); 

                        GPIO_DeInit(GPIOF);

                        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,DISABLE);

                        GPIO_DeInit(GPIOG);

                        jump2app();                                                                            

               }

      }      

      注意:

      (1)

      __disable_irq();

                        TIM_DeInit(TIM3);

                        USART_DeInit(USART1);

                        SPI_I2S_DeInit(SPI1);

                        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,DISABLE); 

                        GPIO_DeInit(GPIOF);

                        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,DISABLE);

                        GPIO_DeInit(GPIOG);

      跳轉前,使用過的定時器、中斷、串口、GPIO都需要關閉,否則跳轉會失敗。只關閉了部分,可能能跳轉,但是會有一定概率的產(chǎn)生死機,多次復位才能正常運行。

      (2)

      u8 rBuff1[2048]__attribute__((at(0X20001000)));

      if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)

      定義了數(shù)組分配的內存地址是0X20001000起,用來從外部flash向stmflash轉移bin文件。

      而bin文件的第4-7的4個字節(jié)的值是app程序復位中斷向量的值。固定格式是08xxxxxxxx。

      (3)

      #defineFLASH_APP1_ADDR            0x08010000

      if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//檢查棧頂?shù)刂肥欠窈戏?/p>

      即取0x80010000開始到0x8010003的4個字節(jié)的值,因為我們的應用程序APP中設置把中斷向量表放置在0x08010000開始的位置; 而中斷向量表里第一個放的就是棧頂?shù)刂返闹怠_@句話即通過判斷棧頂?shù)刂分凳欠裾_來判斷是否應用程序已經(jīng)下載了,因為應用程序的啟動文件剛開始就去初始化化??臻g,如果棧頂值對了,說明應用程序已經(jīng)下載了啟動文件,初始化也執(zhí)行了。

      四、APP程序代碼

         1.通過JSON解析MQTT消息隊列下發(fā)的升級命令

      CLR_CMD_UPDATE_BIN,獲取bin文件包的信息。

             case CLR_CMD_UPDATE_BIN:

             updateBinVersion = cJSON_GetObjectItem(pRoot,'version')->valuestring;

             updateBinFileName = cJSON_GetObjectItem(pRoot,'fileName')->valuestring;

             countPackage = atoi(cJSON_GetObjectItem(pRoot,'countPackage')->valuestring);

             pJsonNode = cJSON_GetObjectItem(pRoot, 'totalLength');//實際文件大小

             totalLength = atoi(pJsonNode->valuestring);

             updateBinPort = cJSON_GetObjectItem(pRoot, 'fileServerPort')->valuestring;

             pJsonNode = cJSON_GetObjectItem(pRoot, 'fileServerIp');

             if (pJsonNode != NULL)

             {

               updateBinIp = pJsonNode->valuestring;

               rt_kprintf('version:%s\n', updateBinVersion);

               rt_kprintf('IP:%s\n', updateBinIp);

               rt_kprintf('Port:%s\n', updateBinPort);

               rt_kprintf('updateBinFilenName:%s\n', updateBinFileName);

               rt_kprintf('countPackage:%d\n', countPackage);

               rt_kprintf('totalLength:%d\n', totalLength);

                param_buf.ip = updateBinIp;

               param_buf.port = updateBinPort;

               param_buf.fileName = updateBinFileName;

               param_buf.countPackage = countPackage;

               param_buf.totalLength = totalLength;

      2.     關閉原有的TCP通道,刪除GPRS任務(本次使用的是GPRS模組),創(chuàng)建新的TCP任務新建TCP連接(此TCP在本例中專用于升級BIN)。

               close_tcp();

               /********* delete mqtt thread ************/

               rt_thread_delay(50);

               rt_err_t rt_err;

               rt_err = rt_thread_delete(gprs_thread);

      #ifdef KT_PRINTF_DEBUG

                if (rt_err != RT_EOK)

               {

                 rt_kprintf('\r\n mqtt task delete failed!\r\n');

               }

               else

               {

                 rt_kprintf('\r\n mqtt task delete successed!\r\n');

                 /********* 創(chuàng)建 tcp 任務 ************/

                  tcp_thread =rt_thread_create('tcp',

                                               tcp_thread_entry, /* tcp_thread_entry */

                                               RT_NULL,          /* 入口參數(shù)是RT_NULL */

                                               2048,             /* 分配空間大小 */

                                               1,                /* 任務優(yōu)先級 */

                                               20);              /* 時間片 */

                 if (tcp_thread != RT_NULL)

                    rt_thread_startup(tcp_thread);

                 else

                    rt_kprintf('\r\n createtcp_thread failed!!\r\n');

               }

      #endif

             }

             break;

      3. 接收bin文件,存入外部flash中,接收完將升級標志位置1

      //擦除bin存儲地址

        for(int i = 0; i < countPackage; i++)

        {

         int offset = i * 0x1000;

         W25Q128FV_Erase_Sector((Addr_UPDATE_BIN + offset) / 4096);

        }

        //接收數(shù)據(jù)包

        for(int j = 1; j <= countPackage; j++)

        {

         TCP_DATA_TRANSFORM(j, updateBinFileName);

         rt_thread_delay(50);

        }

       //將升級標志1存入flash中

       uint8_t *tag = '1';

       W25Q128FV_Erase_Sector(ADDR_UPDATE_TAG / 4096);

       SPI_FLASH_PageWrite(tag, ADDR_UPDATE_TAG, 1);

       uint8_t rBuff[1];

       SPI_FLASH_Read(rBuff, ADDR_UPDATE_TAG, 1);

       rt_kprintf(' ADDR_UPDATE_TAG is %s \r\n', rBuff);

       //將bin包大小存入flash中

        intptl = param_buf.totalLength;

       uint8_t d[3];

        d[0]= ptl >> 16 & 0xff;

       d[1] = ptl >> 8 & 0xff;

       d[2] = ptl & 0xff;

       SPI_FLASH_PageWrite( d, ADDR_UPDATE_TAG + 1, 3);

      //斷開tcp連接,關閉看門狗電路讓單片機斷電復位復位

       disconnectToServer();

       rt_kprintf('^^^^^^^^^^^^^^^^^^^^^^^^^^^tcp_thread

      is died!^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n');

       rt_thread_delete(watchdog_thread);

      4.接收單個bin數(shù)據(jù)分包

       TCP數(shù)據(jù)單包交互方法

       [0],[1] => 當前包序號

       [2],[3] => 當前包長度

       [4].... => 包內容

       末尾4位是crc校驗位

       1、組需要發(fā)送的數(shù)據(jù)包

       2、通過串口發(fā)送數(shù)據(jù)包

       3、接受服務器返回的數(shù)據(jù)包

       4、對比從串口獲取的數(shù)據(jù)包實際長度和 從服務器數(shù)據(jù)包內定義的長度,  不相等則重發(fā)

        int返回值一次讀取的數(shù)據(jù)長度

      int TCP_DATA_TRANSFORM(int packageIndex,char *fileName)

      {

       buildSendP   ackage((char*)content, packageIndex, fileName);

       rt_kprintf(' \r\n content  is  %s \r\n', content);

       transport_gprs_sendPacketBuffer(content, strlen((char *)content));

        intpIndex, pLength;

       wait_for_tcp_data(CRT_HEAD_LENGTH, 10);

       char *buf = buf_uart2.buf;

       memcpy(tcpReceiveBuf, buf + 11, buf_uart2.index);

        //包序號

       pIndex = (tcpReceiveBuf[0] & 0xff) << 8 | tcpReceiveBuf[1]& 0xff;

        //包長度

       pLength = (tcpReceiveBuf[2] & 0xff) << 8 | tcpReceiveBuf[3]& 0xff;

       rt_kprintf(' \r\n  server saypIndex is _____%d____   pLength   is ____%d____  \r\n', pIndex,pLength);

       unsigned char *reBuf = tcpReceiveBuf;

       uint32_t deCodeCRC = my_crc32(reBuf, pLength - 4);

       char crcStr[4] = {0};

       unsigned char crcArray[4] = {tcpReceiveBuf[pLength - 4],tcpReceiveBuf[pLength - 3], tcpReceiveBuf[pLength - 2], tcpReceiveBuf[pLength -1]};

       byteArrayToHexStr(crcArray, crcStr);

       uint32_t serverCRC = htoi(crcStr);

       rt_kprintf(' \r\n deCodeCRC is %d , serverCRC   is %d  \r\n', deCodeCRC,serverCRC);

        if(serverCRC > 0 && deCodeCRC > 0 && serverCRC ==deCodeCRC)

        {

         // for (int i = 4; i < pLength; i++)

         // {

         //   rt_kprintf('%02x',tcpReceiveBuf[i]);

         // }

         // rt_kprintf('\r\n');

         int pOffset = 0X400 * (packageIndex - 1);

         SPI_FLASH_PageWrite(reBuf + 4, Addr_UPDATE_BIN + pOffset, 1024);

      //////////////////////////////

         uint8_t binBuff2[256];

         SPI_FLASH_Read(binBuff2, Addr_UPDATE_BIN + pOffset, 256);

         rt_kprintf(' \r\n binBuff2 is  \r\n');

         for (size_t i = 0; i < 256; i++)

          {

           rt_kprintf('%02x', binBuff2[i]);

          }

         rt_kprintf('\r\n');

         return pLength - 8;

        }

       else

        {

         return TCP_DATA_TRANSFORM(packageIndex, fileName);

        }

      }

      五、APP程序配置

      中斷向量偏移設置

      修改代碼存放的地址空間

       

      六、服務器側,程序代碼

      1.立即執(zhí)行固件更新 1、查詢數(shù)據(jù)庫bin 2、獲取所有設備sn列表 3、通知設備開始更新了,內容包括:文件名,大小,版本號

           */

          @RequestMapping(value = '/update')

          @ResponseBody

          public Object update(LongdeviceBinId) {

              DeviceBinbin = deviceBinService.selectById(deviceBinId);

              if(bin == null)

                  throw newGunsException(BizExceptionEnum.UPDATE_BIN_NOT_EXISTED);

              if(MinaConfig.fileCacheInit(bin)) {

                  deviceBinService.setBinActive(deviceBinId);

              }else

                  throw newGunsException(BizExceptionEnum.UPDATE_BIN_FAILD);

       List<byte[]>cacheList = CacheKit.get(Cache.BIN_GROUP, CacheKey.BIN_NAME);

              StringfilenName = bin.getFileName();

           Stringversion = filenName.substring(filenName.indexOf('_') + 1,filenName.lastIndexOf('.'));

              StringcountPackage = String.valueOf(cacheList.size());

              StringtotalLength = String.valueOf(bin.getFileData().length);

              StringfileServerIp = env.getProperty('spring.tcp.host');

              StringfileServerPort = env.getProperty('spring.tcp.port');              

              JSONObjectobj = new JSONObject();

              obj.put('method','updateBin');

              obj.put('fileName',filenName);

              obj.put('version',version);

              obj.put('countPackage',countPackage);

              obj.put('totalLength',totalLength);

              obj.put('fileServerIp',fileServerIp);

              obj.put('fileServerPort',fileServerPort);

              logger.info('更新固件下發(fā)命令:{}',obj.toJSONString());

      List<Device>list= deviceService.selectList(newEntityWrapper<Device>().eq('is_onLine', 1));

              Message<String>message;

              Device  device;

              for(int i = 0,size=list.size() ; i < size; i++) {

                  device = list.get(i);

      if (device != null &&StringUtils.isNotBlank(device.getSnNum())) {

         message= MessageBuilder.withPayload(obj.toJSONString())

                              .setHeader(MqttHeaders.TOPIC,MqttConst.getCourrentIssueCmd(device.getSnNum())).build();

                      mqtt.handleMessage(message);

                      if(i%10== 0) {

                          try {Thread.sleep(1000);} catch(InterruptedException e) {e.printStackTrace();}  

                      }

                  }

              }

              returnSUCCESS_TIP;

          }

      2.分片bin數(shù)據(jù)包,存入數(shù)據(jù)緩存 2 + 2 + data + 4 分包序號 +發(fā)送數(shù)據(jù)包總長度 + 數(shù)據(jù)包 + crc校驗碼

           *

           *@param bin

           */

          public static booleanfileCacheInit(DeviceBin bin) {

              intfileSizeSlice = FILE_SLICE_SIZE;

              // 分片大小等于1k

              if(bin != null) {

                  byte[] bytes = bin.getFileData();

                  int bytesSize = bytes.length;

                  int totalDataPackage = (int)Math.ceil((float) bytesSize / fileSizeSlice);

                  logger.info('需要發(fā)送的總包數(shù):' + totalDataPackage);

                  int currentFileSizeSlice, offsize,floorDataPackage, j, sliceIndex, packageLength, crcLength = 4;

                  floorDataPackage = bytesSize /fileSizeSlice;

                  List<byte[]> bufferArray = new ArrayList<>(128);

                  for (int i = 1; i <= totalDataPackage;i++) {

                      currentFileSizeSlice= fileSizeSlice;// 當前文件分包大小

                      if(i > floorDataPackage) {

                          currentFileSizeSlice = bytesSize %fileSizeSlice;

                      }

                      byte[]preSendData = new byte[2 + 2 + currentFileSizeSlice];

                      // 低位在前,高位在后

                      // 分包序號

                      sliceIndex= i;

                      j =0;

                      preSendData[j++]= (byte) ((sliceIndex >> 8) & 0xff);

                      preSendData[j++]= (byte) (sliceIndex & 0xff);

                      // 分包長度

                      packageLength= preSendData.length + crcLength;

                      preSendData[j++]= (byte) ((packageLength >> 8) & 0xff);

                      preSendData[j++]= (byte) (packageLength & 0xff);

                      offsize= fileSizeSlice * (i - 1);// 分包偏移量

                      System.arraycopy(bytes,offsize, preSendData, j, currentFileSizeSlice);

                      //crc32校驗

                      CRC32crc32 = new CRC32();

                      crc32.update(preSendData);

                      ByteBufferbuffer = ByteBuffer.allocate(8);

                      buffer.putLong(crc32.getValue());

                      logger.info('packageindex {},crc32 code is {}', i, crc32.getValue());

                      byte[]sendData = new byte[packageLength];

                      System.arraycopy(preSendData,    0, sendData, 0, preSendData.length);

                      System.arraycopy(buffer.array(),4, sendData, preSendData.length, crcLength);

                      bufferArray.add(sendData);

                  }

                  CacheKit.put(Cache.BIN_GROUP,CacheKey.BIN_NAME, bufferArray);

                  logger.info('bin file cached success!');

                  return true;

              }

              returnfalse;

          }

      3.往設備端發(fā)送bin的分包

          public void messageReceived(IoSessionsession, Object message) throws Exception {

              StringstrMsg = message.toString();

              logger.info('服務端接收到的數(shù)據(jù)為:  {}',strMsg);

              if(strMsg.trim().equalsIgnoreCase(EXIT)) {

                  session.closeOnFlush();

                  return;

              }

              JSONObjectobj = JSON.parseObject(strMsg);

              //String fileName = obj.getString('fileName');

              intpackageIndex = obj.getIntValue('packageIndex');

              List<byte[]>cacheList = CacheKit.get(Cache.BIN_GROUP, CacheKey.BIN_NAME);

              if(packageIndex > cacheList.size()) {

                  return;

              }

              byte[]buf = cacheList.get(packageIndex - 1);

              IoBufferio = IoBuffer.wrap(buf, 0, buf.length);

              session.write(io);

          }

      作者:馮美文、應曉川

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多