Ir ao conteúdo

PIC32 Bootloader - CRC


luckkaz

Posts recomendados

Postado

Oi

Eu estou usando o PIC32MX795F512H, e to fazendo um bootloader via serial(a partir do exemplo da microchip) usando o programa "PIC32 bootloader application V1.2", dai eu gostaria de saber como esse programa calcula o CRC e o CRC flash, pois eu gostaria de comunicar o PIC com um outro microcontrolador.

Esse link é do application notes (An1388) e o source code (programa) do bootloader.

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en554836

Desde já agradeço...

Postado

Acho que sua pergunta esta mal formada.

Onde o CRC entra na comunicação dos PICs?

voce pretende atualizar o firmware de um PIC usando outro?

Postado

É exatamente isso. Pretendo atualizar o firmware do PIC usando outro microcontrolador.

Porém o que acontece, é que o Bootloader faz uma comunicação com o programa que eu estou usando pra atualizar o firmware pela serial do PC (o Bootloader application V1.2). Ele manda um cabeçalho e dados (ou comandos) e um CRC (crc low e crc high), e então o PIC responde da mesma forma, porém como eu quero atualiaz um PIC com outro, eu preciso saber como é o calculado o CRC.

O protocolo de comunicação esta descrito no application notes AN1388 na paginas 9 e 10.

Postado

O software no caso é um mestre (envia escrita), para você usar um PIC para gravar outro, você precisa implementar o protocolo mestre no PIC, ou seja, a mesma logica que foi feita no software

Postado

Aqui estou botando o protocolo de comunicação entre o Programa no PC e o PIC:

Nessas imagens estão os

comandos;

inicialização da comunicação;

apagar a flash do PIC;

Programar:

Ler o CRC;

Run application;

e também um print da parte inicial da comunicação;

Está tudo bem explicado, porém eu não sei como implementar o Programa do PC em um microcontrolador, pois não sei como Fazer as partes dos CRC's.

post-943234-13884961651775_thumb.jpg

post-943234-13884961652229_thumb.jpg

post-943234-13884961652527_thumb.jpg

post-943234-13884961652708_thumb.jpg

post-943234-13884961653035_thumb.jpg

Postado

Pois é, o meu problema mesmo é que tem um CRC a cada instrução (por exemplo para a pagar a flash é só, 0x02, CRCL, CRCH, e EOT), e no Read CRC tem o CRC flash (que é o CRC te tudo enviado pela serial), só que no código do bootloader e do Programa do PC eu não consigo achar qual é o código de cada um (eu não consigo diferenciar os dois).

Postado

Ao meu entender existe mais codicos. Para o PIC calcular o CRC ele precisa ter a logica do calculo que sera gravado pelo software, visto que na gravação do Bootloader o pic não tem nada.

Deve ver qual é o tamanho de cada codico enviado, uma implementação que conheço do CRC é no protocolo modbus, cada codico enviado tem 8 valores hexa, ao final do codico tem dois valores em hexa do calculo CRC, um com CRC L e outro com CRC H.

Posso te arrumar a logica do calculo CRC em basic e em C.

No que entendi no protoco Bootloader cada codico enviado termina com EOT, o CRC +- (calculado) são dois Hexa anteriores.

Postado

O CRC do Modbus usa um polinómio = 0xFFFF,o usado no Bootloader é o CCIT = 0x1021.

lucas,deixa eu te explicar sobre arquivos Intel Hex.

:10246200464C5549442050524F46494C4500464C33

Depois dos ':'voce tem o tamanho dos dados(10 Hex = 16 bytes),depois vem o endereço a ser gravado (2 bytes = 2462H),então vem o tipo de dado (1 byte = 00),aí começa os dados a serem gravados(no exemplo 16 bytes = 464C...464C)e por ultimo o checksum = 33.

O checksum é calculado por linha do arquivo e é formado somando todos os bytes -1 e fazendo um NOT.

Postado

Sim sim, você esta certo vtrx, hj eu consegui pesquisar tudo isso, sobre arquivos intel hex, porém estou tendo dificuldades em interpretar os codigos abaixo, que são as partes onde são calculados os CRC's.

