I posted a new version of my crc tool, CRCSNTOOL in the projects area...

Go To Last Post
40 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Everyone,

 

It is here:

 

https://www.avrfreaks.net/project...

 

You can use it to add a crc16 and/or serial number to an ELF or HEX file and unlike srec_cat, it works with debugging (ELF support) and doesn't bloat the flash code up to the flash size.

 

Thanks,

 

Alan

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I like that your tool allows using a CRC with both HEX and ELF which allows easy debugging but it seems that you CRC the entire flash section, not just the memory described by the HEX/ELF. 

 

I have need to:

 

1) Allow an application to self-verify at startup

2) Allow a bootloader to see if there is a valid application in the application flash section

 

crcsntool fails in this usage because it CRCs the entire flash, not just the application itself.

 

Is there a reason that you CRC more than just the area that is actually contained/initialized in the HEX/ELF itself?

 

Are you willing to release the source to crcsntool so that I can adapt it to my situation?

 

Regards,

 

Chuck Hackett

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try this as an alternative.

Attachment(s): 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi ChuckH,

 

#1 is for sure supported as I've always done this (but I can see it not working in a bootloader situation).  The tool excludes the signature string from the CRC calculation which allows the signature/CRC to be embedded in the main code.

 

#2 is something I am doing now, so I have some code that can do this.  The project above looks like it is from 2015 so it is a bit dated.  Let me look through what I have now and see what I can get for you.  I am very swamped right now, so it might be a day or so.

 

Thanks,

 

Alan

 

Last Edited: Thu. Mar 28, 2019 - 03:42 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi ChuckH,

 

Ok, I put together a zip file for you.  This should contain everything you need.  The text file in the zip also contains code from a app/bootloader project I'm using this in to give some examples of how to use it.

 

I also included the crcsntag source code (main.c) so you can see how it reads/modifies HEX/ELF files too or alter it if you need to.  I compile it with Borland C++ Builder 6, but it is pretty stock C/CPP stuff so you can likely recompile it with something else...

 

From the text file in the zip:

 

CRCSNTAG 1.10
_____________

 

I previously used SREC_CAT to add CRC protection to firmware images, but it has a couple of drawbacks.  The first is that it only works with HEX files, but ELF files are required for debugging or for using the convenient CTRL-ALT-F5 program and flash command which allows you to skip opening the programming dialog each time.  The second drawback is that it expands the firmware image size to some static value (often the full size of the flash) which makes programming and verifying take considerably longer.

 

