ATiny Liberation!... Self Replicating Boot Unloader.

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

In a recent ATiny project I have been working on, I find the need to use all 6 IO Pins.

For those that are familiar with the Tiny devices, you know that it only has 5 usable IO Pins.

On a device with only 6 Pins, loosing a Pin HUGE blunder by the designer!!!! (Ok, no more rants).

 

Sure, there are ways around this albatross, but I didn't like any of them, as they added limitations.

 

- Use a high voltage programmer. Problem : Requires special hardware and PC software to use.

- Use one of the many BootLoaders. Problem : Same problem as the last workaround.

- Make a Fuse Rescuer. Problem : Requires special hardware, and moving the chip back and forth every time.

 

I wanted to be able to program and flash the Tiny directly in Studio, and only use my AVRISP, so I came up with a solution...

 

Self Replicating Boot UnLoader, AKA... Quark Loader!

 

Strange name, but suitable since this solution isn't technically a Boot Loader as per the usual suspects.

In Quark Load, you are able to program, assemble, and flash without ever leaving Studio.

To the programmer and IDE, nothing seems different, but the result is all IO Pins usable on the Target ATiny.

Normally, the Rest Pin is dedicated to the ISP, so it can only be used as a limited input, but Quark Loader fixes this.

 

Here are some shots of the hardware, which is basically a "Magic Plug" that fits between your AVRISP and breadboard....

 


Quark Loader - Concept and required components.

 

No doubt, the above photos gives away the solution.

The ATiny marked TX intercepts programming from the AVRISP, and then forwards it to the ATiny marked RX.

An ultra small bit of code that is woven into the main program looks for a signal and then transfers the entire Flash Memory.

This is why I call it a "Self Replicating Boot UnLoader".... it unloads its entire flash to the target, esentially cloning itself.

This process happens automatically right after an ISP programming cycle, so to the user, nothing is any different.

Since the RX (Target) ATiny has the RSTDISBL fuse set, it is free to use the normally locked IO Pin.

 

Quark Loader - Poor Man's PCB.

 

This project was just a quick hack to get around the stupid limitation of the reset Pin, so it ain't pretty!

I will probably use this thing a lot on ATiny projects, so it deserved at least this much refinement.

 

Quark Loader - Completed Hardware ready to use.

 

Since I am using the ATiny-85, this makes the unit backward compatible with some restrictions.

You could program an ATiny-45 for instance, but have to make an adjustment to the INC file to properly report memory sizes.

I made this thing as a solution to an IO Pin problem in my current Quark-85 VGA Project, but it may find a use in other projects.

 

The ATiny85 on the left has been Liberated, and now has 6 IO Pins!

 

So the result is that I can now add sound to this project I have been working on... https://www.avrfreaks.net/forum/quark-85-demo-kube-184-x-240-vga-8-colors-tiny85

The locked Reset Pin is now going to become an output for the Sound Generator.

 

I can continue to program in AS7, using my AVRISP as normal. No strange HV programmer or Boot Loaders requiring one of those Adruiondinno thingys!

 

Since the code for this beast is interwoven in my Video Engine, I will release it when that project is published.

 

Cheers Freaks!

Brad

 

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Sun. Jan 17, 2016 - 07:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mister Magic !

 

Well done, Brad !

 

Nard

A GIF is worth a thousend words   They are called Rosa, Sylvia, Tessa and Tina, You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

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

Utterly mad!

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

Hi Brad,

 

So, I expect I was right with some of my assumptions:

You have some code in the RX device that does the programming there.

I would have called this bootloader, but you are right: that is the wrong word, as it is not "boot" related.

And it is only a part of the solution.

To use the tiny itself as 100% target is a nice idea:

You don't need to care about anything with the protocol etc:

You just get a flash full with your code.

 

I have a few simple questions:

 

1st: "ultra small". The smallest "self programming" solution I've got to work yet needs two pages:

Did you got it smaller than this? As I see, you also need the "upload" code in your binary.

(I think I understand how you can/have solved "page border" problems, so you might not

be bitten by this).

 

2nd: Do you have any kind of validation of the receipt data? I never left out the read back yet:

In your solution, the AVRISP is reading back from the TX (if AVRISP is doing these things, I never used it).

So is the RX device validated in some way?

 

3rd: What happens in case of failure? So if the new application, after transfered to "Rx" will not accept a new download anymore?

In your environment you can still remove the Tiny from the board and use a HV thing of course.

Just doing things right helps a lot of course. But this is programming...

 

Take me right: I like your idea, and I understand why it helps a lot while developing:

Staying in your standard environment and still getting the PIN.

 

Cheers!

  Uli

 

Edit:

PS:

Ha... Finally got it. I was asking and while I did, I thought, maybe Brad has done

