asm inline help

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

Hi everyone,

I'm trying to do a very specific thing which I know how to do in assembly, but I'm lost on how to accomplish it using the avr-gcc compiler. This is WinAVR 2010 01 10 on an ATtiny461A

What I want to do is have the first few instructions of my program load the last value in the program memory, and compare it to some magic value. If it's correct, continue as normal, if incorrect just loop back on itself. This would go in __init()

#define last_byte_high 0x0F
#define last_byte_low 0xFF
#define magic_number 0xA5

loop: ldi ZH,last_byte_high
      ldi ZL,last_byte_low
      lpm r16,Z
      cpi r16,magic_number
      brne loop

I've tried going through the different options in the user manual below, but I'm having trouble even loading the address into the z register. Any ideas?
http://www.nongnu.org/avr-libc/u...

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

What you posted should work for loading the pointer ( works for a m644 in the simulator using Winavr / Studio using a *.S file though ), so I don't get what's going on. HOW does the pointer code not work ? Do you get an error ?

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Mon. Apr 11, 2011 - 07:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, I guess I should have been more clear. I'm using the c compiler, and I just want to do an asm inline.
I've tried using

asm volatile("ldi [percent]a0, [percent]1":: "15" (value))

and variations on that, but can't get seem to get it to work. For some reason I can't post the % in code, sorry.

Is there a way I can use assembler mnemonics directly?
Thanks

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

Yeah % won't go thru when in quotes, but there are at least 2 ways to do it ( which I can't remember ).

No need for nasty inlining !

#include 

#define  end  0x0FFF

uint8_t  hold;
.
.
.
main ( void ){

hold = pgm_read_byte(end);

produces :

hold = pgm_read_byte(end);
  d0:	ef ef       	ldi	r30, 0xFF	; 255
  d2:	ff e0       	ldi	r31, 0x0F	; 15
  d4:	e4 91       	lpm	r30, Z+
  d6:	e0 93 00 01 	sts	0x0100, r30

BUT, how do you think ANY data's gonna change in program memory ? People say you can change it if doing a bootloader, but that's about it.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Mon. Apr 11, 2011 - 07:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Perhaps you want something like

#include 

#define address 0x0FFF 
#define magic_number 0xA5 

const uint8_t * loop (void)
{
    uint8_t temp;
    const uint8_t * addr = (const uint8_t*) address;
    
    asm("0:"                    "\n\t"
        "lpm $[tmp], Z+"       "\n\t"
        "cpi $[tmp], $[magic]"  "\n\t"
        "brne 0b"
        : [Z] "+z" (addr), [tmp] "=d" (temp)
        : [magic] "n" ((uint8_t) magic_number));
        
    return addr-1;
}

Replace $ with % for error in forum stuff.

gcc produces

loop:
	ldi r30,lo8(4095)
	ldi r31,hi8(4095)
/* #APP */
	0:
	lpm r24, Z+
	cpi r24, -91
	brne 0b
/* #NOAPP */
	movw r24,r30
	sbiw r24,1
	ret

I think memchr_P or similar stuff is what you are after?

http://avr-libc.nongnu.org/user-...

avrfreaks does not support Opera. Profile inactive.

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

indianajones11 wrote:
Yeah % won't go thru when in quotes, but there are at least 2 ways to do it ( which I can't remember ).
I don't know what is the second but the first is to write % instead of %.

JW

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

Better use a CRC across the entire program memory.

As seen above, no need for inline asm. You can do all this in C.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Thanks guys. I was worried about not getting the exact behavior I wanted from the compiler, but the progspace macros give me the behavior I want.

I would like to do a CRC across the whole prog memory dl8dtl, but my timing specs wouldn't allow me to. This is a compromise between robustness and speed.

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

A CRC with a LUT can be done fairly fast!

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

Quote:

BUT, how do you think ANY data's gonna change in program memory ?

:twisted: Yeah, it gives the bean counters a warm fuzzy feeling. And it certainly could/should be part of a bootloader sequence.

"But who will watch the watchers?" How do you know the CRC routine is not the corrupted piece?

Re timing specs: do tell more. Yes, I have some apps where I jump into operation >>fairly<< quickly--but that is still measured in milliseconds. My typical startup pause to let things settle is 125ms. (LCDs are slow to get up in the morning.) If I go through 64k of program space and spend a microsecond on each byte, that is 65ms right? And you only have 4k.

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.

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

Quote:

And it certainly could/should be part of a bootloader sequence.

Surely that's exactly what's being discussed here? The reason for the check is for when the bootloader started to upgrade the application flash but was then interrupted (cable pulled, power failed etc). When the bootloader next starts how does it know there is a "whole" app in the application section? One way is a simple flag at the end of the app space which is wiped first and replaced last during an update. A more secure method (in case one page was missed/corrupted) is to embed a CRC at the end of the app flash then have the BL run a CRC over the app space and compare before it's willing to jump into the app. This not only ensures that the programming completed but also that everything is completely intact. Very wise for a bootloader to do this and probably well worth the few hundred milliseconds at power on to do it.

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