CRCSNTAG addresses both of these issues!  It works with both HEX and ELF files.  It also embeds a crc16 or crc32 into a tag within the firmware so that the firmware expands only a 9-17 bytes.  It knows the firmware size and only tests the active bytes.  It can also optionally embed a 4 byte serial number as well which is compatible with my autoprogrammer product (it can automatically increment the serial number for each device it programs).  A library is provided with functions to test the crc, get the serial number, or search for the tag (in the case of a bootloader, it doesn't know the location of the application tag, it needs to find it).

 

Bootloader support has been thought out and you can specify a start address so that the bootloader can have its own tag to validate itself, and the application can have its own tag to validate itself.  You can choose to put a serial number in either tag, but I would recommend putting it in the bootloader tag so you can release an application update that is not serial number specific.  The tag can also be used to locate other information externally - you can add a version number after the tag in the application section that the bootloader can retrieve and provide to the user.  The self test makes for recoverable system where if the application code does not pass the CRC check, it can stay in the bootloader waiting for a good application update.  As always it makes sense to have something such as a button also trigger staying in the bootloader so that the option to replace application section code is always present.

 

The tag uses a special 4 byte preceding signature (cRcM).  This must only be in your compiled code in one location as there can only be one tag in the compiled code.  You can combine a bootloader and application into a single HEX file if you want AFTER using the crcsntag tool, but you must sign the HEX files individually beforehand.

 

More from the crcsntag.txt file:

crcsntag.c/.h contain 3 functions:
  findtag
    searches from a start address through a stop addresss to find a tag
    an application or bootloader KNOWS its own tag location and simply can reference it by name, but a bootloader that needs to find the application tag would
      use this function.

  testcrc
    tests the crc of the tag against what is in flash

  getserial
    retrieves the serial number from the tag if it has a serial number

crcsntag_settings.c/.h
  the .h has options to enable crc32 instead of crc16 or flash more than 64K or not.
  the .c has example tags, you can enable the one you need (crc16 or crc32, with or without serialno)

_____

In AVR Studio you can automatically call this tool as a post build event by going to project properties, build events, post build event command line and add:

My main application build post build event command line:
  crcsntag "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).hex" "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).elf"

My bootloader build post build event command line (note the -start=0x7000 difference!)
  crcsntag "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).hex" "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).elf" -start=0x7000

_____

Some example code:

I have a project with a bootloader and app and I chose to include the crcsntag.c/.h/crcsntag_settings.c/.h files only in the bootloader.  The application needed a tag so I just copied the correct tag into it, but it doesn't do anything with the crcsntag functions as the bootloader does anything relevant with that already.

bootloader main.c - this is code snippets, some code not shown like all variable declarations, etc.

#include "crcsntag.h"

#define FUSE_EXTENDED  0xfd
#define FUSE_HIGH      0xd0
#define FUSE_LOW       0xc2
#define FUSE_LOCK      0xcc       

int main(void)
{
  //test crc
  if (boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)!=FUSE_EXTENDED ||
      boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)!=FUSE_HIGH ||
      boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)!=FUSE_LOW ||
      boot_lock_fuse_bits_get(GET_LOCK_BITS)!=FUSE_LOCK ||
      !testcrc(BOOT_LOCATION,(uint16_t)MsgCRCM))
    {
      //halt so it will not be responsive and this error condition will be detected
      for(;;)
        ;
    }

  //test for enter bootloader condition here UPD
  if (PIND==0xbf && PINC==0xff && PINA==0xfe && PINF==0xfe)
    goto update;

  //get serial
  if (!getserial(&sn,(uint16_t)MsgCRCM))
    sn=0;

  //does the app have a tag and its crc is good
  if (findtag(0,BOOT_LOCATION,&ui1) && testcrc(0,ui1))
    {
      //store sn in GPIOR0 so it can be retrieve by app
      GPIOR0=((uint8_t*)&sn)[0];
      GPIOR1=((uint8_t*)&sn)[1];

      //execute application
      asm("jmp 0");
    }

  update:
  //more code
}

Application main.c:

tag so crcsntag will find/update it:

const uint8_t PROGMEM MsgCRCM[]={'c','R','c','M', 0,0,0,    0,0,};
volatile uint8_t *dummy_ptr;

int main()
  {
    //grab serialno from bootloader
    serialno=GPIOR0 | (GPIOR1<<8);

    //make sure gcc doesn't optimize out our darn tag!
    dummy_ptr=(uint8_t*)MsgCRCM;

    //more code
  }

ALSO - you can include the crcsntag code in the main application and it could do a findtag to locate the bootloader tag and then get the serial out of the bootloader directly instead of my passing 16 bits of it using registers in the example above.

Attachment(s): 

Last Edited: Thu. Mar 28, 2019 - 04:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Hi Alan,

 

I had just gotten crcgen to work (it was missing the code to skip the CRC in the signature) but crcntag looks like it will do everything I need - thanks much.

 

I don't serial number my firmware because it will be uploaded to my website and downloaded by customers to load into their controllers but I do store a version ID for feature/bug tracking.

 

