Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

What am I missing.

Status
Not open for further replies.

Pommie

Well-Known Member
Most Helpful Member
I need to checksum a simple buffer. I decided to have a 32 bit checksum which was simply all the other 32 bit values XORed together.
I set the checksum to zero.
I xor the whole buffer together.
I place the complement of the checksum in the checksum location.
I recalculate the checksum.
I get all ones instead of zero.

In my head, any number XORed with it's complement should give zero.

It's obviously something stupid that I'm missing.
I converted it to Arduino to convince myself it wasn't hardware.
Here it is, apologies for the pointer stuff - it just made handling a byte buffer as 32 bits so much easier.
Code:
uint8_t buff[56];               //buffer to hold data 32*14 = 56*8 = 448 bits

void setup() {
  Serial.begin(115200);
  for(uint8_t i=0;i<56;i++){  //fill with nonsense
    buff[i]=i;
  }
  uint32_t checkSum;
  uint32_t *p;                        //pointer to 32 bit number
  p=(uint32_t*)buff+sizeof(buff)/4-1; //point to the checksum
  *p=0;                               //zero the checksum
  checkSum=calcChecksum();            //calculate with checksum=0
  Serial.print("Checksum = ");
  Serial.println(checkSum,HEX);
  checkSum^=0xffffffff;               //complement
  *p=checkSum;                        //write to checksum location
  checkSum=calcChecksum();
  Serial.print("Checksum = ");
  Serial.println(checkSum,HEX);
  while(1){
  } 
}

void loop() {
}

/* CalcChecksum returns the checksum of the buffer or zero if the complement of
 * the checksum is in the end 32 bits.
 */
uint32_t calcChecksum(void){
  uint32_t *p;                    //pointer to 32 bit number
  p=(uint32_t*)buff;              //point to start of buffer
  uint32_t tempChecksum=0;        //zero checksum
  for(uint8_t i=0;i<sizeof(buff)/4;i++){
    tempChecksum^=*p++;           //xor all words together
  }
  return(tempChecksum);
}

Thanks for any help.

Mike.
 
Except, the exact same code on MPLABX and XC8 doesn't work!!! It works on Arduino but not MPLABX. Actually the reason I converted to Arduino is because I don't trust MPLABX any more.
Code:
#include <xc.h>
#include <stdint.h>
#include "config.c"

uint8_t buff[56];               //buffer to hold saved data 32*14 = 56*8 = 448 bits
uint32_t calcChecksum(void);

void main(void){
    for(uint8_t i=0;i<56;i++){  //fill with nonsense
        buff[i]=i;
    }
    uint32_t checkSum;
    uint32_t *p;                        //32 bit pointer
    p=(uint32_t*)buff+sizeof(buff)/4-1; //point to the checksum
    *p=0;                               //zero the checksum
    checkSum=calcChecksum();            //calculate with checksum=0
    *p=checkSum;                        //write to checksum location
    checkSum=calcChecksum();
    while(1){
    }    
}
/* CalcChecksum returns the checksum of the buffer or zero if the complement of
 * the checksum is in the end 32 bits.
 */
uint32_t calcChecksum(void){
    uint32_t *p;                    //32 bit pointer
    p=(uint32_t*)buff;              //point to start of buffer
    uint32_t tempChecksum=0;        //zero checksum
    for(uint8_t i=0;i<14;i++){      //52+4 bytes need to be checksummed = 14 words
        tempChecksum^=*p++;         //xor all words together
    }
    return(tempChecksum);
}

Mike.
 
The results with MPLABX.
mplab.png


I'm exhausted, been fighting with this thing all day.

Mike.
 
The checksum isn't being written to the buffer. Late here now but will work out why tomorrow.

Mike.
 
Get the CCS compiler, that's what I use (with MPLAB X). When I first needed a PIC C compiler, the free Microchip one had severe limitations, if I remember right, so I went with the CCS PICC compilers. They have vastly better facilities than XC and a lot less bugs, though i have found an occasional one..

I just copied your program in, selected a random PIC18 & set it for simulation - no errors and a correct result.

Debug1.jpg


Debug2.jpg
 
The checksum isn't being written to the buffer. Late here now but will work out why tomorrow.

Mike.

I hate the way this works, but...
Code:
    checkSum=calcChecksum();
    while(1){
    }
Since 'checkSum' is not used after that point, the compiler is free to optimize it away, so it never assigns the result of the function call.

To tell the compiler "I know you're super smart, but please do what I say", change your declaration of checkSum to:
Code:
    volatile uint32_t checkSum;
It will now generate code for the second assignment to 'checkSum'.
 
  • Like
Reactions: Buk
Making it volatile works, thanks.
Before giving up last night, I single stepped through the second call to calcChecksum and, in the final iteration of the for loop, it got the right answer
mplab.png


However, on returning it didn't bother to store the answer so the previous value was shown,
mplab.png

At least I now know what was happening.
Is there a way to turn off all optimizations during debugging?

Mike.
 
Is there a way to turn off all optimizations during debugging?
Things like this don't seem to be considered "optimizations"... it still occurs specifying 'optimization level 0'
There may be some esoteric GCC '-wthere'sacommandlineswitchforeverything' setting but I don't know what it is.

It's doing what the C standard allows (unfortunately).
Personally, I wish they'd stop being so smart and if you type a line of code, then generate code for it!
 
The CCS compiler produces the result OK, even at maximum optimisation (level 9, in that).
 
XC8 is doing what's allowed.

With checkSum and p declared as plain uint32_t:
Code:
    checkSum=calcChecksum();            //calculate with checksum=0
    *p=checkSum;                        //write to checksum location
    checkSum=calcChecksum();
    while(1){
    }
It generates code for the first assignment to checkSum, but since the compiler sees that checkSum is not used after the second assignment it does the second calcChecksum() call but doesn't bother with assigning the result.

I don't care for it, but it's perfectly legal. Declaring it as 'volatile uint32_t' fixes that.
 
To verify what tumbleweed said (not that I doubted him), I removed the volatile and added an increment after the call and that also fixed it.
Code:
    uint32_t *p;
    p=(uint32_t*)buff+sizeof(buff)/4-1;
    *p=0;
    checkSum=calcChecksum();
    *p=checkSum;
    checkSum=calcChecksum();
    checkSum++;

Mike.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top