Important update: Arm Announces End of Life Timeline for Mbed. This site will be archived in July 2026. Read the full announcement.
Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
LPC Signature Generator
Neil Thiessen.
4
replies
And we have progress!!! It turns out that AN11208 over at LPCware has the code for generating a signature in software! In light of this, I think the obvious course of action is to create an mbed library that will work on any mbed-enabled microcontroller. The hardware-based code will be used on LPC microcontrollers, while the software-based code will be used on everything else. Here's the software routine from the app note:
/***************************************************************************//**
** @brief Function starts the execution of the software signature generation.
** @param[in] startAddrs This variable is the starting address of where the signature generation will start.
** @param[in] length The length variable is the region size to used for the signature generation.
** @param[in] *pResultSign The result after generation completion will be put in the pointed location by the pResultSign pointer.
** @return NONE
*****************************************************************************/
void StartSoftSignatureGen (UINT32 startAddr, UINT32 length, FlashSign_t *pResultSign)
{
FlashSign_t flashWord;
FlashSign_t refSignature = {0,0,0,0};
FlashSign_t nextSign;
UINT32 *PageAddr = 0,
i;
PageAddr = (UINT32 *)((UINT32)startAddr);
for ( i = 0; i <= (length>>4); i++ )
{
flashWord.word0 = *PageAddr;
PageAddr++;
flashWord.word1 = *PageAddr;
PageAddr++;
flashWord.word2 = *PageAddr;
PageAddr++;
flashWord.word3 = *PageAddr;
PageAddr++;
/* update 128 bit signature */
nextSign.word0 = flashWord.word0 ^ refSignature.word0>>1 ^ refSignature.word1<<31;
nextSign.word1 = flashWord.word1 ^ refSignature.word1>>1 ^ refSignature.word2<<31;
nextSign.word2 = flashWord.word2 ^ refSignature.word2>>1 ^ refSignature.word3<<31;
nextSign.word3 = flashWord.word3 ^ refSignature.word3>>1 ^
( refSignature.word0 & 1<<29 )<<2 ^
( refSignature.word0 & 1<<27 )<<4 ^
( refSignature.word0 & 1<<2 )<<29 ^
( refSignature.word0 & 1<<0 )<<31;
/* point to the calculated value */
refSignature.word0 = nextSign.word0;
refSignature.word1 = nextSign.word1;
refSignature.word2 = nextSign.word2;
refSignature.word3 = nextSign.word3;
}
/* Copy the reference signature to the result pointer */
pResultSign->word0 = refSignature.word0;
pResultSign->word1 = refSignature.word1;
pResultSign->word2 = refSignature.word2;
pResultSign->word3 = refSignature.word3;
}
Now all we need is a way to run the hardware-based routine (or at least part of it) in RAM. It doesn't look like RVDS has any magic attributes for placing functions in RAM, you have to use Keil to do it. That being said, all this code is doing is poking a few registers, so it shouldn't be hard to cheat the system and do it at runtime. Anybody have any ideas?
Well, after some initial confusion I was able to port the hardware and software routines from AN11208 and run them on an LPC11U24. There are a few math bugs in the AN11208 code that show up when you try to generate a signature for anything but the entire flash, so I had to make some modifications to get everything to work. Here's what I have so far:
#include "mbed.h"
typedef struct {
unsigned int word0; //Word 0 of 128-bit signature (bits 31 to 0).
unsigned int word1; //Word 1 of 128-bit signature (bits 63 to 32).
unsigned int word2; //Word 2 of 128-bit signature (bits 95 to 64).
unsigned int word3; //Word 3 of 128-bit signature (bits 127 to 96).
} FLASH_SIG_Type;
void hardSig(unsigned int startAddr, unsigned int length, FLASH_SIG_Type *pSig)
{
//Make sure the done flag is cleared
LPC_FLASHCTRL->FMSTATCLR = (1 << 2);
//Convert the byte addresses to 128-bit flash word addresses
startAddr = (startAddr >> 4) & 0x0001ffff;
length = (startAddr + ((length - 1) >> 4)) & 0x0001ffff;
//Write the start address
LPC_FLASHCTRL->FMSSTART = startAddr;
//Write stop address and start the signature generator
LPC_FLASHCTRL->FMSSTOP = length | (1 << 17);
//Wait for signature to be generated
while(!(LPC_FLASHCTRL->FMSTAT & (1 << 2)));
//Clear the done flag
LPC_FLASHCTRL->FMSTATCLR = (1 << 2);
//Store the signature words in the structure
pSig->word0 = LPC_FLASHCTRL->FMSW0;
pSig->word1 = LPC_FLASHCTRL->FMSW1;
pSig->word2 = LPC_FLASHCTRL->FMSW2;
pSig->word3 = LPC_FLASHCTRL->FMSW3;
}
void softSig(unsigned int startAddr, unsigned int length, FLASH_SIG_Type *pSig)
{
FLASH_SIG_Type flashWord;
FLASH_SIG_Type refSignature = {0, 0, 0, 0};
FLASH_SIG_Type nextSign;
unsigned int* PageAddr = (unsigned int*)((unsigned int)startAddr);
for (unsigned int i = 0; i < (length >> 4); i++) {
flashWord.word0 = *PageAddr;
PageAddr++;
flashWord.word1 = *PageAddr;
PageAddr++;
flashWord.word2 = *PageAddr;
PageAddr++;
flashWord.word3 = *PageAddr;
PageAddr++;
//Update 128 bit signature
nextSign.word0 = flashWord.word0 ^ refSignature.word0 >> 1 ^ refSignature.word1 << 31;
nextSign.word1 = flashWord.word1 ^ refSignature.word1 >> 1 ^ refSignature.word2 << 31;
nextSign.word2 = flashWord.word2 ^ refSignature.word2 >> 1 ^ refSignature.word3 << 31;
nextSign.word3 = flashWord.word3 ^ refSignature.word3 >> 1 ^
(refSignature.word0 & 1 << 29) << 2 ^
(refSignature.word0 & 1 << 27) << 4 ^
(refSignature.word0 & 1 << 2) << 29 ^
(refSignature.word0 & 1 << 0) << 31;
//Point to the calculated value
refSignature.word0 = nextSign.word0;
refSignature.word1 = nextSign.word1;
refSignature.word2 = nextSign.word2;
refSignature.word3 = nextSign.word3;
}
//Copy the reference signature to the result pointer
pSig->word0 = refSignature.word0;
pSig->word1 = refSignature.word1;
pSig->word2 = refSignature.word2;
pSig->word3 = refSignature.word3;
}
//Flash word 1024 (0x400)
const char dummyData1[16] __attribute__((at(0x4000))) = {
0xFF, 0x00, 0xFF, 0x11, 0xFF, 0x22, 0xFF, 0x33, 0xFF, 0x44, 0xFF, 0x55, 0xFF, 0x66, 0xFF, 0x77
};
//Flash word 1025 (0x401)
const char dummyData2[16] __attribute__((at(0x4010))) = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
//Flash word 1026 (0x402)
const char dummyData3[16] __attribute__((at(0x4020))) = {
0x11, 0x22, 0x44, 0x88, 0xFF, 0xFF, 0x88, 0x44, 0x22, 0x11, 0x11, 0x22, 0x44, 0x88, 0xFF, 0xFF
};
int main()
{
FLASH_SIG_Type sig1;
hardSig((unsigned int)dummyData1, 16, &sig1);
printf("\nHard Signature 1: 0x%x%x%x%x", sig1.word3, sig1.word2, sig1.word1, sig1.word0);
FLASH_SIG_Type sig2;
softSig((unsigned int)dummyData1, 16, &sig2);
printf("\nSoft Signature 1: 0x%x%x%x%x", sig2.word3, sig2.word2, sig2.word1, sig2.word0);
FLASH_SIG_Type sig3;
hardSig((unsigned int)dummyData2, 16, &sig3);
printf("\nHard Signature 2: 0x%x%x%x%x", sig3.word3, sig3.word2, sig3.word1, sig3.word0);
FLASH_SIG_Type sig4;
softSig((unsigned int)dummyData2, 16, &sig4);
printf("\nSoft Signature 2: 0x%x%x%x%x", sig4.word3, sig4.word2, sig4.word1, sig4.word0);
FLASH_SIG_Type sig5;
hardSig((unsigned int)dummyData3, 16, &sig5);
printf("\nHard Signature 3: 0x%x%x%x%x", sig5.word3, sig5.word2, sig5.word1, sig5.word0);
FLASH_SIG_Type sig6;
softSig((unsigned int)dummyData3, 16, &sig6);
printf("\nSoft Signature 3: 0x%x%x%x%x", sig6.word3, sig6.word2, sig6.word1, sig6.word0);
}
The code will generate signatures for 3 different flash words using both routines. Obviously the hardware routine is running out of flash instead of RAM, but it appears to work just fine...
Just finished an initial port of the software generator routine to C#. This is basically a straight port and hasn't been optimized for C# at all, but I tested it out on 16, 32, and 48 byte arrays and it does work:
public struct FLASH_SIG_Type {
public uint word0; //Word 0 of 128-bit signature (bits 31 to 0).
public uint word1; //Word 1 of 128-bit signature (bits 63 to 32).
public uint word2; //Word 2 of 128-bit signature (bits 95 to 64).
public uint word3; //Word 3 of 128-bit signature (bits 127 to 96).
}
private void softSig(ref byte[] data, uint length, ref FLASH_SIG_Type pSig)
{
FLASH_SIG_Type flashWord;
FLASH_SIG_Type refSignature;
refSignature.word0 = 0;
refSignature.word1 = 0;
refSignature.word2 = 0;
refSignature.word3 = 0;
FLASH_SIG_Type nextSign;
uint PageAddr = 0;
for (uint i = 0; i < (length >> 4); i++) {
flashWord.word0 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24);
flashWord.word1 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24);
flashWord.word2 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24);
flashWord.word3 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24);
//Update 128 bit signature
nextSign.word0 = flashWord.word0 ^ refSignature.word0 >> 1 ^ refSignature.word1 << 31;
nextSign.word1 = flashWord.word1 ^ refSignature.word1 >> 1 ^ refSignature.word2 << 31;
nextSign.word2 = flashWord.word2 ^ refSignature.word2 >> 1 ^ refSignature.word3 << 31;
nextSign.word3 = flashWord.word3 ^ refSignature.word3 >> 1 ^
(refSignature.word0 & 1 << 29) << 2 ^
(refSignature.word0 & 1 << 27) << 4 ^
(refSignature.word0 & 1 << 2) << 29 ^
(refSignature.word0 & 1 << 0) << 31;
//Point to the calculated value
refSignature.word0 = nextSign.word0;
refSignature.word1 = nextSign.word1;
refSignature.word2 = nextSign.word2;
refSignature.word3 = nextSign.word3;
}
//Copy the reference signature to the result pointer
pSig.word0 = refSignature.word0;
pSig.word1 = refSignature.word1;
pSig.word2 = refSignature.word2;
pSig.word3 = refSignature.word3;
}
Code is now up! This should work on any mbed-enabled microcontroller, although I was only able to test it on the LPC11U24 and KL25Z:
[Repository '/users/neilt6/code/FlashSig_HelloWorld/latest/' not found]
I've also written improved C# code for generating reference signatures:
public struct FLASH_SIG_Type {
public uint word0; //Word 0 of 128-bit signature (bits 31 to 0).
public uint word1; //Word 1 of 128-bit signature (bits 63 to 32).
public uint word2; //Word 2 of 128-bit signature (bits 95 to 64).
public uint word3; //Word 3 of 128-bit signature (bits 127 to 96).
}
private FLASH_SIG_Type generate(ref byte[] data)
{
//Initialize the local variables
FLASH_SIG_Type refSignature = new FLASH_SIG_Type();
FLASH_SIG_Type nextSignature;
FLASH_SIG_Type dataWord;
//The initial data index
uint dataIndex = 0;
//Calculate the signature for the specified region
for (uint i = 0; i < (data.Length >> 4); i++) {
//Load the next 128-bit data word
dataWord.word0 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24);
dataWord.word1 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24);
dataWord.word2 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24);
dataWord.word3 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24);
//Calculate the word's signature using the previous signature as a reference
nextSignature.word0 = dataWord.word0 ^ refSignature.word0 >> 1 ^ refSignature.word1 << 31;
nextSignature.word1 = dataWord.word1 ^ refSignature.word1 >> 1 ^ refSignature.word2 << 31;
nextSignature.word2 = dataWord.word2 ^ refSignature.word2 >> 1 ^ refSignature.word3 << 31;
nextSignature.word3 = dataWord.word3 ^ refSignature.word3 >> 1 ^
(refSignature.word0 & 1 << 29) << 2 ^
(refSignature.word0 & 1 << 27) << 4 ^
(refSignature.word0 & 1 << 2) << 29 ^
(refSignature.word0 & 1 << 0) << 31;
//The calculated signature is the new reference signature
refSignature.word0 = nextSignature.word0;
refSignature.word1 = nextSignature.word1;
refSignature.word2 = nextSignature.word2;
refSignature.word3 = nextSignature.word3;
}
//Return the reference signature
return refSignature;
}
Has anybody ever used the signature generator on the NXP microcontrollers? I noticed it at 20.16.4.7 on page 403 of the LPC11UXX user manual while I was reading up on the IAP commands. I could see this being extremely useful for control devices that store data in the flash. If the data is ever corrupted, the system could detect it and refuse to run as opposed to just going haywire. The way I see it there are a couple of things that have to happen to make this work... First of all, the calling code needs to run from RAM, so does anybody know how to define RAM-based functions using the online compiler? I'm not sure how important this is, since I was able to generate a signature WITHOUT running from RAM, but who knows maybe it could fail at some point? Secondly, there needs to be a desktop application that can generate reference signatures for a block of data. There's pseudo code in the user manual, but I couldn't get it to work in C#... Anyway, here's the code I used to generate a signature for the entire flash contents on an LPC11U24:
#include "mbed.h" DigitalOut myled(LED1); int main() { unsigned int sig[4]; //Print the generating message printf("\nStarting signature generation...\n\n"); //Make sure the done flag is cleared printf("Clearing done flag..."); LPC_FLASHCTRL->FMSTATCLR = (1 << 2); printf("done!\n"); //Set the 128-bit start and stop word addresses printf("Setting start and stop addresses..."); LPC_FLASHCTRL->FMSSTART = (0x00000000 >> 4) & 0x0001FFFF; LPC_FLASHCTRL->FMSSTOP = (0x00007FFF >> 4) & 0x0001FFFF; printf("done!\n"); //Start the signature generation printf("Starting generator..."); LPC_FLASHCTRL->FMSSTOP |= (1 << 17); printf("done!\n"); //Wait for the signature generation to complete printf("Waiting for done flag..."); while(!(LPC_FLASHCTRL->FMSTAT & (1 << 2))); printf("done!\n"); //Clear the done flag printf("Clearing done flag..."); LPC_FLASHCTRL->FMSTATCLR = (1 << 2); printf("done!\n"); //Copy the signature to RAM printf("Copying signature..."); sig[0] = LPC_FLASHCTRL->FMSW0; sig[1] = LPC_FLASHCTRL->FMSW1; sig[2] = LPC_FLASHCTRL->FMSW2; sig[3] = LPC_FLASHCTRL->FMSW3; printf("done!\n"); //Print the signature printf("\nSignature: %u-%u-%u-%u", sig[0], sig[1], sig[2], sig[3]); while(1) { myled = 1; wait(0.2); myled = 0; wait(0.2); } }