Assembly FAT code? Or can GCC service interupts fast.

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

I am writing some code that needs to run certain things fast. Also needs to allow 1 interupt to always be se even when serviceing another interupt.
I have looked at using the GCC, but it looks very much like I would have to seriously mess with the interupt code and lots of assembler in it which from may become very boded to get it to work..... Just to be able to use FAT on an SD card easier.
So has anyone tried to do this and what problems were there?
Or is there a key reason why people have not tried to do this yet?
Any good pointers on where to get the info to do it, and which format is best FAT 16 or 32 for cards.

Cheers,
Mark

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

As this is a GCC question you would be better to place it on the GCC forum.

Keep it simple it will not bite as hard

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

I was going to, but its also about assembler and writing FAT code, so put it in the more general area. Sorry for that.

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

I wrote FAT.asm some years ago, but not full function. I used some C source to write in assembly (complied by hand :), I used this code to write come data to CF card:
http://www.vfx.hu/avr/download/f...

VFX.

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

Why do u want to write FAT code in asm? (It's true that it's faster but how fast do u want your code to go?- it's much more difficult to write it in asm and also propably your programme will take much more time executing in the low level driver for SD than in the FAT code). Also it's not a good tactic to let int to interrupt your interrupts cause u can easily end with a mess with your stack. Just try to keep the ints short and the other int will be served just after the first int will be finished.Can u please send your speed requirements so someone can suggest something more specifically.
Kostas

It's better to keep your mouth shut and think you a fool, than open it and move out the doubts!

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

Quote:

It's true that it's faster ...

Here we go again. Please tell me how, exactly, an AVR "knows" whether an ISR is written in ASM, how the AVR "knows" whether an ISR is written in C, and why or how it gets to the ISR faster if written in ASM. Of course, the answer is that the AVR does not know, and you get to the first instruction of the ISR just as fast no matter what language is used.

Now, let us repeat the above reasoning with >>leaving<< the ISR and returning to the mainline code. Eventually the RETI will be done and that takes the same amount of time regardless of the source language.

So, addressing the OPs question, "can GCC service interrupts fast". There is nothing inherent in C programming that would let interrupts be serviced more slowly than in ASM. That said, whether GCC's interurpt handling is as efficient as CodeVision or ImageCraft or Rowley may be another topic of discussion. Perhaps it does a fine job; perhaps you get what you paid for.

The same line of reasoning I used above can apply to the bodies of the ISRs. As always in these challenges, post the fragment of machine language or the algorithm that needs to be done. In almost all cases (the notable exceptions are those in which rotation or the concept of "carry" make the algorithm more efficient--C has no concept of those) straight C can match the ASM times.

Lee

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

If you need fast interrupt response and fast processing for file storage, maybe you should consider not using the FAT filesystem. Depending on many variables, FAT would give you varying response times depending on what it has to do, like allocate another cluster. Also, flash cards sometimes have to to some internal housekeeping that slows the response - so don't expect to get a certain write speed, you may get a high speed burst, slow then high speed burst and so on. For my datalogger, I decoupled the filesystem from my data collection by using a FIFO (first in first out) buffer. It needs to be large enough to soak up the data in the filesystem slow periods. If your data input exceeds the agregate write rate of the filesystem, then the fifo buffer cannot help you as it will fill and data will be lost. Personally, I'd keep the filesystem in 'c' - it waits for write to the flash card most of the time so writing it in assembler probably won't buy you the performance increase you would like. Reality can be a bitch at times!

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

Quote:

Please tell me how, exactly, an AVR "knows" whether an ISR is written in ASM, how the AVR "knows" whether an ISR is written in C, and why or how it gets to the ISR faster if written in ASM. Of course, the answer is that the AVR does not know, and you get to the first instruction of the ISR just as fast no matter what language is used.

Yes AVR doesnt know of Your source: C or asm. Did You see a compilled C source in asm? C and ASM programming is two diffrent logic. Im using asm only, but I dont need a lot of stack (usualy i using 200-300 byte of stack for all program, no need local variable, asm is use lower number of variable as C ect.).
ASM code is smaller -> smaller code is faster.

I dont want a holy war: C vs ASM. Im just answer Your question.

VFX.
http://www.vfx.hu

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

Quote:

Im using asm only, but I dont need a lot of stack (usualy i using 200-300 byte of stack for all program, no need local variable

And the contention is that a program written in C, which does exactly the same thing as your program written in ASM without, will probably end up with similar resource demands.

But then C programmers are prone to start thinking, "Hey, I'm in C... I can add this and that and the kitchen sink with just one or two lines of source!" This thought process, not C itself, is responsible for bloated RAM requirements and undecipherable machine language.

The added bonus of C is that you can then move on to projects with a much larger scope, without the risk of brain explosions. :D

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

Quote:

Did You see a compilled C source in asm?

Yes, often.

Quote:

Im using asm only, but I dont need a lot of stack (usualy i using 200-300 byte of stack for all program, no need local variable, asm is use lower number of variable as C ect.).

Not necessarily. Of course, it depends on the specific example. Most of my all-C applications use a few dozen bytes of stack, if that. I don't use many local variables. Why would ASM need "lower number of variables"--there is no reason based on the language; it depends on how you write it.

Quote:

I dont want a holy war: C vs ASM. Im just answer Your question.

Yes, it is indeed a Holy War. But the question is not yet answered--show me a piece of code that is so much more efficient in ASM that it makes a difference.

There are some easy ways to demonstrate this. I already mentioned two of them: register rotation and use of the carry flag. Another might be 24-bit arithmetic--if it REALLY has an advantage in your app, then it is not convenient to do it in C where only 8, 16, and 32 bit integer types are provided.

I will close by hunting up two of my ISR examples I posted in recent threads on ISR construction. The first is a single-instruction ISR body. The other is a 16-bit x4 quadrature ISR.

         ;    1960 interrupt [TIM0_COMPA] void timer0_compa_isr(void)
         ;    1961 {
          _timer0_compa_isr:
         ;    1962 
         ;    1963 // Flag to main loop that a tick has occured
         ;    1964 	tick = 1;
000548 9af0      	SBI  0x1E,0
         ;    1965 }
000549 9518      	RETI
         ;    2109 interrupt [HALLB_INT] void pin_change_isr1(void)
         ;    2110 {
          _pin_change_isr1:
000580 93ea      	ST   -Y,R30
000581 b7ef      	IN   R30,SREG
         ;    2111 // An edge on HALLB was detected.  We use both edges (x2 quadrature)
         ;    2112 //	as well as both edges on HALLB giving x4 quadrature
         ;    2113 	if (HALLB)
000582 9b32      	SBIS 0x6,2
000583 c008      	RJMP _0x76
         ;    2114 		{
         ;    2115 		// A rising edge.
         ;    2116 
         ;    2117 		if (!HALLA)
000584 994a      	SBIC 0x9,2
000585 c003      	RJMP _0x77
         ;    2118 			{
         ;    2119 			// Positive direction (arbitrary)
         ;    2120 			position += rotation;
000586   +  	__ADDWRR 9,10,7,8
         ;    2121 			}
         ;    2122 		else
000588 c002      	RJMP _0x78
          _0x77:
         ;    2123 			{
         ;    2124 			// Negative direction (arbitrary)
         ;    2125 			position -= rotation;
000589   +  	__SUBWRR 9,10,7,8
         ;    2126 			}
          _0x78:
         ;    2127 
         ;    2128 		}
         ;    2129 	else
00058b c007      	RJMP _0x79
          _0x76:
         ;    2130 		{
         ;    2131 		// A falling edge.
         ;    2132 
         ;    2133 		if (HALLA)
00058c 9b4a      	SBIS 0x9,2
00058d c003      	RJMP _0x7A
         ;    2134 			{
         ;    2135 			// Positive direction (arbitrary)
         ;    2136 			position += rotation;
00058e   +  	__ADDWRR 9,10,7,8
         ;    2137 			}
         ;    2138 		else
000590 c002      	RJMP _0x7B
          _0x7A:
         ;    2139 			{
         ;    2140 			// Negative direction (arbitrary)
         ;    2141 			position -= rotation;
000591   +  	__SUBWRR 9,10,7,8
         ;    2142 			}
          _0x7B:
         ;    2143 
         ;    2144 		}
          _0x79:
         ;    2145 
         ;    2146 }
000593 bfef      	OUT  SREG,R30
000594 91e9      	LD   R30,Y+
000595 9518      	RETI

There is very little fat in these ISRs. Yes, as I previously discussed, I chose my constructs carefully, and used global register variables--the same way it would be done in crafting a critical ISR in ASM. the above two examples are straight C using my choice of compiler that gives me the flexibility to think in machine language and write in C. I always enjoy challenging the generalized statements such as "It's true that it's faster ... ". Is it?

Lee

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

Ok, You are right. This example is good, but I dont understand exatly.
My private mind: if You want write a fast code and You have a lot of time use asm else use C or something.

VFX.

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

VFX wrote:
My private mind: if You want write a fast code and You have a lot of time use asm else use C or something.

You're still missing the point! :roll:

It's not the language that you choose that makes the big difference to the performance of the code that you write - it's how you write it that makes the difference.

It is very likely that assembler code thrown together by a raw newbie with no previous assembler experience and no understanding of the processor architecture will be less efficient than 'C' code carefully written by an experienced embedded programmer with a thorough understanding of the tools and the target architecture!

Again, the point is: it's not the language that counts; it's how you use it.

If you write 'C' with no regard for the underlying architecture, and no understanding of the "cost" of the various constructs that you use, then you will obviously not end up with optimum code

As has already been noted, there are a few cases where 'C' just not suitable and assembler is the only sensible choice - but that's a matter of picking the right tool for the job, not a blanket generalisation like "C is slow; ASM is fast."

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Excuse myself if i didn't understand something in the question but i said that ASM is faster usually cause u can do the critical parts of the program as fast as it gets. You do know how fast a C program is but you don't know in how many instructions your compiler will compile it. We had a conversation before some months of how fast a SW SPI can get and we ended up that in asm it can get to Fclock/5 (/5.4 as Lee stated there with the necessary setup). Personally writing only in C i never managed to get faster than 11 times due to compiling and using CV (i tried certain tactics like loop unrolling or different syntax). I think in asm u can achieve higher speed code. (Personally i prefer C code combined with asm parts for the critical parts if necessary)
My excuses if i misunderstood something
Kostas

It's better to keep your mouth shut and think you a fool, than open it and move out the doubts!

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

Quote:

...i said that ASM is faster usually cause u can do the critical parts of the program as fast as it gets....

And I will say that critical parts can usually/oftem/mostly be done as fast as it gets...

Quote:

You do know how fast a C program is but you don't know in how many instructions your compiler will compile it.

...so you check the instructions, just as you look over the critical sections of your ASM program to see if it can be done better. I have worked in my life with several ASM/machine language gurus that will almost always use the optimal sequence the first time. These people are few and far between. You may very well be one of them.

There are multiple parts to this "challenge". The first is as I mentioned: the generaltities just are not true. Another part is the challenge to see if my tool of choice can generate tight code. So I look forward to seeing the example of the ISR that is sooooo much slower or larger in C. There certainly are some--I've got a couple driving Mega169 LCD segments that the board designer hooked up for ease of board layout, not for software. A single 7-segment digit is spread among 3 I/O bytes. I very quickly decided to write that in ASM. These examples are fairly widely separated, though

So I'm still waiting for the example that I can hold up and say "this ISR cannot be done nearly this fast in C".

Lee

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

Oh boy, a holy war! If I publish a derogatory cartoon about someones favorite assembler or complier will there be rioting in the streets over it or is this a civilized holy war?

One obvious disadvantage is not getting a C complier that optimizes really well. However, bad coding practices and inefficient algorithms can cancel tons of optimization. Bad coding practices can also make assembly code programs that are much less efficient than well written C code programs. Using C code and writing critical code with in-line assembly is an option if you think you can out optimize the C complier. The key here is the word “think”. You should know when and why you are using in-line assembly or you will not achieve anything beneficial by doing so.

An option for an interrupt that must always be active is to look at the ARM or other types of processors with a built in Non-Maskable Interrupt (NMI) and let the hardware do it for you. Another option is maybe your NMI can be put into a dedicated co-processor. It makes the overall design more complex, but a cheap ATtiny or ATmega48 might be able to handle whatever it is your interrupt needs to have done on a full time dedicated basis (as long as you do not need resources on the main processor chip for your NMI).

Because of the way the AVR hardware works, the global interrupt flag will always be cleared by the hardware whenever you service an interrupt. Just for reliability, if you enable global interrupts inside an interrupt response routine, you should disable the specific interrupt vector that is currently being serviced, (this prevents nesting interrupts and possibly having your stack crash). Then you have to decide where to re-enable the interrupt vector. If you re-enable it before exiting the interrupt service routine, then you need to disable global interrupts first to avoid nesting and let the reti instruction do its thing.

You need to be very careful and keep all interrupt service code as small and efficient as possible. Be creative and look for different ways of doing things if it speeds things up. Then maybe you can tolerate having global interrupts disabled for short periods during interrupt service execution.

Another consideration is to use the highest priority interrupt vector for your simulated NMI, so it will always be first in line when global interrupts are re-enabled (especially since you cannot stop the AVR hardware from disabling global interrupts as it sees fit).

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

Wellas i asked the question I muct be in no-mans land.........
Ducks.

Anyway, from what I saw, the C comiler needs to ensure that any current operations need to be stored before the interupt is serviced. To highlight this, there appears to be a flag or different option for GCC to allow sei to be set as the first line of the interupt before the store code runs then it goes into your code. This directly says that the compiler is inserting code before you can deal with the interupt.
This is where I have the problem. I only need to deal with two bytes Very fast here, but also allow another (but only one - not all of them) interupt to run. It one interupt must ALWAYS be serviced, while the others can wait.

Hoe that makes some sense, or have I been reading up the GCC documentation wrong?

Mark

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

Make the two "can wait" interrupts with the INTERRUPT attribute, while the blocking ISR with the SIGNAL attribute. If you are using the previous version o f WinAVR, the macros are:

INTERRUPT(isrname)
{
   // Non-critical ISR code here
}

SIGNAL(isrname)
{
   // Critical ISR code here - no other ISRs may execute while this ISR is running
}

With the latest ISR, you need to specify the interrupt attribute manually:

void isrname_vect() __attribute__((interrupt));
void isrname_vect()
{
   // Non-critical ISR code here
}

ISR(isrname)
{
   // Critical ISR code here - no other ISRs may execute while this ISR is running
}

If you dislike that, use my attached file. That will modify the ISR macro so you can use "ISR(vectname, ISR_BLOCK)" for critical ISRs and "ISR(vectname, ISR_NOBLOCK)" for non-critical ones.

- Dean :twisted:

Attachment(s): 

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Quote:

Using C code and writing critical code with in-line assembly is an option if you think you can out optimize the C complier. The key here is the word “think”.

Exactly.

Now, CodeVision has added some "smart ISR" checking and only saves what needs to be saved. That is the "think" part--you need to know the model of the way the compiler generated code.

The GCC model may be different, and the close-enough-to-optimal fragments that I posted may not apply to your compiler.

Now, if you call a function from your ISR, then pretty much all bets are off--the compiler is forced to save all working registers; it usually will not be able to determine what happens in that other fucntion, whether it is also called from mainline, etc.

Quote:

...if you enable global interrupts inside an interrupt response routine, ...

I have talked myself out of doing that on all of my AVR apps to-date. I keep [almost] all of my ISRs as short as practical--typically a few microseconds. When sketching out the overhead needed to allow another nested interrupt through, it seems that the overhead of additional saving and restoring, the extra stack space needed, the protection against stack windup (as you mentioned), and extra interlocking means that I can get out of the low-priority ISR faster than the overhead to set up for a nested one. IMO the result (with non-nested ISRs) is a simpler and more reliable system. YMMV.

Lee

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

So the sample code will allow one interupt always to be active, even inbetween other interupts?
Ie if Im servicing another one, the SIGNAL interupt will happily interupt it?
Thatss just what I'm after...
Better switch to the GCC forum really Now...

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

INTERRUPTS can interrupt themselves, and other INTERRUPT ISRs. SIGNAL ISRs cannot be interrupted and must complete before other SIGNALS or INTERRUPTS - and can interrupt INTERRUPT attributed ISRs.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

In rare circumstances, I might renable interrupts while handling an exception on an ARM9 or ARM11. But, I have never and would never do this on an AVR(8). Listen to Lee's real-world experience and very good explanation.

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

My ButtLoad application uses several INTERRUPT tagged ISRs, which may be interrupted. These have been done for several reasons, but I made darn sure that problems won't occur because of it. Mainly, i'm using the Butterfly with a serial rate higher than normal on the internal oscillator (calibrating the RC for best performance beforehand). I've had to make all the large ISRs (the LCD interrupt! Oh ATMEL, 30ms a refresh!?!) interruptable so that the extreamly short serial interrupt can jam the incomming data into a ringbuffer for later processing. There are others in Buttload, but that's a good example. Interruptable ISRs arn't nessesarily evil and do have a limited use in AVRs, IMHO of course ;).

AVR-GCC can be configured to intelligently give each ISR its own custom eplilogue and prologue for maximum speed - that way only the registers used by the ISR need to be pushed and poped. This of course falls apart when you call a function from an ISR, but that's nessesary. You can, however, set a flag which will cause GCC to create one honking great big prologue and epilogue which every ISR uses - that saves flash, but it causes longer ISR times.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!