Quote:

Surely that's exactly what's being discussed here?

OK, I re-read the entire thread and I still say I need my crystal ball to divine that. And don't call me Shirley.

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.

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

Shall we put money on it for when we here back from OP? ;-)

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

I'm in. What's the ante? :)

How about this one too? :D

https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=105507

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

theusch wrote:
Quote:

BUT, how do you think ANY data's gonna change in program memory ?

:twisted: Yeah, it gives the bean counters a warm fuzzy feeling. And it certainly could/should be part of a bootloader sequence.

"But who will watch the watchers?" How do you know the CRC routine is not the corrupted piece?

Re timing specs: do tell more. Yes, I have some apps where I jump into operation >>fairly<< quickly--but that is still measured in milliseconds. My typical startup pause to let things settle is 125ms. (LCDs are slow to get up in the morning.) If I go through 64k of program space and spend a microsecond on each byte, that is 65ms right? And you only have 4k.

It has to take control of it's IO within 10us and start at 1MHz, so the timing requirements are very restrictive. I'm already exceeding them obviously, but they'll just have to live with that. :)

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

Quote:

It has to take control of it's IO within 10us and start at 1MHz, so the timing requirements are very restrictive.

That doesn't mean that you can't do your port init, and then continue with the flash verification. (Following on to "who watches the watchers", why can't this mysterious flash corruption occur during normal operation? thus, the checking process should be ongoing anyway.)

And (surely) you haven't answered directly the bootloader question. From your post, however, it seems I might be collecting the virtual antes.

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.

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

clawson wrote:
Shall we put money on it for when we here back from OP? ;-)

Come on guys, surely posting one day apart isn't too bad. I'm going to have to get updates to this thread sent to my phone to keep up around here. :)

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

theusch wrote:
Quote:

It has to take control of it's IO within 10us and start at 1MHz, so the timing requirements are very restrictive.

That doesn't mean that you can't do your port init, and then continue with the flash verification. (Following on to "who watches the watchers", why can't this mysterious flash corruption occur during normal operation? thus, the checking process should be ongoing anyway.)

And (surely) you haven't answered directly the bootloader question. From your post, however, it seems I might be collecting the virtual antes.

That's actually an interesting idea, although there is no bootloader in this application. It's a power management uc and it's programmed using ISP by a microprocessor running Linux. The danger of that approach is that since verification is done after the IO is set, there is still the possibility that corruption during programming could cause the uC to drive it's outputs but then enter an indeterminate state. IE, after the chip erase the first pages with the vector table and IO control are written, but the CRC code is corrupted or never gets written.

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

DaveWill wrote:
It has to take control of it's IO within 10us and start at 1MHz, so the timing requirements are very restrictive.
If "take control of its IO" means to set the ports to some particular state, you surely can do that as the very first instructions (after the jump from reset vector). However, this won't happen before the oscillator (whichever you use) starts up and then the internal reset is finished (see ksel), so there is no way you can achieve 10us, if that was meant from the moment the power ramps up.

JW

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

To program:
erase flash
write rjmp .-2 in page 0
write the rest of the pages
write page 0

If writing page 0 twice really bothers you:
erase flash
write rjmp .-2 in page 1
write the rest of the pages

Persuading the tool chain to skip over page 1 (at
least its word 0) is left as an exercise for the reader.

Iluvatar is the better part of Valar.

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

skeeve wrote:
To program:
erase flash
write rjmp .-2 in page 0
write the rest of the pages
write page 0

If writing page 0 twice really bothers you:
erase flash
write rjmp .-2 in page 1
write the rest of the pages

Persuading the tool chain to skip over page 1 (at
least its word 0) is left as an exercise for the reader.

That was the original solution to the problem. The person writing the comm libraries on the linux side indicated that this wouldn't be possible though, since he found he could only write a page once after a chip erase. IE, you can only clear a bit not set it, and if you write 0xF5 to a location and then write 0xAF to it in a later write without a CE, you would read 0xA5 from that location.

I thought this was strange since you can do self-programming of the flash, but didn't look into too much. Is it possible to write over already written page in flash without releasing the reset pin?

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

DaveWill wrote:
skeeve wrote:
To program:
erase flash
write rjmp .-2 in page 0
write the rest of the pages
write page 0

If writing page 0 twice really bothers you:
erase flash
write rjmp .-2 in page 1
write the rest of the pages

Persuading the tool chain to skip over page 1 (at
least its word 0) is left as an exercise for the reader.

That was the original solution to the problem. The person writing the comm libraries on the linux side indicated that this wouldn't be possible though, since he found he could only write a page once after a chip erase. IE, you can only clear a bit not set it, and if you write 0xF5 to a location and then write 0xAF to it in a later write without a CE, you would read 0xA5 from that location.

I thought this was strange since you can do self-programming of the flash, but didn't look into too much. Is it possible to write over already written page in flash without releasing the reset pin?

I'd forgotten about that.
For some reason, one can erase a single page from code,
but not through ISP.
This might work:
  .section .init0
  ; in page 0 we hope
  rjmp 5f
  .align 128  ; or the correct page size
  rjmp .-2
5:

The section command might need work.
Program page1 first, page 0 last.

Iluvatar is the better part of Valar.

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

Quote:

although there is no bootloader in this application.

Your weren't supposed to say that! One virtual beer to Lee then.

But I'm curious, if it's not for an app validity check then WHY do you need to read the last bytes of flash? If it's some kind of "cookie" value held there (an Ethernet Mac address perhaps?) then is EEPROM not the more obvious place to hold it?

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

clawson wrote:
Quote:

although there is no bootloader in this application.

Your weren't supposed to say that! One virtual beer to Lee then.

But I'm curious, if it's not for an app validity check then WHY do you need to read the last bytes of flash? If it's some kind of "cookie" value held there (an Ethernet Mac address perhaps?) then is EEPROM not the more obvious place to hold it?

:) Well, I guess you could call these few lines of code a bootloader that checks a byte and either runs the main program or another.

