Closed Azmisov closed 1 year ago
See pull request which fixes it for me. Also just FYI, the problem was because I had interrupts enabled for the same port as UPDI pin was on, but I did not have the ISR defined. The interrupt got triggered when UPDI started and that must have locked the device with the nonexistent ISR.
Well, if this works, that's pretty damned awesome. That was one of the Three Missing Features.
And that is very interesting. Here is the seqence of events
2-3 clocks from the the interrupt to reach the vector. That's a JMP to BADISR, and almost certainly relaxed to an rjmp. So to clock cycles later, it hits another rjmp, this one to 0x0000. where the CPU would arrive 6-7 clocks from the initial insult. A few very early init tasks would be done, then init3 would be reached, which would then issue a software reset..... to clear the detected dirty reset. I suspect that without the reset, you'd have been able to reprogram.
That implies that it should also be possible to get the same soft brick by uploading this sketch.
#include <util/delay.h>
int main() {
PORTA.PIN0CTRL=0x03; //tinyAVR
//PORTF.PIN7CTRL=0x03; //DD.
}
ISR(PORTA_PORT_vect) {
//ISR(PORTF_PORT_vect) { //DD
__PROTECTED_WRITE(RSTCTRL.SWRR, 1);
}
If that's true, it's rather gross.
Waaait..... waaaaaaiitt is this true?
Can I do fucking ersatz reset for tiny1-series parts ON THE UPDI PIN??? And A) it will reset the part (I did not relize you could do interrupts on the UPDI pin when it's acting as a updi pin) and B) that doing this will foil a programmer that cant do chip erase, but C) can be overcome with updi programmer as long as it does chip erase correctly?
That is would be huge.
That would let you get virtual autoreset for all 0/1-series and 2-series 14-pin parts with unmodified hardware using the same PCBs I sell for using with UPDI fused as reset and optiboot loaded, except you'd be able to disconnect the autoreset bridge and UPDII program it? And all it would cost is the PORTA_PORT_vect?!? If that is true, that has been in my hopeless dream category since day one, because magically we would suddenly have a way to turn UPDI or RESET pin into UPDI and RESET...
I can't get the soft-brick with your code, but it will brick with this:
void setup(){
PORTA.DIRCLR = 0b1; // pa0 input
PORTA.INTFLAGS = 0b1; // clear pa0 interrupts
PORTA.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
}
ISR(PORTA_PORT_vect){
if (PORTA.INTFLAGS & 0b1)
_PROTECTED_WRITE(RSTCTRL.SWRR, 1);
}
void loop(){}
If I do without setup/loop, it doesn't brick. I don't know enough about the differences between main vs setup/loop to comment. Admittedly, this is my first time programming a microcontroller in several years.
I actually didn't realize you couldn't do GPIO and UPDI at the same time. And it was working for both, before I had commented out the ISR. I guess I got lucky since I was using it as input-pullup for a button, same as UPDI. I suppose whenever the button was pressed (longer than 200ns), it triggered the UPDI enable flow, temporarily driving low, then reverting to input-pullup to wait for SYNCH. Since no SYNCH came from the button press, UPDI didn't get enabled.
It's increasingly looking like the UPDI pin, when fused as that, is still fully usable as an input, provided your input don't bear a dangerous resemblance to UPDI commands function as an input pin.
OH, duh, of course my code couldn't manifest it, interrupts start off disabled,
int main() {
sei();
PORTA.PIN0CTRL=0x03; //tinyAVR
//PORTF.PIN7CTRL=0x03; //DD.
}
ISR(PORTA_PORT_vect) {
//ISR(PORTF_PORT_vect) { //DD
__PROTECTED_WRITE(RSTCTRL.SWRR, 1);
}
Not sure exactly how it happened, but I've got an attiny424 that got into a locked state and can't be programmed anymore. I'm trying to do a chip erase with prog.py. Calling:
python3 prog.py -d attiny424 -a erase -u /dev/ttyUSB0
And the logs:I think
pymcu._start_session
shouldn't have returnedSTATUS_SUCCESS
, since the device was locked (if it didn't return success, it would have dropped into the chip erase logic). Digging through pymcuprog included in megatinycore, looks like the culprit is inBackend.start_session
->self.programmer.setup_device
->get_nvm_access_provider
->NvmAccessProviderSerial.__init__
->self.avr.enter_progmode()
. The final call fails (device doesn't unlock before timeout); but the error is caught. Everything else runs fine unwinding the stack toBackend.start_session
. Looks like aPymcuprogDeviceLockedError
should have been raised somewhere, but is not. I think the solution is to raise raisePymcuprogDeviceLockedError
in the try-except block for thatenter_progmode()
call (see nvmserialupdi.py).(Note I think the Device ID mismatch error is misleading, and I suspect just shows up because the NVM programmer couldn't unlock the device and couldn't get an ID)
So after adding that change, I get:
Looks like the
args_start.chip_erase_locked_device
is not being used forNvmAccessProviderSerial
class. It only seems to be used by Searching the files, looks like it is only used inNvmAccessProviderCmsisDapUpdi
. Does the chip erase logic need to be ported toNvmAccessProviderSerial
? Or perhaps I should be calling this with different args so thatNvmAccessProviderCmsisDapUpdi
gets used instead?In any case, in the process of digging further into pymcuprog, it happened to resolve itself:
No other changes necessary, it just happened to get lucky and fix itself. I think maybe there was a problem with an ISR or something, and so the device appeared to be locked when it was just super slow to respond to the serial programmer (?). E.g. note that in the success case, you don't get the
ERROR - Device is locked.
message anymore.So perhaps the timeout for
enter_progmode()
(currently 100ms) should be made higher for my particular case. (Edit: Nevermind, after running into the same problem I put this up to 10s and it still says device locked; so that doesn't appear to help). Though I also suspect that if my tiny were actually locked, it would have continued to fail and you'd need to implement some code to actually handlechip_erase_locked_device
inNvmAccessProviderSerial
. As it stands, turning that flag on in the chip-erase branch of prog.py doesn't actually do anything.