SpenceKonde / megaTinyCore

Arduino core for the tinyAVR 0/1/2-series - Ones's digit 2,4,5,7 (pincount, 8,14,20,24), tens digit 0, 1, or 2 (featureset), preceded by flash in kb. Library maintainers: porting help available!
Other
564 stars 148 forks source link

Writing flash memory on an attiny3217 #934

Closed Unreal-Dan closed 1 year ago

Unreal-Dan commented 1 year ago

Hello @spencekonde, first thank you for all your hard work on Megatinycore!

My friend and I have been using your library quite reliably to run a firmware on an atmel attiny3217 1-series, we flash it with a separate Uno with jtag2updi.

Our only issue is we are finding that we need more than the available 255 bytes of eeprom, and we cannot fit any external memory modules onto the circuitboard.

On other devices we have that run the same firmware we just rewrite the flash memory but we seem to have hit a roadblock trying to do that with the attiny3217 and megatinycore.

I have noticed that in the boards.txt you have set the fuses for append and bootend to 0:

atxy7.bootloader.APPEND=0x00
atxy7.bootloader.BOOTEND=0x00

If I understand correctly this means the entire section of flash is 'bootloader' code and any attempt to write to a region of flash memory via the NVMCTRL will fail due to the write protections.

I really need to reserve a section of flash memory that is re-writable (at least 1 or 2 kb) and I am willing to get nitty gritty to do it. I am quite experienced and can handle complex instructions and code, in fact I will probably solve the problem eventually by wrapping my own build chain instead of arduino... But it would help greatly if you could give some insight into the issue, and/or point us in the right direction.

Would it be possible to just modify some default settings in the default linker script (is it avr1.x?) for our platform such that a separate region is created that can be written with the nvmctrl?

Thanks in advanced

Dan

SpenceKonde commented 1 year ago

You can do so freely if using Optiboot through the Flash library.