this already, so should I. Don't know why: I know he must know almost everything

about AVR better than me. (As most of the people here, I expect).

But I have understood what has to be done to program the flash:

So what can I cut from my bootloader feature list? Almost everything.

Including the word "boot".

So:

16 instructions. 32 Bytes. A single page...

 

Last Edited: Sun. Jan 17, 2016 - 11:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tinybear wrote:

Hi Brad,

 

So, I expect I was right with some of my assumptions:

You have some code in the RX device that does the programming there.

I would have called this bootloader, but you are right: that is the wrong word, as it is not "boot" related.

And it is only a part of the solution.

To use the tiny itself as 100% target is a nice idea:

You don't need to care about anything with the protocol etc:

You just get a flash full with your code.

 

I have a few simple questions:

 

1st: "ultra small". The smallest "self programming" solution I've got to work yet needs two pages:

Did you got it smaller than this? As I see, you also need the "upload" code in your binary.

(I think I understand how you can/have solved "page border" problems, so you might not

be bitten by this).

 

2nd: Do you have any kind of validation of the receipt data? I never left out the read back yet:

In your solution, the AVRISP is reading back from the TX (if AVRISP is doing these things, I never used it).

So is the RX device validated in some way?

 

3rd: What happens in case of failure? So if the new application, after transfered to "Rx" will not accept a new download anymore?

In your environment you can still remove the Tiny from the board and use a HV thing of course.

Just doing things right helps a lot of course. But this is programming...

 

Take me right: I like your idea, and I understand why it helps a lot while developing:

Staying in your standard environment and still getting the PIN.

 

Cheers!

  Uli

 

 

Greets, and thanks for all of the comments!

 

Technically, it will squeeze into one page.

The nice thing is that it fits right after some startup code and leaves a few bytes free before the next boundary.

I do a lot of "strange" things in this one, here are some points that should answer your questions.

 

There is a compiler switch that only needs to be set once for the target.

This puts the RX version of the code in the target, which occupies the same page as the TX version.

So the "development" ATiny (loader) is free to stuff code starting at .ORG 128 up to end of Flash.

This is why I decided to go back to Atmel Assembly... GCC-GAS is stoned when it comes to ORG.

I know there are "ways" to make it work, but I refuse to screw with make files and CLI junk.

For pure assembly, the Atmel assembler is still the best for what I like to do!

 

Anyhow, the code the lives in both ATinys is this bit.

QMODE Switch 0=TX and 1=RX...

 

.if QMODE==0
// [ATINY-85 PORT PINS]
// PORT B.0 > PIN 5 = LED
// PORT B.3 < PIN 2 = INPUT
// PORT B.4 > PIN 3 = OUTPUT
ldi r16,17
out DDRB,r16
clr r16
out PORTB,r16

// SEND PROGRAM REQUEST
sbi PORTB,4

// WAIT FOR RESPONSE
QUARK85_PRESP:
sbis PINB,3
rjmp QUARK85_PRESP

// TURN ON LED
sbi PORTB,0

// SET SOURCE ADDRESS
ldi ZL,low(256)
ldi ZH,high(256)
QUARK85_DLOOP:

// READ PROGRAM DATA
lpm r16,Z+
// SEND DATA BITS
rcall QUARK85_WCLK
sbrc r16,0
sbi PORTB,4
sbrs r16,0
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,1
sbi PORTB,4
sbrs r16,1
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,2
sbi PORTB,4
sbrs r16,2
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,3
sbi PORTB,4
sbrs r16,3
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,4
sbi PORTB,4
sbrs r16,4
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,5
sbi PORTB,4
sbrs r16,5
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,6
sbi PORTB,4
sbrs r16,6
cbi PORTB,4
rcall QUARK85_WCLK
sbrc r16,7
sbi PORTB,4
sbrs r16,7
cbi PORTB,4

// CONTINUE DATA LOOP
cpi ZL,low(8192)
ldi r16,high(8192)
cpc ZH,r16
brne QUARK85_DLOOP

// RELEASE PINS
clr r16
out PORTB,r16
out DDRB,r16

// WAIT FOR PROGRAMMER
QUARK85_END:
rjmp QUARK85_END

// WAIT FOR CLOCK
QUARK85_WCLK:
sbic PINB,3
rjmp QUARK85_WCLK
QUARK85_WCLK2:
sbis PINB,3
rjmp QUARK85_WCLK2
ret

// END OF LOADER
.org 128
.endif

 

.if QMODE==1
// [ATINY-85 PORT PINS]
// PORT B.0 < PIN 5 = INPUT
// PORT B.1 > PIN 6 = OUTPUT
ldi r16,2
out DDRB,r16
clr r16
out PORTB,r16