/*********************************************************************

*

* PIC32 Boot Loader

*

*********************************************************************

* FileName: Framework.c

* Dependencies:

* Processor: PIC32

*

* Compiler: MPLAB C32

* MPLAB IDE

* Company: Microchip Technology, Inc.

*

* Software License Agreement

*

* The software supplied herewith by Microchip Technology Incorporated

* (the “Company”) for its PIC32 Microcontroller is intended

* and supplied to you, the Company’s customer, for use solely and

* exclusively on Microchip PIC32 Microcontroller products.

* The software is owned by the Company and/or its supplier, and is

* protected under applicable copyright laws. All rights are reserved.

* Any use in violation of the foregoing restrictions may subject the

* user to criminal sanctions under applicable laws, as well as to

* civil liability for the breach of the terms and conditions of this

* license.

*

* THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,

* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED

* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A

* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,

* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR

* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.

*

*

* $Id: $

* $Name: $

*

**********************************************************************/

#include "GenericTypeDefs.h"

#include "HardwareProfile.h"

#include "Include\BootLoader.h"

#include "Include\Framework\Framework.h"

#include "Include\NVMem.h"

#include <string.h>

#include <plib.h>

#define DATA_RECORD 0

#define END_OF_FILE_RECORD 1

#define EXT_SEG_ADRS_RECORD 2

#define EXT_LIN_ADRS_RECORD 4

#define FLASH_PAGE_SIZE 4096

#define DEV_CONFIG_REG_BASE_ADDRESS 0x9FC02FF0

#define DEV_CONFIG_REG_END_ADDRESS 0x9FC02FFF

typedef enum

{

READ_BOOT_INFO = 1,

ERASE_FLASH,

PROGRAM_FLASH,

READ_CRC,

JMP_TO_APP

}T_COMMANDS;

typedef struct

{

UINT Len;

UINT8 Data[FRAMEWORK_BUFF_SIZE];

}T_FRAME;

typedef struct

{

UINT8 RecDataLen;

DWORD_VAL Address;

UINT8 RecType;

UINT8* Data;

UINT8 CheckSum;

DWORD_VAL ExtSegAddress;

DWORD_VAL ExtLinAddress;

}T_HEX_RECORD;

static const UINT8 BootInfo[2] =

{

MAJOR_VERSION,

MINOR_VERSION

};

static T_FRAME RxBuff;

static T_FRAME TxBuff;

static BOOL RxFrameValid;

static BOOL TriggerBaudChange;

static DWORD_VAL NewBaud;

static BOOL RunApplication = FALSE;

void HandleCommand(void);

void BuildRxFrame(UINT8 *RxData, INT16 RxLen);

UINT GetTransmitFrame(UINT8* Buff);

void WriteHexRecord2Flash(UINT8* HexRecord, UINT totalRecLen);

BOOL BaudRateChangeRequested(void);

UINT16 CalculateCrc(UINT8 *data, UINT32 len);

/********************************************************************

* Function: FrameWorkTask()

*

* Precondition:

*

* Input: None.

*

* Output: None.

*

* Side Effects: None.

*

* Overview: Process the command if there is a valid fame.

*

*

* Note: None.

********************************************************************/

void FrameWorkTask(void)

{

if(RxFrameValid)

{

// Valid frame received, process the command.

HandleCommand();

// Reset the flag.

RxFrameValid = FALSE;

}

}

/********************************************************************

* Function: HandleCommand()

*

* Precondition:

*

* Input: None.

*

* Output: None.

*

* Side Effects: None.

*

* Overview: Process the received frame and take action depending on

the command received.

*

*

* Note: None.

********************************************************************/

void HandleCommand(void)

{

UINT8 Cmd;

DWORD_VAL Address;

UINT8 i;

DWORD_VAL Length;

UINT8 *DataPtr;

UINT Result;

WORD_VAL crc;

void* pFlash;

// First byte of the data field is command.

Cmd = RxBuff.Data[0];

// Partially build response frame. First byte in the data field carries command.

TxBuff.Data[0] = RxBuff.Data[0];

// Reset the response length to 0.

TxBuff.Len = 0;

// Process the command.

switch(Cmd)

{

case READ_BOOT_INFO: // Read boot loader version info.

memcpy(&TxBuff.Data[1], BootInfo, 2);

//Set the transmit frame length.

TxBuff.Len = 2 + 1; // Boot Info Fields + command

break;

case ERASE_FLASH:

pFlash = (void*)APP_FLASH_BASE_ADDRESS;

for( i = 0; i < ((APP_FLASH_END_ADDRESS - APP_FLASH_BASE_ADDRESS + 1)/FLASH_PAGE_SIZE); i++ )

{

Result = NVMemErasePage( pFlash + (i*FLASH_PAGE_SIZE) );

// Assert on NV error. This must be caught during debug phase.

ASSERT(Result==0);

}

//Set the transmit frame length.

TxBuff.Len = 1; // Command

break;

case PROGRAM_FLASH:

WriteHexRecord2Flash(&RxBuff.Data[1], RxBuff.Len-3); //Negate length of command and CRC RxBuff.Len.

//Set the transmit frame length.

TxBuff.Len = 1; // Command

break;

case READ_CRC:

// Get address from the packet.

memcpy(&Address.v[0], &RxBuff.Data[1], sizeof(Address.Val));

memcpy(&Length.v[0], &RxBuff.Data[5], sizeof(Length.Val));

crc.Val = CalculateCrc((UINT8 *)Address.Val, Length.Val);

memcpy(&TxBuff.Data[1], &crc.v[0], 2);

//Set the transmit frame length.

TxBuff.Len = 1 + 2; // Command + 2 bytes of CRC.

break;

case JMP_TO_APP:

// Exit firmware upgrade mode.

RunApplication = TRUE;

break;

default:

// Nothing to do.

break;

}

}

