ATMega128 self programming question

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

I have two more questions for you kind folks:

1) I'm trying to write flash with the SPM instruction on a ATMega128. Let's say I'm trying to write the 64 words (128 bytes) located at E000 in my address map. How do I set Registers 31, 30 and port RAMPZ to do that. The ATMEL docs on the subject just spin my head around and around and around...

2) Ok so I want to erase the page that holds my interrupt vectors in flash on the ATMega128.
I set bit 0 in RAMPZ to zero. I set SPMSCR with an STS instruction to 3. I load Registers 31 and 30 with zero then issue the spm instruction. Interrupts are disabled. I wait a second or two. The value of SPMSCR is still 0x3. What did I do wrong?

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

wbmarvin wrote:
Let's say I'm trying to write the 64 words (128 bytes) located at E000 in my address map. How do I set Registers 31, 30 and port RAMPZ to do that.
The documentation is pretty clear in describing the operations that must be done. While filling the page buffer, RAMPZ is immaterial and only a subset of the bits in r31:30 are used, i.e the word-based page offset of the page buffer to which the r1:r0 value is written. See the paragraph labeled "Filling the Temporary Buffer" in the section "Self-Programming the Flash".

In contrast, when initiating the page write, the RAMPZ register should contain the 64K page address and r31:30 should contain the address of the first byte in the page to be written. See the paragraph entitled "Performing a Page Write".

Note, also, that you muse first erase a page before it can be written. See the section entitled "Performing Page Erase by SPM. Lastly, you'll have to re-enable the RWW section after the page write completes.

wbmarvin wrote:
I set SPMSCR with an STS instruction to 3. I load Registers 31 and 30 with zero then issue the spm instruction. What did I do wrong?
You probably aren't meeting the four-cycle requirement. Generally, you shouldn't have *any* instructions between the write to the SPMCSR and the SPM instruction. Moreover, the SPM instruction *must* reside in the boot section of the device. If it is in the application section it will be a NOP.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