// STARTUP DELAY
clr r16
clr r17
clr r18
ldi r19,4
QUARK85_SDLY:
dec r16
brne QUARK85_SDLY
dec r17
brne QUARK85_SDLY
dec r18
brne QUARK85_SDLY
dec r19
brne QUARK85_SDLY

// CHECK FOR PROGRAM REQUEST
sbis PINB,0
rjmp QUARK85_NOPROG

// SEND PROGRAM RESPONSE
sbi PORTB,1

// DESTINATION ADDRESS
ldi YL,low(256)
ldi YH,high(256)
QUARK85_LPAGE:

// ERASE 64 BYTE PAGE
movw Z,Y
ldi r16,3
out SPMCSR,r16
spm

// GET 64 BYTES OF EXTERNAL DATA
ldi r17,32
QUARK85_LPB:

// GET WORD DATA
rcall QUARK85_GETDATA
mov r18,r16
rcall QUARK85_GETDATA
mov r19,r16

// STORE 64 BYTES TO PAGE BUFFER
movw r0,r18
ldi r16,1
out SPMCSR,r16
spm
adiw Z,2
dec r17
brne QUARK85_LPB

// WRITE 64 BYTE PAGE BUFFER
movw Z,Y
ldi r16,5
out SPMCSR,r16
spm

// GET NEXT PAGES
adiw Y,32
adiw Y,32
cpi YL,low(8192)
ldi r16,high(8192)
cpc YH,r16
brne QUARK85_LPAGE
rjmp QUARK85_NOPROG

// READ DATA BITS
QUARK85_GETDATA:
clr r16
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,1
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,2
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,4
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,8
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,16
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,32
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,64
rcall QUARK85_TXCLK
sbic PINB,0
sbr r16,128
ret

// CLOCK PULSE
QUARK85_TXCLK:
cbi PORTB,1
ldi r20,100
QUARK85_CDLY:
dec r20
brne QUARK85_CDLY
sbi PORTB,1
ldi r20,100
QUARK85_CDLY2:
dec r20
brne QUARK85_CDLY2
ret

// END OF LOADER
QUARK85_NOPROG:
.org 128
.endif

 

I bit banged the SPI because it was more fun!

Actually, there are other reasons which I will get into later.

 

As you can see, it is basic and raw!

In the event of a failure, the video system will fail to boot, but the loader is always in tact, so it works.

I tried killing it by doing all kinds of things like removing power during a load, reset, etc, but it still works.

The loader kicks in 2 ways... trigger during HSync, or on startup, so the fallback is always there.

Since the loader only writes Flash beyond itself, it would take a lot to kill it.

You are correct though, if somehow it died, a fuse rescue on the target would be in order.

 

No doubt, what I have done here is like running with scissors blindfolded along the freeway while drunk during rush hour!

But hey... it works! I have reprogrammed the target probably 100+ times already!

I should also mention that the target is writing its own Flash at 36Mhz as well!!

 

The way I have the pins configured (RST is Audio output), I can still use standard ISP and see the Video Output.

This allows coding the "normal" way until I want sound, and then I use the SRBU.

 

The goal was to allow my Quark-85 project to have 5 IO (Red, Green, Blue, Sync, Audio) and so far so good.

To be honest, the SRBU was more challenging that the Video Generator, and I am pleasantly surprised that it works.

I never used SPM before this project, so it was a learning curve. Thanks to this community for the help!

 

Cheers,

Brad

 

 

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Mon. Jan 18, 2016 - 12:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry for editing my last post. Didn't expect the next response so fast.

15 instructions now. And a few ideas to get it smaller. There is not a lot left to remove,

so doing it differently would be the next try. Nothing I will try anymore today. Too late.

 

Are you sure this is code from RX? Looks like TX to me. But its late, so ignore me if this nonsense.

(I did not found the SPM yet, that is why I ask)

 

I have to think a bit about your "RX" code is at "TX".

Does AVRISP program everything in TX or only the part after your loader to TX?

If everything, I don't understand why it doesn't upload the RX part to TX?!

 

For the .org problem: I don't get your problem. It is so simple.

But please don't discuss that: Just create your sound generator.

That is more fun... Use the tools you like and fit for you.

 

Finally an optimization question:

sbrc r16,6
sbi PORTB,4
sbrs r16,6
cbi PORTB,4
rcall QUARK85_WCLK

 

(Sorry, I don't know the statements, and don't want to look now):

 

load t with bit 6

rcall

 

and in WCLK

 

skip if t is set

sbi

skip if t is clear

cbi

 

?!

 

Uli

 

 

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

For my optimziation: Ok, maybe the number of cycles.

 

So now this:

 

...

load t with bit 6 of r16  ; 1 cycle?!

store t to bit 4 of a r17 ; 1 cycle?!