/********************************************************************

* Function: BuildRxFrame()

*

* Precondition:

*

* Input: Pointer to Rx Data and Rx byte length.

*

* Output: None.

*

* Side Effects: None.

*

* Overview: Builds rx frame and checks CRC.

*

*

* Note: None.

********************************************************************/

void BuildRxFrame(UINT8 *RxData, INT16 RxLen)

{

static BOOL Escape = FALSE;

WORD_VAL crc;

while((RxLen > 0) && (!RxFrameValid)) // Loop till len = 0 or till frame is valid

{

RxLen--;

if(RxBuff.Len >= sizeof(RxBuff.Data))

{

RxBuff.Len = 0;

}

switch(*RxData)

{

case só: //Start of header

if(Escape)

{

// Received byte is not só, but data.

RxBuff.Data[RxBuff.Len++] = *RxData;

// Reset Escape Flag.

Escape = FALSE;

}

else

{

// Received byte is indeed a só which indicates start of new frame.

RxBuff.Len = 0;

}

break;

case EOT: // End of transmission

if(Escape)

{

// Received byte is not EOT, but data.

RxBuff.Data[RxBuff.Len++] = *RxData;

// Reset Escape Flag.

Escape = FALSE;

}

else

{

// Received byte is indeed a EOT which indicates end of frame.

// Calculate CRC to check the validity of the frame.

if(RxBuff.Len > 1)

{

crc.byte.LB = RxBuff.Data[RxBuff.Len-2];

crc.byte.HB = RxBuff.Data[RxBuff.Len-1];

if((CalculateCrc(RxBuff.Data, (UINT32)(RxBuff.Len-2)) == crc.Val) && (RxBuff.Len > 2))

{

// CRC matches and frame received is valid.

RxFrameValid = TRUE;

}

}

}

break;

case DLE: // Escape character received.

if(Escape)

{

// Received byte is not ESC but data.

RxBuff.Data[RxBuff.Len++] = *RxData;

// Reset Escape Flag.

Escape = FALSE;

}

else

{

// Received byte is an escape character. Set Escape flag to escape next byte.

Escape = TRUE;

}

break;

default: // Data field.

RxBuff.Data[RxBuff.Len++] = *RxData;

// Reset Escape Flag.

Escape = FALSE;

break;

}

//Increment the pointer.

RxData++;

}

}

/********************************************************************

* Function: GetTransmitFrame()

*

* Precondition:

*

* Input: Buffer pointer.

*

* Output: Length of the buffer.

*

* Side Effects: None.

*

* Overview: Gets the complete transmit frame into the "Buff".

*

*

* Note: None.

********************************************************************/

UINT GetTransmitFrame(UINT8* Buff)

{

INT BuffLen = 0;

WORD_VAL crc;

UINT8 i;

if(TxBuff.Len)

{

//There is something to transmit.

// Calculate CRC of the frame.

crc.Val = CalculateCrc(TxBuff.Data, (UINT32)TxBuff.Len);

TxBuff.Data[TxBuff.Len++] = crc.byte.LB;

TxBuff.Data[TxBuff.Len++] = crc.byte.HB;

// Insert só (Indicates beginning of the frame)

Buff[buffLen++] = só;

// Insert Data Link Escape Character.

for(i = 0; i < TxBuff.Len; i++)

{

if((TxBuff.Data == EOT) || (TxBuff.Data == )

|| (TxBuff.Data == DLE))

{

// EOT//DLE repeated in the data field, insert DLE.

Buff[buffLen++] = DLE;

}

Buff[buffLen++] = TxBuff.Data;

}

// Mark end of frame with EOT.

Buff[buffLen++] = EOT;

TxBuff.Len = 0; // Purge this buffer, no more required.

}

return(BuffLen); // Return buffer length.

}