But you're not using optiboot, so no that's not supported. The tricky part is that if you want to rewrite the app section, the code doing the write needs to be in the bootloader section, so you need a "fake" bootloader (this is what we do on DxCore - but over there the code we need to run is trivial SPM Z, RET. On these parts both the writes to the page buffer AND the command to write it must be done in a higher privileged section of mermory If I were to add a menu that changes APPEND (this in and of itself is a pain in the fucking ass, because he APPEND isn't the same in all parts so there has to be a per-chip declaration in boards.txt of what each of them someone coughyoucough would have the task of writing a flashwrite library de novo. You'd have my defines to guide you, ie you could detect how much space and what the address of the start of it was

The IDE could be made to disallow app code to go into appdata by lowering chip flash size.

SpenceKonde commented 1 year ago

If you want to write the library, i'll implement the menu

Unreal-Dan commented 1 year ago

So we actually attempted to use optiboot but could never get that part working, when we try to upload to the attiny3217 we receive this error:

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: Expected signature for ATtiny3217 is 1E 95 22
         Double check chip, or use -F to override this check.

Neither of us are sure what exactly to do but we assumed that optiboot just wasn't an option.

Is there some steps we need to follow to get optiboot working? If so then we would be happy to use that, as we understand it would give us more flash space because it's a smaller bootloader as well. This is definitely beneficial to us.

I think whatever the easiest path may be we would be happy to pursue it.

I understand what you mean about creating a fake bootloader section in order to satisfy the cascading write protections but I am not quite sure how to do it beyond modifying the fuses in boards.txt to create a section of bootloader code by changing BOOTEND (at least I don't know how to do that part properly).

I actually was able to track down the linker script that is being used (it was avrxmega3.xn) and I added in these sections for writable_flash (I have no idea if this is necessary whatsoever):

{
  text   (rx)   : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__ - 1024
  writable_flash (rw!x) : ORIGIN = __TEXT_REGION_LENGTH__ - 1024, LENGTH = 1024
  data   (rw!x) : ORIGIN = __DATA_REGION_ORIGIN__, LENGTH = __DATA_REGION_LENGTH__
  eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
  lock      (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
  signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
  user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
}

...

  .writable_flash :
  {
    _writable_flash_start = .;
    KEEP(*(.writable_flash))
    _writable_flash_end = .;
  } > writable_flash

Then I tried to put a variable in global scope in that section:

__attribute__((section(".writable_flash"))) 
static const uint8_t flash_data[STORAGE_SIZE] = {0};

I verified in my map file that this was present:

_writable_flash_start|00007c00|   R  |            NOTYPE|        |     |.writable_flash 
flash_data          |00007c00|   r  |            OBJECT|00000400|     |.writable_flash  
__RODATA_PM_OFFSET__|00008000|   A  |            NOTYPE|        |     |*ABS*
__TEXT_REGION_LENGTH__|00008000|   A  |            NOTYPE|        |     |*ABS*
_writable_flash_end |00008000|   R  |            NOTYPE|        |     |.writable_flash  

Then I figured that meant I had 0x7c00 text and 0x400 'writable_flash' so I tried to make BOOTEND=0x7c and APPEND=0x00 first try, then APPEND=0x80 second try. I was hoping it would put the first 0x7c00 text into bootloader and the final 0x400 into app code, and then everything else into app data.

This attempt didn't work and the chip just crashed.

So if I can do some kind of nasty hack like this then that would be optimal, I'm not necessary looking for a generalized solution to adjust the flash size in the menus of arduino -- that's a bit overkill for my needs so I don't want to ask you to do that.

But if you can either point us in the right direction for optiboot, or help me create a section of bootloader code that can write memory (I would just need some sort of stub function in the bootloader section right?)

Unreal-Dan commented 1 year ago

I should also note that when trying to do "burn bootloader" that also fails (I've selected attiny3217 w/ optiboot).

It throws an error after burning fuse 8 (bootend) for some reason

C:\Users\danie\AppData\Local\Arduino15\packages\DxCore\tools\avrdude\6.3.0-arduino17or18/bin/avrdude -CC:\Users\danie\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.6.5/avrdude.conf -v -pattiny3217 -cjtag2updi -PCOM12 -b115200 -e -Ufuse0:w:0x00:m -Ufuse1:w:0x00:m -Ufuse2:w:0x02:m -Ufuse5:w:0b11000100:m -Ufuse6:w:0x04:m -Ufuse8:w:0x02:m -Ufuse7:w:0x00:m -Uflash:w:C:\Users\danie\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.6.5/bootloaders/hex/optiboot_txyz{bootloader.entrycond}.hex:i 

avrdude: Version 6.3-20201216
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Users\danie\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.6.5/avrdude.conf"

         Using Port                    : COM12
         Using Programmer              : jtag2updi
         Overriding Baud Rate          : 115200
JTAG ICE mkII sign-on message:
Communications protocol version: 1
M_MCU:
  boot-loader FW version:        1
  firmware version:              6.00
  hardware version:              1
S_MCU:
  boot-loader FW version:        1
  firmware version:              6.00
  hardware version:              1
Serial number:                   00:00:00:00:00:00
Device ID:                       JTAGICE mkII
         AVR Part                      : ATtiny3217
         Chip Erase delay              : 0 us
         PAGEL                         : P00
         BS2                           : P00
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 0
         StabDelay                     : 0
         CmdexeDelay                   : 0
         SyncLoops                     : 0
         ByteDelay                     : 0
         PollIndex                     : 0
         PollValue                     : 0x00
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00
           prodsig        0     0     0    0 no         61   61      0     0     0 0x00 0x00
           fuses          0     0     0    0 no          9   10      0     0     0 0x00 0x00
           fuse0          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse1          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse2          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse4          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse5          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse6          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse7          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           fuse8          0     0     0    0 no          1    0      0     0     0 0x00 0x00
           lock           0     0     0    0 no          1    0      0     0     0 0x00 0x00
           data           0     0     0    0 no          0    0      0     0     0 0x00 0x00
           usersig        0     0     0    0 no         32   32      0     0     0 0x00 0x00
           flash          0     0     0    0 no      32768  128      0     0     0 0x00 0x00
           eeprom         0     0     0    0 no        256   64      0     0     0 0x00 0x00

         Programmer Type : JTAGMKII_PDI
         Description     : JTAGv2 to UPDI bridge
         M_MCU hardware version: 1
         M_MCU firmware version: 6.00
         S_MCU hardware version: 1
         S_MCU firmware version: 6.00
         Serial number:          00:00:00:00:00:00
         Vtarget         : 5.0 V

avrdude: jtagmkII_initialize(): Cannot locate "flash" and "boot" memories in description
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.05s

avrdude: Device signature = 0x1e9522 (probably t3217)
avrdude: erasing chip
avrdude: reading input file "0x00"
avrdude: writing fuse0 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse0 written
avrdude: verifying fuse0 memory against 0x00:
avrdude: load data fuse0 data from input file 0x00:
avrdude: input file 0x00 contains 1 bytes
avrdude: reading on-chip fuse0 data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse0 verified
avrdude: reading input file "0x00"
avrdude: writing fuse1 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse1 written
avrdude: verifying fuse1 memory against 0x00:
avrdude: load data fuse1 data from input file 0x00:
avrdude: input file 0x00 contains 1 bytes
avrdude: reading on-chip fuse1 data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse1 verified
avrdude: reading input file "0x02"
avrdude: writing fuse2 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse2 written
avrdude: verifying fuse2 memory against 0x02:
avrdude: load data fuse2 data from input file 0x02:
avrdude: input file 0x02 contains 1 bytes
avrdude: reading on-chip fuse2 data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse2 verified
avrdude: reading input file "0b11000100"
avrdude: writing fuse5 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse5 written
avrdude: verifying fuse5 memory against 0b11000100:
avrdude: load data fuse5 data from input file 0b11000100:
avrdude: input file 0b11000100 contains 1 bytes
avrdude: reading on-chip fuse5 data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse5 verified
avrdude: reading input file "0x04"
avrdude: writing fuse6 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse6 written
avrdude: verifying fuse6 memory against 0x04:
avrdude: load data fuse6 data from input file 0x04:
avrdude: input file 0x04 contains 1 bytes
avrdude: reading on-chip fuse6 data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse6 verified
avrdude: reading input file "0x02"
avrdude: writing fuse8 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse8 written
avrdude: verifying fuse8 memory against 0x02:
avrdude: load data fuse8 data from input file 0x02:
avrdude: input file 0x02 contains 1 bytes
avrdude: reading on-chip fuse8 data:

Error while burning bootloader.
Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse8 verified
avrdude: reading input file "0x00"
avrdude: writing fuse7 (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of fuse7 written
avrdude: verifying fuse7 memory against 0x00:
avrdude: load data fuse7 data from input file 0x00:
avrdude: input file 0x00 contains 1 bytes
avrdude: reading on-chip fuse7 data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of fuse7 verified
avrdude: reading input file "C:\Users\danie\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.6.5/bootloaders/hex/optiboot_txyz{bootloader.entrycond}.hex"
avrdude: can't open input file C:\Users\danie\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.6.5/bootloaders/hex/optiboot_txyz{bootloader.entrycond}.hex: No such file or directory
avrdude: read from file 'C:\Users\danie\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.6.5/bootloaders/hex/optiboot_txyz{bootloader.entrycond}.hex' failed

avrdude done.  Thank you.
SpenceKonde commented 1 year ago

https://github.com/SpenceKonde/megaTinyCore/issues/927 current release doesn't support burn bootloader because of a typo, and I thought I released 2.6.6 but didn't and proceeded to take a wrecking ball to PWM and now I can't make any PWM come out.

SpenceKonde commented 1 year ago

There is currently no good version. Github version must be manually installed and has no PWM, and latest release doesn't burn bootloader and the one before that and all prior ones have other critical issues.

Unreal-Dan commented 1 year ago

What would you suggest is the best approach forward? I want to minimize the amount of work you have to do.

I'm fine with using optiboot or not, but I'm unsure which would be the least work?

I'm not super familiar with what you mean by the PWM component being broken, we are controlling some leds with some code I borrowed from tinyNeoPIxel but we aren't controlling any kind of pwm through megatinycore that I know of so I don't think that would matter for us.

edit: okay I think I understand the PWM aspect, if we're using analogWrite then it would be broken right?

SpenceKonde commented 1 year ago

Well if using Optiboot instead of UPDI to program, the included flash library (Totally different from the flash library of DxCore - they were developed essentially simultaneously by different people unaware of the other's work; The DxCore one doesn't require optiboot, but the nvm write mechanics are trivial on the Dx.

And yeah PWM from analogWrite() is busted in the github version, and bootloaders are busted in the released version. I'm working on the PWM issue

-Spence

SpenceKonde commented 1 year ago

PWM works, will do release once CI gives go ahead\

Unreal-Dan commented 1 year ago

my hero