out portb,r17 ; 1 cycle?!

rcall

...

 

Did I count wrong? a few less cycles.

Ok, if PORTB is changed in an interrupt this will not work.
Obviously portb must be read to r17 once before doing that stuff.

 

Anyway:

a lot shorter, but not slower I expect:

 

...

load t with bit 6 of r16

rcall

....

 

and there:

 

store t to bit 4 of a r17

out portb,r17

and the rest of your WCLK

 

I'm not familiar with cycles, but a quick check showed me that these skip jumps are "expensive"?

 

Bye,

  Uli

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

I added both code segments (RX and TX) in my post with the code (forgot the second segment).

Only one is active, and it depends on the setting of QMODE.

 

Because the code below .ORG 128 is so small, optimization is not really important.

I still have a few free words, so shortening it would not really do anything.

Before my Loader code, I have some setup stuff for the Video Engine.

It would be impossible to bring it back before .ORG 128, so all is well.

 

Even on the small 8192 Bytes of ATtiny Flash, the Loader code hardly makes a dent.

 

Working on my sound routines now, trying to get a nice clean dual channel mixer going.

Might even have room for a noise channel if things go well.

 

Brad

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Mon. Jan 18, 2016 - 12:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the code.

 

:-)

> Even on the small 8192 Bytes of ATtiny Flash, the Loader code hardly makes a dent.

 

.ORG 128 means 256 byte in your assembler? (gas uses bytes).

Then I understand why you don't have a problem.

 

The 2313 has only 2K flash and a page has 32 bytes (on that chip). But it has the USART

and lots of Pins. So different things, different problems and different projects...

 

Yours is much more fun to read about.

 

Uli

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

Yes, according to the LSS File, .ORG 128 = location 128. Since AVR is organized as words, this is confirmed.

When I use the Z pointer however, I have to point it to location 256, as it works in bytes.

In GCC-AS, I would point Z directly to location 128.

 

The TX section does not care about pages, it just spews out 63,488 Bits (7936 Bytes minus the Loader Segment).

The RX inhales bits, writing as words until it is full, and then continues executing code at location 128.

 

At least, that's how I wrote this thing, and it seems to work so far, and has proven to be very robust to all ways I tried to kill it!

I can crash the Video Driver, smash the stack, cut power during a load, screw with the fuses, and it still repairs (Self Replicates) itself on start-up.

When I think about it, it's more like a Virus than any kind of Boot Loader!

 

Of course, don't consider anything I do to be "good advice"... I am just a weekend hacker right to my core!

 

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Mon. Jan 18, 2016 - 01:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I really should go to sleep...

Anyway, thanks for the info. I think in bytes, so I wasn't sure. 256 bytes is more than enough.

 

I'm down to 14 instructions, 28 bytes now, maybe I will be able to use bit bang io in

this 16 instructions page? That would be nice for an Attiny13. A one page upgrade thing...
 

You can "screw with the fuses" and "it still repairs"?

I'm not sure this is right, because you can't change the fuses in the RX Device?!

 

 

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

Correct, once you set RSTDISBL, you cannot alter the RX fuses.

But the RX only sees the AVRISP once in its lifetime.

When I say mess with the fuses, I mean on the TX unit.

The RX unit cannot write anything beyond .ORG 128, so its Loader code is always safe.

.... well, unless I find out otherwise, but after 100+ program cycles, I have not found any issues yet.

 

Another thing to note is why the hell I have not used the USI to save a few bytes?

Since the Target is always running, and the SRBU is always hooked to the AVRISP, there would be contention.

Because the USI shares the same Pins as the AVRISP ISP, the Target would have to disconnect during a SRBU program cycle.

The way I am using IO out of the SRBU, they do not conflict with either the Target program or the AVRISP ISP.

So this way, I just hit "Program" in AS7, and 5 seconds later, the Target is running the program... like magic!

 

Again, this was a bizarre solution to a bizarre problem, and is probably not much use in the "real World".

SRBU simply lets me use AVRISP, AS7, and get an ATiny85 with 6 usable IO Pins.

I don't need a serial port, don't have to move the chip, don't need a linux machine, and don't need one of those duinnoduielimovimore things!

 

Funny... my original solution involved capturing the ISP signal on an XMega, storing the stream in SRAM, and then sending it HV mode back to the Tiny85!

I only gave up on that version because I couldn't jam it into the AVRISP case. It bothered me because it looked to gangly!

Long live Rube Goldberg!

 

OK, back to the Quark-85 thread.

Might be a while before I get anything done... the real world is cutting into my fun time!

 

Cheers,

Brad

 

I Like to Build Stuff : http://www.AtomicZombie.com

Last Edited: Mon. Jan 18, 2016 - 03:22 AM