/********************************************************************

* Function: WriteHexRecord2Flash()

*

* Precondition:

*

* Input: HexRecord buffer.

*

* Output: None.

*

* Side Effects: None.

*

* Overview: Writes hex record to flash.

*

*

* Note: None.

********************************************************************/

void WriteHexRecord2Flash(UINT8* HexRecord, UINT totalHexRecLen)

{

static T_HEX_RECORD HexRecordSt;

UINT8 Checksum = 0;

UINT i;

UINT WrData;

UINT RdData;

void* ProgAddress;

UINT Result;

UINT nextRecStartPt = 0;

UINT8 temp[4];

while(totalHexRecLen>=5) // A hex record must be atleast 5 bytes. (1 Data Len byte + 1 rec type byte+ 2 address bytes + 1 crc)

{

HexRecord = &HexRecord[nextRecStartPt];

HexRecordSt.RecDataLen = HexRecord[0];

HexRecordSt.RecType = HexRecord[3];

HexRecordSt.Data = &HexRecord[4];

//Determine next record starting point.

nextRecStartPt = HexRecordSt.RecDataLen + 5;

// Decrement total hex record length by length of current record.

totalHexRecLen = totalHexRecLen - nextRecStartPt;

// Hex Record checksum check.

Checksum = 0;

for(i = 0; i < HexRecordSt.RecDataLen + 5; i++)

{

Checksum += HexRecord;

}

if(Checksum != 0)

{

//Error. Hex record Checksum mismatch.

}

else

{

// Hex record checksum OK.

switch(HexRecordSt.RecType)

{

case DATA_RECORD: //Record Type 00, data record.

HexRecordSt.Address.byte.MB = 0;

HexRecordSt.Address.byte.UB = 0;

HexRecordSt.Address.byte.HB = HexRecord[1];

HexRecordSt.Address.byte.LB = HexRecord[2];

// Derive the address.

HexRecordSt.Address.Val = HexRecordSt.Address.Val + HexRecordSt.ExtLinAddress.Val + HexRecordSt.ExtSegAddress.Val;

while(HexRecordSt.RecDataLen) // Loop till all bytes are done.

{

// Convert the Physical address to Virtual address.

ProgAddress = PA_TO_KVA0(HexRecordSt.Address.Val);

// Make sure we are not writing boot area and device configuration bits.

if(((ProgAddress >= (void *)APP_FLASH_BASE_ADDRESS) && (ProgAddress <= (void *)APP_FLASH_END_ADDRESS))

&& ((ProgAddress < (void*)DEV_CONFIG_REG_BASE_ADDRESS) || (ProgAddress > (void*)DEV_CONFIG_REG_END_ADDRESS)))

{

if(HexRecordSt.RecDataLen < 4)

{

// Sometimes record data length will not be in multiples of 4. Appending 0xFF will make sure that..

// we don't write junk data in such cases.

WrData = 0xFFFFFFFF;

memcpy(&WrData, HexRecordSt.Data, HexRecordSt.RecDataLen);

}

else

{

memcpy(&WrData, HexRecordSt.Data, 4);

}

// Write the data into flash.

Result = NVMemWriteWord(ProgAddress, WrData);

// Assert on error. This must be caught during debug phase.

ASSERT(Result==0);

}

// Increment the address.

HexRecordSt.Address.Val += 4;

// Increment the data pointer.

HexRecordSt.Data += 4;

// Decrement data len.

if(HexRecordSt.RecDataLen > 3)

{

HexRecordSt.RecDataLen -= 4;

}

else

{

HexRecordSt.RecDataLen = 0;

}

}

break;

case EXT_SEG_ADRS_RECORD: // Record Type 02, defines 4th to 19th bits of the data address.

HexRecordSt.ExtSegAddress.byte.MB = 0;

HexRecordSt.ExtSegAddress.byte.UB = HexRecordSt.Data[0];

HexRecordSt.ExtSegAddress.byte.HB = HexRecordSt.Data[1];

HexRecordSt.ExtSegAddress.byte.LB = 0;

// Reset linear address.

HexRecordSt.ExtLinAddress.Val = 0;

break;

case EXT_LIN_ADRS_RECORD: // Record Type 04, defines 16th to 31st bits of the data address.

HexRecordSt.ExtLinAddress.byte.MB = HexRecordSt.Data[0];

HexRecordSt.ExtLinAddress.byte.UB = HexRecordSt.Data[1];

HexRecordSt.ExtLinAddress.byte.HB = 0;

HexRecordSt.ExtLinAddress.byte.LB = 0;

// Reset segment address.

HexRecordSt.ExtSegAddress.Val = 0;

break;

case END_OF_FILE_RECORD: //Record Type 01, defines the end of file record.

default:

HexRecordSt.ExtSegAddress.Val = 0;

HexRecordSt.ExtLinAddress.Val = 0;

break;

}

}

}//while(1)

}