Oh great, a cross post - he posted exactly the same thing on the end of the Bootloader FAQ thread in tutorial where I wasted my time answering it :-(

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

sorry for the cross post. I'm somewhat new to the forum and posted before I realized I posted to the wrong forum

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

Below is an assembly listing of my erase routine
As you can see the spm is within one instruction
of the load of the SPMCSR register.

Here is what is happening:

I call the routine with interrupts disabled and IFlag = 0. and attempt to break at the ret instruction. The program hangs in the flash_wait_program subroutine. When I examine the SPMCSR register with my emulator is remains at 3. The routines reside at 0xfe00 which should be in a boot loader section

    ??flash_wait_program_0:
    46 {
    47 while((SPMCSR & (1<<SPMEN)) != 0)
    \ 00000000 9100.... LDS R16, _A_SPMCSR
    \ 00000004 2F10 MOV R17, R16
    \ 00000006 FF10 SBRS R17, 0
    \ 00000008 C002 RJMP ??flash_wait_program_1
    48 {
    49 __no_operation();
    \ 0000000A 0000 NOP
    \ 0000000C CFF9 RJMP ??flash_wait_program_0
    50 }
    51 }
    \ ??flash_wait_program_1:
    \ 0000000E 9508 RET
    \ 00000010 REQUIRE _A_SPMCSR
    52
    53 #pragma location="IMMUTIBLE"
    54 #pragma optimize=none
    55

    \ In segment IMMUTIBLE, align 2, keep-with-next
    56 void flash_erase_page(UInt16 address)
    \ flash_erase_page:
    57 {
    \ 00000000 939A ST -Y, R25
    \ 00000002 938A ST -Y, R24
    \ 00000004 01C8 MOVW R25:R24, R17:R16
    58 RAMPZ = address; // set the page addressing range
    \ 00000006 2F08 MOV R16, R24
    \ 00000008 BF0B OUT 0x3B, R16
    59 address = address << 1; // convert into a 17 bit address
    \ 0000000A 0F88 LSL R24
    \ 0000000C 1F99 ROL R25
    60 ZUpper = (UInt8) (address >> 8); // set page address in upper Z ptr
    \ 0000000E 018C MOVW R17:R16, R25:R24
    \ 00000010 2F01 MOV R16, R17
    \ 00000012 E010 LDI R17, 0
    \ 00000014 9300.... STS ZUpper, R16
    61 ZLower = (UInt8) (address & 0x80); // set page address in lower Z ptr
    \ 00000018 2F08 MOV R16, R24
    \ 0000001A 7800 ANDI R16, 0x80
    \ 0000001C 9300.... STS ZLower, R16
    62 if (IFlag)
    \ 00000020 9100.... LDS R16, IFlag
    \ 00000024 2300 TST R16
    \ 00000026 F009 BREQ ??flash_erase_page_0
    63 __disable_interrupt(); // make sure we're not disturbed
    \ 00000028 94F8 CLI
    64 asm("lds R31, ZUpper"); // set zptr
    \ ??flash_erase_page_0:
    \ 0000002A 91F0.... lds R31, ZUpper
    65 asm("lds R30, ZLower"); // " "
    \ 0000002E 91E0.... lds R30, ZLower
    66 SPMCSR = (1<<PGERS) | (1<<SPMEN); // set erase operation
    \ 00000032 E003 LDI R16, 3
    \ 00000034 9300.... STS _A_SPMCSR, R16
    67 asm("spm"); // perform the erase
    \ 00000038 95E8 spm
    68 if (IFlag)
    \ 0000003A 9100.... LDS R16, IFlag
    \ 0000003E 2300 TST R16
    \ 00000040 F009 BREQ ??flash_erase_page_1
    69 __enable_interrupt(); // reenable interrupt
    \ 00000042 9478 SEI
    70 ZUpper = ZUpper -1; // quiet compiler
    \ ??flash_erase_page_1:
    \ 00000044 9100.... LDS R16, ZUpper
    \ 00000048 950A DEC R16
    \ 0000004A 9300.... STS ZUpper, R16
    71 flash_wait_program(); // Warning! SPMCR on debugger does not show changing value
    \ 0000004E .... RCALL flash_wait_program
    72 }
    \ 00000050 9189 LD R24, Y+
    \ 00000052 9199 LD R25, Y+
    \ 00000054 9508 RET
    \ 00000056 REQUIRE IFlag
    \ 00000056 REQUIRE _A_RAMPZ
    \ 00000056 REQUIRE _A_SPMCSR
    \ 00000056 REQUIRE ZUpper
    \ 00000056 REQUIRE ZLower[lis

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

      wbmarvin wrote:
      The routines reside at 0xfe00 which should be in a boot loader section
      If that is a byte address, it is definitely *not* in the boot section. If it is a word address, it is.

      Don Kinzer
      ZBasic Microcontrollers
      http://www.zbasic.net

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

      my linker appears to be byte oriented. It is in fact at 0x1FC00 in the linker directive. It is still not working

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

      I'll answer my own question. The ATMega128A was in "103 compatibility mode" (Ya hafta set a fuse bit) It appearently comes that way from the factory. (So who knew?) LOL

      Thanks for your efforts anyway

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

      Quote:

      (So who knew?)

      Everyone who's read the datasheet perhaps?

      (but yeah, I know, why would anyone read a manual until at least you reach the point where the smoke is released? ;-))

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

      wbmarvin wrote:
      It appearently comes that way from the factory. (So who knew?)
      The datasheet contains that and many other useful bits of information.
      Quote:
      The ATmega128 is by default shipped in ATmega103 compatibility mode.

      Don Kinzer
      ZBasic Microcontrollers
      http://www.zbasic.net

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

      Or when you look over ALL of the fuse settings to configure for a particular app?

      You can put lipstick on a pig, but it is still a pig.

      I've never met a pig I didn't like, as long as you have some salt and pepper.