This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

UCD3138128: Checksums don't match

Part Number: UCD3138128
Other Parts Discussed in Thread: UCD3138

Tool/software:

Hello again...

I am having problems calculating and verifying the checksums in flash memory.

Here are the steps.

STEP 1

I downloaded my application and added the checksum as follows: 

The check sum is: 0x3097B3F36D16

The bootloader then successfully boots the program so I know the checksum added to the end of block1 is correct (at least the bootloader thinks it is).

STEP 2

I verified this is correct using the fusion gui here:

STEP 3

I ran my firmware checksum calculation over the same address space and I get a different result. Here is my code snippet. I used was from the UCD3138 programmers manual.

The value I calculate in my firmware with the function included below, is:   0x18F9B3F36D16 while the value fusion GUI calculates is  0x3097B3F36D16.

Can you please verify that this is the same function that the bootloader uses or perhaps supply me with the code snippet?

Any help is GREATLY appreciated as usual!

.

// FROM SPEC...
Uint64 a0_long_checksum =0;
Uint64 a0_long_checksum01 =0;
Uint64 a0_long_checksum23 =0;

void calculate_checksum(register Uint32 *start_address, register Uint32 *end_address)
{
    Uint64 lcs = a0_long_checksum; //use local register variable for speed?? TAW not sur that works

    while(start_address < end_address)
    {
        lcs = lcs + *start_address ;
        lcs = lcs + (Uint32)*(start_address + 1) ;
        start_address = start_address + 2;
    }
    a0_long_checksum = lcs;
}