This is for one of my hobbies - Live Steam Railroads (7.5" gauge).  You can see my locomotive (about 2,500 lbs) here:

 

http://www.whitetrout.net/Chuck/images/8444%20Joan%20&%20Chuck%20at%20KC.jpg

 

I have developed an automatic signal system for these railroads which I sell.  Not a big market but the system is installed at 4 railroads and I have not started advertising yet. 

 

Currently the controller must be loaded via the USART bootloader but I am in the process of upgrading the bootloader so that one/several/all controllers (our railroad has 19 controllers installed) can be loaded at once over the CAN data bus that they use to communicate.

 

http://www.minirailsolutions.com/

 

There are currently about 28,000 lines of code in the controller (ATMega1284) but one of the biggest challenges is lightning:

 

http://www.minirailsolutions.com/living-with-lightning/

 

Thanks again ...

 

Regards,

 

Chuck

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Super - I spent a lot of time with crcsntag trying to get it to do _everything_ I'd ever need so I didn't have to go back and rework it again later.

 

Great pictures - impressive sir!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH wrote:
... but one of the biggest challenges is lightning:
Thanks for the good read!

http://www.minirailsolutions.com/living-with-lightning/

...

The device is not an insulator, it’s a lightning arrester. 

...

This will provide an “air gap” to protect the power supply and signal system when the system is turned off (which is usually 90% of the time).

...

Y'all are well placed in Florida for lightning testing operations (consistent thunderstorms)

Oil field equipment also have lightning arrestors to protect contactors, motors, and etc.

MOV can protect electronics though these tend to, with exposure, short, partially short, or become very leaky.

A TBU can be after a MOV for additional protection.

Lightning sensors can be in operator's equipment such that operators evacuate customers to shelter in a walled structure then an operator throws the system's switch.

 


Delta Lightning Arrestors - How Arrestors Work

MOV - Metal Oxide Varistor

SOV - Silicon Oxide Varistor

Delta SOV for 120V AC or DC

Delta's MOV : Delta Data Line Circuit Protectors

both via Delta Lightning Arrestors - Specifications

Bourns - TBU High-Speed Protectors (HSPs)

Incoming Storm A Lightning Detector from ams | DigiKey

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gchapman wrote:

Y'all are well placed in Florida for lightning testing operations (consistent thunderstorms)

 

Lightning capital of the world!  :-) 

 

gchapman wrote:

MOV can protect electronics though these tend to, with exposure, short, partially short, or become very leaky.

A TBU can be after a MOV for additional protection.

 

Yes, the reason I did not go with MOVs is that they degrade.  I use a TVS diode on the track input and a fuse to protect the TVS diode (TVS diodes usually fail 'shorted' which is better in this case).  The signal then goes to an RC conditioning filter and directly to an ADC input on the ATMega1284.  I can draw a 3/16" arc from a 6,000vac supply to the track input terminal without harm.  

 

The power (30vdc) and CAN bus were more difficult.  I started with fuse/TVS but that was not sufficient.  I have now gone to 75v Gas Discharge Tube (GDT) and inductor on the power and GDTs and Bourns TBUs on the CAN bus.  Looks good so far but we have not been through a full lightning season with them yet.

 

BTW: Why do you have different code in crcntag and testcrc()?  I have not studied them in detail yet but so far I am getting mismatched CRCs.  First couple bytes compared ok by after about 12k (of 78k) i have a mismatch.  I'm going to cut back from 12k gradually and see if I can see where they diverge.

 

Chuck

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OOps, that crcntag stuff was for Alan :-)

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH wrote:
BTW: Why do you have different code in crcntag and testcrc()?

 

Do you mean the crssntag.exe (from main.c) vs testcrc() from crcsntag.c ?  What is different?

 

ChuckH wrote:
I have not studied them in detail yet but so far I am getting mismatched CRCs.  First couple bytes compared ok by after about 12k (of 78k) i have a mismatch.  I'm going to cut back from 12k gradually and see if I can see where they diverge.

 

I don't understand how you know some of it is ok and some not.  The crcsntag tool figures out the size of a hex/elf and calculates a crc for that entire blob of memory.  When you compile if you are using the post build command you can see the crcsntag executeable run and it will say what the length was, the crc calculated, etc.  For example:

 

crcsntool test.hex [hex, found 0x151, size 25206, crc 0x01A0]
crcsntool test.elf [elf, found 0x151, size 25206, crc 0x01A0]

 

Thanks,

 

Alan

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you using the >64K option?  I'm can't remember if I tested that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH wrote:
You can see my locomotive (about 2,500 lbs) here:
Wow - that's a pretty serious bit of kit!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH wrote:
I started with fuse/TVS but that was not sufficient.
TVS destruction?

PolyZen have an automotive power use case though lightning is an order of magnitude worse than automotive and PolyZen's time duration to clamp is a few orders of magnitude slower than a TVS (some regulator pass transistors can withstand the avalanche though some won't)

 

PolyZen Devices for Overvoltage-Overcurrent Protection - Littelfuse

PolyZen Device Fundamentals

(page 2, right column, bottom half)

Transient Protection Design Considerations

Transient protection is especially critical when designing peripherals that may be powered off computer buses and automotive power buses. Automotive power buses are notoriously dirty. Although they are nominally 12V, they can range in normal operation from 8V to 16V. Still, battery currents can exceed 100 Amps and be stopped instantly via a relay or fuse, generating large inductive spikes on the bus and increasing voltage by 5 times or more. In operation, automotive supplies are subject to damage from misconnected batteries [1] and double battery jumpstarts (24V) [2]. A condition known as “load dump” can also generate large voltages on the bus [3].