/**

* Static table used for the table_driven implementation.

*****************************************************************************/

static const UINT16 crc_table[16] =

{

0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,

0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef

};

/********************************************************************

* Function: CalculateCrc()

*

* Precondition:

*

* Input: Data pointer and data length

*

* Output: CRC.

*

* Side Effects: None.

*

* Overview: Calculates CRC for the given data and len

*

*

* Note: None.

********************************************************************/

UINT16 CalculateCrc(UINT8 *data, UINT32 len)

{

UINT i;

UINT16 crc = 0;

while(len--)

{

i = (crc >> 12) ^ (*data >> 4);

crc = crc_table[i & 0x0F] ^ (crc << 4);

i = (crc >> 12) ^ (*data >> 0);

crc = crc_table[i & 0x0F] ^ (crc << 4);

data++;

}

return (crc & 0xFFFF);

}

/********************************************************************

* Function: ExitFirmwareUpgradeMode()

*

* Precondition:

*

* Input: Void

*

* Output: True if firmware upgrade mode has to be exited.

*

* Side Effects: None.

*

* Overview: This function returns true if firmware mode has to be exited.

*

*

* Note: None.

********************************************************************/

BOOL ExitFirmwareUpgradeMode(void)

{

return RunApplication;

}

/**************************End of file**************************************************/

e

FRAMEWORK,h

#ifndef __FRAMEWORK_H__

#define __FRAMEWORK_H__

#define 01

#define EOT 04

#define DLE 16

#define FRAMEWORK_BUFF_SIZE 1000

#define FRAMEWORK_FrameWorkTask FrameWorkTask

#define FRAMEWORK_BuildRxFrame BuildRxFrame

#define FRAMEWORK_GetTransmitFrame GetTransmitFrame

#define FRAMEWORK_ExitFirmwareUpgradeMode ExitFirmwareUpgradeMode

// Exported functions

extern void FRAMEWORK_FrameWorkTask(void);

extern void FRAMEWORK_BuildRxFrame(UINT8 *RxData, INT16 RxLen);

extern UINT FRAMEWORK_GetTransmitFrame(UINT8* Buff);

extern BOOL FRAMEWORK_ExitFirmwareUpgradeMode(void);

#endif

Postado

Existe alguns detalhes que tem que ser exclarecido.

voce pretende usar outro PIC para 'gravar' o Firmware em um PIC 'receptor',mas como vai manter o arquivo Hex no PIC 'mestre'?

voce ,talvez,tenha que programar esse PIC 'mestre' todo baseado em #DEFINES ou usar 'Strings',o que vai dificultar muito.

voce poderia usar tambem,qualquer PIC com serial,tipo o 16F628,e manter o arquivo Hex(firmware) numa Eeprom externa,tipo 24C512.

Como pretende amarzenar o Hex(firmware)a ser gravado?

Qual a utilidade de se usar um PIC para gravar um Firmware em outro PIC usando um Bootloader,se voce pode usar Uma Eeprom e gravar normalmente usando baixa tensão,igual aos programadores fazem?

Postado

Na verdade eu não pretendo armazenar o arquivo hex. Eu vou manda-lo via wireless para um módulo (PIC mestre), para que este possa fazer com que o PIC escravo entre em modo bootloader via serial, e então passar todo o arquivo hex para o PIC escravo, que logo após irá rodar o novo Firmware.

Além disso tambem não posso usar eeprom.

No caso eu preciso gravar o pic a distância...

Postado
Apenas não entendi como vai fazer a gravação dos PICs em rede, ja que gravação do bootloader é por ICSP

Então Rafeal,o Bootloader usa serial entre outros,não usa ICSP.

  • 3 meses depois...
Postado

Olá a todos,

luckkaz estou tento o mesmo problema que você para calcular o CRC do comando do bootloader do PIC32. Você conseguiu resolver de algum modo? ou alguma ideia?

Muito obrigado, e qq duvida, só chamar.

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...