void Pflash_GetChecksum01(void)
{
    a0_long_checksum = 0;
    Uint32* start_address = (Uint32*) PGM_BLOCK0_ADDRESS; // 0x00000000
    Uint32* end_address = (Uint32*) (PGM_BLOCK2_ADDRESS -8);// 0x00010000 - 8
    calculate_checksum(start_address,end_address ); // result is in a0_long_checksum
    a0_long_checksum01 =a0_long_checksum;
}

  • Although I think the following is not the problem...

    Perhaps my Memory Base Address Registers are not correct?  HEre are the MFBAHR1 and 17 registers. 
    Can someone check these? I just used the defaults.

  • Another thing I noticed is that the checksum that the GUI calculates is larger. There is another chunk of memory being included int the GUI calculation that is not included in my calcuation. Can the bootloader memory be being used in that GUI calculation? I just completely lost as to why my calculation is not correct.

  • Hello BatMan,

    Thank you for your question. I am looking into your inquiry and I will provide a response next week.

    Regards,

    Jonathan Wong

  • I am having to make firmware work arounds concerning this issue as well as the one that switches applications under firmware control ...so any expeditious help would be greatly appreciated!

  • Hello BatMan,

    You can try looking at the .map file directly using a text editor (like VS Code) and see if the register address matches the register value shown in the memory debugger. I have found that sometimes the memory debugger is different than the .map file. Also, confirm that the file location you have selected in the memory debugger is the correct location. I assume you are using the Bidirectional DC/DC firmware as a starting point. That firmware file structure is different than typical UCD3138 file structures.

    I believe that firmware also does not have .pp files enabled. You can find the settings for the Parser Preprocessor (.pp) directives in Project Properties → Build → Arm Compiler  Advanced Options → Parser Preprocessing Options. Select manual mode and check the bottom two options. Make sure the .pp files are generated in the same folder as your .map file and point to that folder in the memory debugger. 

    Regards,

    Jonathan Wong

  • I can use the memory debugger to calculate and program the checksum correctly. This is verified because when I reboot the device, the bootloader verifies that the checksum is correct and boots the application correctly. However, when I run my application function to verify the check sum, I calculate a different result. I did check the memory map and pp files to be sure and do not see any differences between the debugger and the memory map. The (.pp) files are updating when I compile, as well.

  • Hello BatMan,

    I will check if there is a better way to calculate the checksum. I will get back to you at the end of the week.

    Regards,

    Jonathan Wong

  • Hi Jonathan,

    It appears that there is a compiler bug when dealing with "unsigned long long" values.

    I have to admit that I was a little leery when I saw the method used to calculate checksums using 64 bit integers because the processor is only 32 bit so the handling of the carry/overflow bit of the 32bit sum values, must be handled in assy code. Theoretically this was done to "speed up" the checksum calculation.

    This does NOT work:

    void calculate_checksum(register Uint32 *start_address, register Uint32 *end_address)
    {

       Uint64 lcs = 0;
       while(start_address < end_address)
       {
           lcs = lcs + *start_address ;
           lcs = lcs + *(start_address + 1) ;
           start_address = start_address + 2;
        }

    }

    This does work!! bizarre huh?

    void calculate_checksum(register Uint32 *start_address, register Uint32 *end_address)
    {

       Uint64 lcs = 0; 

       while(start_address < end_address)
       {
           lcs = lcs + (Uint64)*start_address ; // MUST BE CAST HERE or addition doesnt work properly!
           start_address = start_address + 1;
        }
    }

  • Hello BatMan,

    Thank you for the input. I will provide a detailed response later this week.

    Best,

    Jonathan Wong

  • Hello BatMan,

    Thank you for your insights into the calculate_checksum() feature. Here are some thoughts that I hope are helpful for you and anyone else on this forum.

    The original calculate_checksum() function you found is on page 18 in the UCD3138A64/UCD3138128 Programmer's Manual

    void calculate_checksum(register Uint32 *start_address, register Uint32 *end_address)
    {
        register unsigned long long lcs = long_checksum; //use local register variable for speed.
        while(start_address < end_address)
        {
            lcs = lcs + *start_address ;
            lcs = lcs + (Uint32)*(start_address + 1) ;
            start_address = start_address + 2;
        }
        long_checksum = lcs;
    }

    You are right that the UCD3138x Arm core is a 32-bit processor. So, start_address is indexed as a 32-bit number. Thus, the best method would be to index using a 32-bit number so that every time you increment start_address, you read the next 4 bytes of data. The Programmer's Manual recommends to speed up this process by reading 8 bytes of data for each loop.

    Thus, I there are 3x methods to calculate the checksum. I have a table below to highlight the process:

    1. Fast method from Programmer's Manual by reading 2x 32-bits at a time
    2. Your method of reading 1x 64-bits 
    3. Slow method reading only 1x 32-bits at a time. 

    The solution from the Programmer's Manual provided should work, so I am not sure why the code did not work for you. I suspect 2 possible causes:

    • The Fusion GUI checksum calculates the checksum across the entire program flash bank (128kB if you select all 4 blocks). Your function may have a different end_address than the Fusion GUI and thus stops the calculation at a different location.
    • It may be a little endian vs. big endian issue. Instead of accurately reading 0x0011223344556677, your function may be reading something like 0x3322110077665544. 

    calculate_checksum() from Programmer's Manual

    calculate_checksum() function  ↓start (lcs) ↓start+1 (lcs) ↓start+2
    Address 0x800 0x801 0x802 0x803 0x804 0x805 0x806 0x807 0x808 0x809 0x80a 0x80b 0x80c 0x80d 0x80e 0x80f
    Program Data (1byte) 0x00 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa 0xbb 0xcc 0xdd 0xee 0xff

    calculate_checksum() using (uint64) 

    calculate_checksum() function  ↓start ↓start+1
    Address 0x800 0x801 0x802 0x803 0x804 0x805 0x806 0x807 0x808 0x809 0x80a 0x80b 0x80c 0x80d 0x80e 0x80f
    Program Data (1byte) 0x00 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa 0xbb 0xcc 0xdd 0xee 0xff

    calculate_checksum() using (uint32) ONLY

    calculate_checksum() function  ↓start ↓start+1
    Address 0x800 0x801 0x802 0x803 0x804 0x805 0x806 0x807 0x808 0x809 0x80a 0x80b 0x80c 0x80d 0x80e 0x80f
    Data (1byte) 0x00 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa 0xbb 0xcc 0xdd 0xee 0xff

    I would recommend using the last method, where you just count by 1x 32-bits at a time. While it is theoretically slower, I do not believe you would save much time when counting 2x 32-bits at a time at the expense of potential errors. The code to count 1x 32-bits at a time is below:

    void calculate_checksum(register Uint32 *start_address, register Uint32 *end_address)
    {
        register unsigned long long lcs = long_checksum; //use local register variable for speed.
        while(start_address < end_address)
        {
            lcs = lcs + *start_address ;
            start_address = start_address++;
        }
        long_checksum = lcs;
    }

    Regards,

    Jonathan Wong