[1] Correct battery replacement sequence is +, -, -, +

[2] IIRC, there's a procedure to jump start a 12V automobile from a 24V automobile (semi-tractor, heavy wrecker, medium truck)

[3] Up to approximately 300V plus or minus

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

ChuckH wrote:

You can see my locomotive (about 2,500 lbs) here:

 

Wow - that's a pretty serious bit of kit!!

 

Especially when it comes off the track ... and the boiler is HOT (350 degrees with steam at 125 psi) ... smiley

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

Are you using the >64K option?  I'm can't remember if I tested that.

 

Yes, I am using the >64k option.  Actual code size: 78654

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH wrote:
This is for one of my hobbies - Live Steam Railroads (7.5" gauge).  You can see my locomotive (about 2,500 lbs) here:

Nice looking 4-8-4!  My cousin was in to that too, last time I saw his it had not yet been painted.  Sadly he has passed, so I don't know what became of it....

 

Jim

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
stack gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

ChuckH wrote:
BTW: Why do you have different code in crcntag and testcrc()?

 

Do you mean the crssntag.exe (from main.c) vs testcrc() from crcsntag.c ?  What is different?

 

Yes, I am using Atmel Studio post-build step of:

 

crcsntag "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).hex" "$(MSBuildProjectDirectory)\$(Configuration)\$(OutputFileName).elf"

 

code from cr[c]sntag.exe (from main.c) (in "UpdateSignature"):


uint16_t _crc16_update(uint16_t ACRC, uint8_t AValue)
  {
    uint8_t c1,c2;

    //xor value
    ACRC^=AValue;

    //for each bit
    for (c1=0; c1<8; c1++)
      {
/*        if (ACRC&1)
          ACRC=(uint16_t)((ACRC>>1)^0xA001);
        else ACRC=(uint16_t)(ACRC>>1);*/

        //remember lsb
        c2=(uint8_t)(ACRC & 1);

        //shift 1 bit
        ACRC>>=1;

        //if lsb apply polynomial
        if (c2)
          ACRC^=0xA001;
      }
      
    return ACRC;
  }

... and in UpdataSignature ...

      {
        //calculate crc16
        crc16=0xffff;
        for (ul1=startaddr; ul1<imagesize; ul1++)
          if (ul1<sigpos || ul1>=sigpos+SIG_SIZE)
            crc16=_crc16_update(crc16,image[ul1]);
        crc16=(uint16_t)~crc16;

        printf(", crc 0x%04X",crc16);
        memcpy(sigstr+7,&crc16,2);
      }

.vs. in testcrc:

    //calculate crc
    for (addr=AStartAddr;;)
      {
        if (addr<ATagAddr || addr>=ATagAddr+c3)
          {
            #ifdef CRCSNTAG_ENABLE_CRC32
....
            #endif
              {
                crc16^=PGM_READ_BYTE(addr);
                for (c1=0;c1<8;c1++)
                  {
                    c2=(uint8_t)(crc16 & 1);
                    crc16>>=1;
                    if (c2)
                      crc16^=0xA001;
                  }
              }
          }

        addr++;
        if (addr==stopaddr)
          break;
      }

... as I said, I am still investigating but I noticed that they were different code sections ... BUT ... they may be identical in function, I still have to step the code and check stuff to be sure I'm using it correctly.  I just though it was strange that the function wasn't used by "testcrc".  I am probably doing something wrong and not ready to question it yet until I verify that they are, in fact, operating on the exact same code image.

 

alank2 wrote:

ChuckH wrote:
I have not studied them in detail yet but so far I am getting mismatched CRCs.  First couple bytes compared ok by after about 12k (of 78k) i have a mismatch.  I'm going to cut back from 12k gradually and see if I can see where they diverge.

 

I don't understand how you know some of it is ok and some not.  The crcsntag tool figures out the size of a hex/elf and calculates a crc for that entire blob of memory.  When you compile if you are using the post build command you can see the crcsntag executeable run and it will say what the length was, the crc calculated, etc.  For example:

 

crcsntool test.hex [hex, found 0x151, size 25206, crc 0x01A0]
crcsntool test.elf [elf, found 0x151, size 25206, crc 0x01A0]

 

Thanks,

 

Alan

 

 

Sorry for the confusion, I'll try to clarify:  When I found that I was coming up with a different crc I verified (by breakpoints) that they were both operating on the same range (0 : 78654).  I then set a breakpoint in crcsntag.exe and testcrc as they did the first couple of bytes (both starting at 0) and it was OK.  Then I tried to set a conditional breakpoint after they had both done 0x3000 worth of code to verify the crc but Atmel Studio wasn't cooperating (always broke instead of when "addr > 0x3000".  I will investigate more today.

 

Hope that clarifies it.  I'll let you know what I find ...

 

Regards,

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck, did you enable this line in the crcsntag_settings.h (by removing the //)?

 

//#define CRCSNTAG_ENABLE_FAR            //enable if you are using >64K flash

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

Chuck, did you enable this line in the crcsntag_settings.h (by removing the //)?

 

//#define CRCSNTAG_ENABLE_FAR            //enable if you are using >64K flash

 

Yes ...

 

I am in the middle of a 'binary search' (setting breakpoints in crcsntag and testcrc at different addresses values).  I have narrowed the issue down to somewhere between 2039 & 4080 ... getting close!

 

FYI: tag is at 1397 and size is 78752 

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very odd.  I've got to look and see if I have an easy to program part over 64K to test it with, so I might be able to look at it a bit this weekend.  Maybe you will figure it out first!!

 

Another test - remark out some of your code so it drops below 65536 bytes.  Does it work/fail then?

 

If it fails then, disable the tag above, Does it work then?

 

The code difference is probably me trying to optimize the C to produce better ASM on the AVR side.

Last Edited: Fri. Mar 29, 2019 - 06:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found a MEGA1284P project I had laying around an expanded it to 93K flash.  Added crcsntag to it and it works.  I tried tags with and without serial number successfully.  If I disable the >64K define it fails as expected.  Are you testing it in the bootlaoder or in the app?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

Very odd.  I've got to look and see if I have an easy to program part over 64K to test it with, so I might be able to look at it a bit this weekend.  Maybe you will figure it out first!!

 

Another test - remark out some of your code so it drops below 65536 bytes.  Does it work/fail then?

 

If it fails then, disable the tag above, Does it work then?

 

The code difference is probably me trying to optimize the C to produce better ASM on the AVR side.

 

I have finished my 'binary search' test with the following:

  • It matches until it attempts to CRC location 2138 (0x085A)
  • At this point the accumulation (current CRC) is 10049 (0x2741)
  • The byte it is trying to add to the CRC is 0x63 ***
  • The result on the PC is 6567 (0x19A7)
  • The result on the ATMega1284p is 39654 (0x9AE6)

 

*** News flash: for some reason that I can not explain, when the loop in the AVR goes to do a "PGM_READ_BYTE(addr)" and "addr" is 2138 (0x085A) the value returned is NOT the value shown as being in that location by the debug/memory window (BTW: using JTAG) nor the value shown in the HEX file for that location. 

 

The following (unoptimized) code:

 

				crc16 = _crc16_update(crc16, PGM_READ_BYTE(addr));

compiles to:

 

                crc16 = _crc16_update(crc16, PGM_READ_BYTE(addr));
    6c88:    8a 81           ldd    r24, Y+2    ; 0x02
    6c8a:    9b 81           ldd    r25, Y+3    ; 0x03
    6c8c:    ac 81           ldd    r26, Y+4    ; 0x04
    6c8e:    bd 81           ldd    r27, Y+5    ; 0x05
    6c90:    8a 8f           std    Y+26, r24    ; 0x1a
    6c92:    9b 8f           std    Y+27, r25    ; 0x1b
    6c94:    ac 8f           std    Y+28, r26    ; 0x1c
    6c96:    bd 8f           std    Y+29, r27    ; 0x1d
    6c98:    8a 8d           ldd    r24, Y+26    ; 0x1a
    6c9a:    9b 8d           ldd    r25, Y+27    ; 0x1b
    6c9c:    ac 8d           ldd    r26, Y+28    ; 0x1c
    6c9e:    bd 8d           ldd    r27, Y+29    ; 0x1d
    6ca0:    ab bf           out    0x3b, r26    ; 59
    6ca2:    fc 01           movw    r30, r24
    6ca4:    87 91           elpm    r24, Z+
    6ca6:    8e 8f           std    Y+30, r24    ; 0x1e
    6ca8:    2e 8d           ldd    r18, Y+30    ; 0x1e
    6caa:    8e 81           ldd    r24, Y+6    ; 0x06
    6cac:    9f 81           ldd    r25, Y+7    ; 0x07
    6cae:    62 2f           mov    r22, r18
    6cb0:    07 df           rcall    .-498        ; 0x6ac0 <_crc16_update>
 

Now, I'm no expert at AVR assembler but, setting a breakpoint at 6CA4 (program read) shows the Z register contains 0x085A.  Stepping to the next instruction shows a value of 0x98 loaded into R24 ... not 0x65 !

 

This (wrong value) continues for the next location (then I was tired and confused).

 

Just now, researching the ELPM instruction I discovered this (see ATMega1284p datasheet, section 7.5.2):

 

RAMPZ – Extended Z-pointer Register for ELPM/SPM(1)
For ELPM/SPM instructions, the Z-pointer is a concatenation of RAMPZ, ZH, and ZL, as shown
in Figure 7-4 on page 15. Note that LPM is not affected by the RAMPZ setting.
Figure 7-4. The Z-pointer used by ELPM and SPM
The actual number of bits is implementation dependent. Unused bits in an implementation will
always read as zero. For compatibility with future devices, be sure to write these bits to zero.

Followed ominously by:

Note: 1. RAMPZ is only valid for ATmega1284/ATmega1284P

Since I'm using the ATMega1284p this warrants more study ... I'll get back to you, probably Sunday as I have a commitment all day tomorrow.

 

The good news is that it does not appear to be your code ...

 

GCC not being told the correct stuff about the ATMega1284p? ... Stay tuned ...

 

Regards,

 

Chuck

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

App ... but the BOOTRST fuse is programmed.

 

CPU registers show execution in normal app space.

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Chuck,

 

I've dug into it a bit too and one of the confusing things I think is that in gcc, it treats PROGMEM variables as 16-bit pointers (such as the MsgCRCM tag).  I don't think this is a huge issue because I've seen some messages about how gcc packs the PROGMEM's into the first 64K anyway, but there is a function pgm_get_far_address() that I *think* I've used in a bootloader before to get a correct pointer (I could be wrong about this).  That only has to do with using the MsgCRCM reference, if searching for it, it should be fine.  Even then, it might only be an issue in a bootloader loaded above 64K referencing its MsgCRCM tag.

 

I'm not following post #24...

 

Thanks!

Alan

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I couldn't go to bed until I checked the value of the RAMPZ when doing the good and bad memory reads ...

 

The RAMPZ was always 0 as it should be in the lower 64k (As shown in the Atmel Studio "I/O" pane).

 

... so I am at a loss at the moment ... I have no idea why the ELPM instruction is getting the wrong byte ...

 

A long time ago I had the honor (?) of finding a microcode bug in a fairly new computer on the market (Tandem) ... this kind of smells like that ... but, I've been in this business too long to go blaming something on compiler or hardware without rock-solid evidence ... so I'm not going there now ...

 

I'm going to drag myself to bed where I will probably lie awake thinking about it ...

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

 

I'm not following post #24...

 

 

That was in answer to your question about "in app or bootloader".

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been there Chuck!!!  Those unexplained things can be vexing!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So you have BOOTRST set, but you are testing the crc in the app section?  Do you have the bootloader as a separate project?  I've had BOOTRST set before and when I flash the app alone, it may start at the BOOTRST address, but if it is empty, it rolls around and eventually gets to run the app section...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Alan,

 

Unless I'm missing something, the:

PGM_READ_BYTE(addr)

(due to CRCSNTAG_ENABLE_FAR being defined) resolves to (in pgmspace.h):


/** \ingroup avr_pgmspace
    \def pgm_read_byte_far(address_long)
    Read a byte from the program space with a 32-bit (far) address. 

    \note The address is a byte address. 
    The address is in the program space. */

#define pgm_read_byte_far(address_long)  __ELPM((uint32_t)(address_long))

which handles 32-bit addresses and this would seem to be born out by the code quoted in #23 where there is the "OUT" to RAMPZ and the ELPM so it should work.

 

Stepping through RAMPZ and the Z register look fine -- unless Atmel Studio is wrong ...

 

Regards,

 

Chuck

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Correct.  Could there be something corrupting the flash?  If you read the byte that comes back the wrong value in your main function before calling the testcrc function using the pgm_read_byte_far, what does it return?  Is it what it should return?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

So you have BOOTRST set, but you are testing the crc in the app section?

Yes ...

 

alank2 wrote:

Do you have the bootloader as a separate project?  I've had BOOTRST set before and when I flash the app alone, it may start at the BOOTRST address, but if it is empty, it rolls around and eventually gets to run the app section...

 

Yes, separate project.  My controller normally runs with a bootloader in memory but, when testing with Studio it's easier to just have the app loaded and I have not had an issue in the past when it just rolls off the end to 0.

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ChuckH wrote:

with Studio it's easier to just have the app loaded and I have not had an issue in the past when it just rolls off the end to 0.

 

I do the same thing and agree.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:

Correct.  Could there be something corrupting the flash?  If you read the byte that comes back the wrong value in your main function before calling the testcrc function using the pgm_read_byte_far, what does it return?  Is it what it should return?

 

If I understand what you are asking:

 

I placed this before the call:

					volatile uint16_t TheByte;
                                        .... loop ...
                                            TheByte = pgm_read_byte_far( addr );

For location 0x0859 it returned 0x01 (correct)

For 0x085A it returned 0x98 (wrong)

For 0x085B it returned 0x95 (wrong)

For 0x085C it returned 0x98 (wrong)

....

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suspect there is something residual in a register that ELPM is using that I don't know is there ... 

 

I can't imaging there is anything special about location 0x085A ...

 

Ok, it had to be done ... I have been testing with this controller for awhile, so I switched to a different board ...

 

... No change ...  sad

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, it gets stranger ...

 

I placed this and a call to it just about first thing in my app:


void DumbTest( void )
{
    volatile uint8_t TheByte;
    for ( uint32_t Address = 2136; Address < 3000; Address++ )
	TheByte = pgm_read_byte_far( Address );
}

... and it worked (code bytes were shifted slightly due to code change in lower code space).

 

When I added it just ahead of "testcrc" and a call to it first thing in testcrc ... it failed !

 

testcrc is higher in memory (0x35BE) but don't see how that makes a difference.

 

Ok, it's 12:02 AM here ...

 

Chuck

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the  out    0x3b, r26 is setting the rampz register.  I see that in your code example above - do you see it in yours tests in post 35/36 ?

 

What does removing the loop do:  What should the 3 bytes be?

volatile uint16_t TheByte;
TheByte = pgm_read_byte_far( 0x085A );
TheByte = pgm_read_byte_far( 0x085B );
TheByte = pgm_read_byte_far( 0x085C );

 

Last Edited: Sat. Mar 30, 2019 - 04:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:
What does removing the loop do

 

See: https://www.avrfreaks.net/commen...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

alank2 wrote:
Ok, I put together a zip file for you.

 

Ok, things seem to be going better now.

 

I have been doing some testing ...

 

Be aware that, if crcsntag is not run on the hex/elf file (user forgot, gave it the wrong file, etc.) the tag will be cRcM followed by 0x00's.  This causes your code to have a 'startaddr' of 0 AND a 'stopaddr' of 0.  On a 32-bit processor this causes it to loop for a LOOOOONG time even at 20 MHz.  I assume it would eventually fail but I didn't wait that long :-) 

 

Is there a reason you don't use the value of the linker symbol "__data_load_end"?

 

You can get it in C with:

//
//	Get the 32-bit address of the linker symbol "__data_load_end"
//
//	Note: Not doable in WinAVR because GCC treats pointers as 16 bits
//
uint32_t get_data_load_end(void)
{
	uint32_t tmp;

	asm volatile("ldi %A0, lo8(__data_load_end)" "\n"
	"ldi %B0, hi8(__data_load_end)" "\n"
	"ldi %C0, hlo8(__data_load_end)" "\n"
	"ldi %D0, hhi8(__data_load_end)"
	: "=r"(tmp));
	return tmp;
}

This way it would always be valid (assuming you want to CRC all of flash).

 

Chuck

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Chuck,

 

The code that signs it with the crc16 already knows the length so it embeds the length along with the crc16 at the same time.  You could though modify the tag to have something like the above automatically done however.  You can't forget to do the crcsntag command if it is a post build instruction (unless you disable it!).  Let me know if you come up with an improvement!!

 

Thanks,

 

Alan