problems with calling bootloader functions

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

I'm using the XMega128a1 bootloader hack (AVR109) that damien_d posted a while back. I want to call the sp_driver.S functions from application code. I'm running on Linux so I don't have easy access to a debugger.

I took a look at the bootloader FAQ and nothing jumped out to me there as far as doing something wrong. I know that it is recommended not to hardcode a jump table, but that is what I am trying right now because I can't modify the bootloader under Linux. I will clean it up once I can use the MKII programmer with avrdude under Linux.

I'm trying to read and write to the User Signature Row. The application code looks like this:

//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
static void LoadAppTableWord(uint16_t tableAddress, uint8_t lowByte, uint8_t highByte)
{
        /* Perform word load. */
        SP_LoadFlashWord(tableAddress, ((uint16_t) highByte << 8) | lowByte);

        /* Wait for NVM to finish. */
        SP_WaitForSPM();
}


/////////////////////////////////////////////////////////////////////////////////////
//  assumes address is 6 bytes
/////////////////////////////////////////////////////////////////////////////////////
void write_mac_address(uint8_t *address) {

        /* Erase the user signature row. */
        SP_EraseUserSignatureRow();

        /* Wait for NVM to finish. */
        SP_WaitForSPM();

        //load in mac address
        LoadAppTableWord(0, address[0], address[1]);
        LoadAppTableWord(2, address[2], address[3]);
        LoadAppTableWord(4, address[4], address[5]);

        /* Write the Flash buffer to the user signature row. */
        SP_WriteUserSignatureRow();

        /* Wait for NVM to finish. */
        SP_WaitForSPM();

}
/////////////////////////////////////////////////////////////////////////////////////
//  assumes address is 6 bytes
/////////////////////////////////////////////////////////////////////////////////////
void read_mac_address(uint8_t *address) {
int i;
        for(i=0;i<6;i++) {
                address[i] = SP_ReadUserSignatureByte(i);
        }
}

And the jump table looks like this:

.global SP_ReadByte
SP_ReadByte:
        jmp     0x20a9c

.global SP_ReadWord
SP_ReadWord:
        jmp     0x20aa8

.global SP_ReadCalibrationByte
SP_ReadCalibrationByte:
        jmp     0x20ab6

.global SP_ReadUserSignatureByte
SP_ReadUserSignatureByte:
        jmp     0x20aba

.global SP_ReadFuseByte
SP_ReadFuseByte:
        jmp     0x20abe

.global SP_WriteLockBits
SP_WriteLockBits:
        jmp     0x20ad4

.global SP_ReadLockBits
SP_ReadLockBits:
        jmp     0x20adc

.global SP_EraseUserSignatureRow
SP_EraseUserSignatureRow:
        jmp     0x20ae2

.global SP_WriteUserSignatureRow
SP_WriteUserSignatureRow:
        jmp     0x20aea

.global SP_EraseApplicationSection
SP_EraseApplicationSection:
        jmp     0x20af2

.global SP_EraseApplicationPage
SP_EraseApplicationPage:
        jmp     0x20afa

.global SP_LoadFlashWord
SP_LoadFlashWord:
        jmp     0x20b06

.global SP_LoadFlashPage
SP_LoadFlashPage:
        jmp     0x20bca

.global SP_ReadFlashPage
SP_ReadFlashPage:
        jmp     0x20b10

.global SP_WriteApplicationPage
SP_WriteApplicationPage:
        jmp     0x20b32

.global SP_EraseWriteApplicationPage
SP_EraseWriteApplicationPage:
        jmp     0x20b3e

There is a header file with prototypes for all the SP_xxx functions. I'm not up much on assembly these days, but the output from GCC seems OK. Any thoughts on why this doesn't work?

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

I found my first problem. The spi_driver.S file contains the wrong NVM_CMD for reading user signature row, which of course was the first NVM command I was trying to use...

#define NVM_CMD_READ_USER_SIG_ROW_gc (0x01<<0)

should be

#define NVM_CMD_READ_USER_SIG_ROW_gc (0x03<<0)

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

telliott wrote:
I found my first problem. The spi_driver.S file contains the wrong NVM_CMD for reading user signature row, which of course was the first NVM command I was trying to use...

#define NVM_CMD_READ_USER_SIG_ROW_gc (0x01<<0)

should be

#define NVM_CMD_READ_USER_SIG_ROW_gc (0x03<<0)

After some more experimentation things are working correctly.

I spoke too soon. The sp_driver.S file is correct:
#define NVM_CMD_READ_USER_SIG_ROW_gc (0x01<<0)

The Revision 04/09 doc8077 "A" manual is wrong on page 369

and

avr-libc from debian repository 1:1.6.2.cvs20080610-2 is also wrong in the include file
/usr/lib/avr/include/avr/iox128a1.h
line 4275
NVM_CMD_READ_USER_SIG_ROW_gc = (0x03<<0),

Now happily reading fuses, app crc, boot crc, r/w user signature, and calibration bytes from the application section.

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

telliott wrote:

...I'm trying to read and write to the User Signature Row.

With my 128A1RevH part I've not had any problems with signatures. However I have noted that the very first read of the production serial number (see NVM_PROD_SIGNATURES_t) after power up alway returns a value of zero. Thereafter the values match what Studio shows under the advanced tab.

  (void) ( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM0 ) ) ); /* First read after reset has bug of always returning zero */

byte_u8 = ( SP_ReadCalibrationByte( offsetof( NVM_PROD_SIGNATURES_t, LOTNUM0 ) ) ); 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bpaddock wrote:

With my 128A1RevH part I've not had any problems with signatures. However I have noted that the very first read of the production serial number (see NVM_PROD_SIGNATURES_t) after power up alway returns a value of zero. Thereafter the values match what Studio shows under the advanced tab.

Thanks for the reply Bob. I did get it working. The sp_driver.c example is OK, but the manual and avr-libc include file is wrong for the read User Signature. I also noticed a problem with the first read of the Production row. Works great after that and serves as a great way to generate a unique MAC address.