The purpose of this is for an app validity check. To make a long story sort of short, it's a power management uC for a battery-powered microprocessor-based embedded system. The uC has no real outside connection, it just monitors battery voltage and a couple digital inputs, and controls the system power supply. However, since the unit defaults to a main power off state, it's possible that if the first couple pages get written but the rest don't for whatever reason (power loss, uP lock during programming, etc), the uC can turn off the main power and then reach a point where all the code is FFs, and never be able to turn on the main power. No main power means no uP, and no way to programming the unit baring physically opening it up and tying the power supply line high.

Doing a full CRC would be ideal, but since the uC needs to force the power supply off within a short time in order to prevent pulsing the power on and off, it's probably not possible.

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

Quote:

it's possible that if the first couple pages get written but the rest don't for whatever reason (power loss, uP lock during programming, etc)

What's doing this writing then? Are you talking about ISP or JTAG programming? If so why is that programmer not doing a verify check at the end to make sure the programmed code is intact?

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

The uP downloads the upgrade through WiFi/CDMA/GSM and performs the upgrade using ISP.

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

Then why can it not do an integrity check at the end before letting the uC "rip"?

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

I just though of something better.
For both versions of your code:

  .section .one.more.vector,"ax",@progbits
  RJMP .-2

Edit the linker script so that it places section .one.more.vector just after .vectors .
For the second version, additionally edit so that no .vectors section is included.
Replace it with 0xFFFFs.
As an alternative, the second hex or binary file could be made by directly editing the first.
Now you can program page zero twice.
The second programming only needs to clear bits.

Iluvatar is the better part of Valar.

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

clawson wrote:
Then why can it not do an integrity check at the end before letting the uC "rip"?

It does, but if an external event like a power loss or some daemon locking up caused the programming to fail, it might not reach the point where it performs the verification. In that case, it could brick the unit.

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

What happens if the "break" in code presence is half way through the AVRs integrity flag checking routine? That's why it could make a lot of sense to put this in a bootloader that (a) never changes and (b) can be separately protected by lock bits.

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

clawson wrote:
What happens if the "break" in code presence is half way through the AVRs integrity flag checking routine? That's why it could make a lot of sense to put this in a bootloader that (a) never changes and (b) can be separately protected by lock bits.

In that case, all the pins would still be inputs, and pull ups on the power supply pins would keep the main supply on, in the same way that the uP can be booted before the uC is programmed.

With b, I'm not sure to what you're referring. Are you suggesting having the uP write the program through the bootloader using self-programming?

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

DaveWill wrote:
clawson wrote:
What happens if the "break" in code presence is half way through the AVRs integrity flag checking routine? That's why it could make a lot of sense to put this in a bootloader that (a) never changes and (b) can be separately protected by lock bits.

In that case, all the pins would still be inputs, and pull ups on the power supply pins would keep the main supply on, in the same way that the uP can be booted before the uC is programmed.

With b, I'm not sure to what you're referring. Are you suggesting having the uP write the program through the bootloader using self-programming?

Lock bits can prevent a bootloader from writing on itself.
If you use a bootloader,
you only have to get it right once.
Your corruption checking code can go in the bootloader.

Iluvatar is the better part of Valar.

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

Quote:

Are you suggesting having the uP write the program through the bootloader using self-programming?

You could go either way. But the lock bits give you a bit of memory protected from external interference though I fear an ISP "chip erase" will clear the locks and wipe anyway - but maybe ISP has the ability to just erase individual pages (I dunno enough about it to say)?

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

clawson wrote:
Quote:

Are you suggesting having the uP write the program through the bootloader using self-programming?

You could go either way. But the lock bits give you a bit of memory protected from external interference though I fear an ISP "chip erase" will clear the locks and wipe anyway - but maybe ISP has the ability to just erase individual pages (I dunno enough about it to say)?
It doesn't.

Iluvatar is the better part of Valar.