Which is better to use in AVR microcontroller programming, ASSEMBLY or C programming?
Can you please help me?
Learn assembler then C so you can understand what the C compiler has produced when fault finding your code. After that it gets religious!
Definitely C programming :-)
Assembley code is going to be alot longer to write, but will operate faster than c code. C code will make your life alot easier, but slow it down (not by much, but will)
Learn assembler then C so you can understand what the C compiler has produced when fault finding your code. After that it gets religous!
This is the best way to go!
Hehe… Depends what you wanna do: swim smoothly (C/EC++) or scuba diving (asm)? :wink:
When you've got an idea about how to implement a certain functionality, most of the work is already done, the rest is the actual coding. So, at this stage, all you need to do is to translate your design into a particular language. In the end, it's a matter of personal preferences, and up to date, every such discussion hasn't come to an end.
PS: having an idea and expressing it: re-think about your title: "Can you please help me?" shows that you didn't come to the step where you clearly can state your problem/solution :lol:
Assembley code is going to be alot longer to write, but will operate faster than c code. C code will make your life alot easier, but slow it down (not by much, but will)
==========================================
Old wives tale. Cite ANY example to back up this claim. Show code. Quantify "not by much" 10% speed improvement? Take as many weeks as you want to carefully tweak this speed improvement, then submit your results.
My first project, back in the mid 1970's, was hand written, and hand entered, with toggle switches. Back then, 1K of memory was just about infinent!
Then I learned assemply for that particular (Fairchild F8) processor. I programmed in assembly for many years, thinking I had to squeeze every byte and clock cycly out of the machine.
Phooey! In most cases I had plenty of time for most things that needed to be done. I usually designed enough EEPROM to accomodate my need. But now I see that even assembly was excrusiatingly painful and needless. But back then, it was all we had!
Now I don't really care about that last colck cycle or byte. Rarely do I have to be concerened about such tight timing restraints that I would consider assembly code. But then, it is available to me within the C compiler, if I deem it neccessary.
In the past year I have done some pretty hard stuff with the AVR machine in C. If I had to do the same in assembly, i'd be pushing a walker before I got it functional.
So, learn assembly, if you want to. Learn C, if you want to. Assembly might save you a few clock cycles, but will the benifit of a clock cycle or two be worth the tremendous increase in time, effort, and debugging?
C will waste a few clock cycles, maybe use a few more bytes, but it is probably an order (10 times) of magnitude faster then assembly.
And, it's just my opinion!!!
I started programming in hex machine code on a Commodore Vic20, then stepped up to the luxury of assembler on the same machine. I still program micros in assembler because it helps me , or forces me I should say, to learn about the workings of the micro. An intimate knowledge of how they operate can be a great help when it comes to de-bugging. Also, a great help when it comes to deciding whether a particular micro is up to the job you have in mind for it. With assembler you can easily calculate how much time the micro will take, to perform a particular task.
I'm not going to say which language I think is better. We don't want another boring C verses assembler war, but the above reasons are why I use assembler.
Edit:
Having just read the post above, I've gotta admit that he's probably right.
I never really learnt much C but the writer above did. I just wonder how good a C programmer one might be, if one had never had the experience with assembler first off. I wonder if one views the micro in the same 'electronic' type way. Anyway, learning assembler first is certainly going to be of enormous benefit when it comes time to learn C.
Cheers Jim
The guys that wrote c at bell labs were all pdp11 assembler programmers, and they wanted to be able to do all the stuff they could do in assembler, like shifts, ands, ors, pointers, incrementing variables (that's the thing++ operator in c folks). c fortran basic and pascal are all very alike (as opposed to forth, lisp apl, and some of these newfangled script languages that I cant even recognize)
One of the nice things about learning a high level language is that you learn about program structure. You learn about the while, do, and for loop, which are very prwerful. You learn about data types, arrays and data structures. You learn about techneques from a "High Level" prespective. You still have to learn about bits, nibbles, bytes, words, and the like, especially as applied to any specific machine. Learning a hich level language is usually less detailed, but provides the opportunity to remove one's self from the "Nity Gritty" that might bog a beginner down.
I learned assembly first, because I had no choice. Even BASIC didn exist (Not the langualge to learn with) back then. I'm not putting assembly down, I happen to like being close to the machine. But I can't see that assembly offers me any real advantage to learning how to use the AVR over C. I still have to figure out how to interpert the data sheet, and apply that information to the goals of the target project. In C, I still have to understand ORing, ANDing, XORin, MASKing, BINARY addition, subtraction, counters, timers, SPI, EEPROM, and all of the other hardware. Where's the assembly in that?
Whether you learn assembly, C Pascal, FORTH, or any other language, if you don't first understand the basic technical concepts of the hardware you are using, the language really becomes less important.
One could say that it is far, far more important to have a good grasp od things like timers, counters, registers, and communications formats, such as used in the UART, USART, SPI. Knowing how oscilators work, power supplys transistors, field effective transistors, diodes, R/C circuits, etc. are just as important.
Unfortunately, as hobbist, we don't all get a structured education, but instead, learn about the things that our imediate interest lead us to.
If I had it to do all over again, I don't think I'd change a thing. I'd Learn and master some basic physics & electronics, then basic machine hardware, along with the diferent numbering systems, and then a peppering of assembly and high level languages.
I can know electronics and control "Real World" things without neccessarily having to know about computers and their languages. But I can't easily control "Real World" things with computers and ltheir languages, without a good understanding of the physics of , and the electrical & electronics, being used to control those "Real World" things.
Can't you see the question answers itself?
"Can't you sea the question answers itself?"
To whom is your question directed toward?
The originaly posted question. Actually, I'm trying to contact WKRP but keep getting reruns.
Hey! That's where I live - here in Cincinnati!!!
Have you guys noticed the other advantage that's gained from learning programming languages ?
It improves your English language skills, both verbal and written.
"Syntax" improves.
i dont think ive sean any programers write like this on this forrum yet have yous ??
Cheers Jim
Assembley code is going to be alot longer to write, but will operate faster than c code. C code will make your life alot easier, but slow it down (not by much, but will)
!
Lots of good points being made, as usual since we do this about once a month. My usual response is:
Assembly language programming is only faster if you are a world class assembly language programmer and you are not.
No one on this thread is and I doubt if many are even regulars on AVRFreaks. I'll back up what Bob said and issue a...
:twisted: Challenge :twisted:
If you want to say that assembly language coding produces faster code then PROVE IT!.
And you can't use a C compiler's assembly listing to tweek your test, you gotta do it from scratch, then test it against a C generated hex file (fairly optimized of course).
ANY TAKERS? bet not. It's like the old saw about the Greeks sitting around arguing about how many teeth a horse has and not a one of them will get up and go find a horse and count the damn teeth!
Even if assembly language programming produced faster code (and it won't be for you or anybody you or I know), it is still takes much more time to produce and is much harder to maintain than C code. Microcarl made a very good point about program structure. I venture to add that if you are a decent assembly language programmer and you learn about all the neat stuff that thousands of Computer Scientists have learned over the past 50 years and apply that knowledge to your programming, you will use your assembly language skills to invent a new language that will be remarkably like C (unless you are a total anal-retentive type and then you'll invent C++)
And, of course the AVR was invented with C specifically in mind during the hardware design phase.
Pppfffbtttzzzz... this is not a religious arguement and all you pro assembly apostates are going to Hell!
Smiley, the apostle of C
I lived in Cincinnati
Thank you Smileymicro...
No REAL programmers here on the list??? (I mean ASM programmers) :)
OK, I am also using C in the meantime, but some of the abovementioned arguments take things a bit to easy IMHO.
Not possible to write code in ASM that RUNS faster than C code? Then you must be a real bad ASM programmer. It may take much more PROGRAMMING time to do it, but it may also RUN a lot faster. It just depends on the problem to solve. Just imagine bit reverse shuffling of a byte (One of my hardware related colleagues likes to connect the data lines of controller and LCD the easiest way on the pcb: D0 to D7, D1 to D6 ...)
How would you solve that in C ?(first guess: fire the colleague):
lcd_byte = 0; If (data_byte & 0x01) lcd_byte |= 0x80; .....
in ASM:
btst data_byte,0 bld lcd_byte,7 ...
Bet that's a lot faster than what YOUR C-compiler generates (CVAVR? No, just kidding, I think not even IAR would do it that way :) ).
Jörg.
Bet that's a lot faster than what YOUR C-compiler generates (CVAVR? No, just kidding, I think not even IAR would do it that way ).
Actually, Jorg, I think that you lose the bet. [Full disclosure: I >>did<< put lcd_byte & data_byte declarations where I knoew that they would be register-based, but, hey, that's what register variables are for, right?]
CodeVisionAVR Standard, version 1.24.5
; 55 void main(void) ; 56 { .CSEG _main: ; 57 unsigned char data_byte; ; 58 unsigned char lcd_byte; ; 59 ; 60 lcd_byte = 0; ; data_byte -> R16 ; lcd_byte -> R17 000094 e010 LDI R17,LOW(0) ; 61 if (data_byte & 0x01) 000095 fd00 SBRC R16,0 ; 62 lcd_byte |= 0x80; 000096 6810 ORI R17,LOW(128)
BTST? I'm not familiar with that assembler mnemonic.
Lee
Aaarrg,
you got me! Where can I send the beer? This was really not a very good example!!! Even if you have to be sure that the compiler uses registers, that is the same with the ASM code.
But wait, there must be a better code example. Would any of the ASM gurus help me, please? There MUST be a really good reason to use ASM!
Jörg.
You still haven't told me what the magic "BTST" instruction is. Or is it a macro?
My example is 2 clocks and 2 words per bit. :)
Lee
Oh sorry, second fault!
Was meant to be 'BST', stores a bit from a register to the T flag in status register. 'BLD' than moves this back to a register.
The T flag is a nice temporary storage for a condition, because it is not touched by any other operation.
Starts to become obvious that I am not using ASM any more (and that its the end of a busy week). Why do I want to defend these ASM guys? Maybe it's because they are a 'dying-out' species and I cannot forget these 'glorious' times of the PDP11 with its switch-knobs!?!
Jörg.
But wait, there must be a better code example. Would any of the ASM gurus help me, please? There MUST be a really good reason to use ASM!
If you would have used the rotate method for your bit reversal (or other algorithms) it would be nearly impossible to duplicate in C, as C has no concept of rotating registers or the CARRY bit. In practice, I've only run into it in the case of bit-reversal (as is your example) and one case of CRC generation.
I >>will<< drop into #asm from time to time in CV programs, not necessarily to save the last cycle or word, but rather to avoid building a very complex C expression. An example of mine would also involve those darned hw layout people: a 2x6 multiplexed keypad, with the 6 row bits scattered all around the AVR. I found that the resulting #asm code was more straightforward to read & understand than the complex C expression with masking & shifting of each bit capture. I believe that most of the C compilers have facilities for inline ASM, but I'm only sure of CV.
Another example might be (say) 24-bit arithmetic, where 16 bits just ain't wide enough and 32 bits just ain't fast enough (or takes too many registers, and results in too many register "spills" to SRAM). Or arithmetic wider than the 32-bits or whatever your compiler supports.
Side story: Back in the early 1970's, the people at Bell Labs were developing lots of electronic switching gear to replace the relay stuff. When the electronics guys would show off their new version that was faster, smaller, less power, etc., the relay guys would look it over and comment to the effect: "Why didn't you SAY that was what you wanted!". They'd return to their labs & come back with the relay version that roughly matched the features of the electronic version.
The "I bet you can't do this in C" claim can be dangerous. :) The current generation of compilers is pretty good at "normal" stuff. You've got to be able to live with the compiler writer's "model" of code generation for the AVR. Very small complete programs may show the ASM version as 10% of the size of the C version--the C version, untweaked, probably has a full vector table and a full startup prologue, even if the complete program is 3 instructions as in our example fragment above. As the app gets filled out, those differences tend to diminish. Also, in the ASM "any program can be made one word shorter"; not >>quite<< as easy to do in C but usually still doable.
CV added "smart" register saving in ISRs a few releases back. I've got a high-speed encoder app with the ISR entirely written in C:
// // ************************************************************************** // * // * P I N _ C H A N G E _ I S R 2 // * // ************************************************************************** // // Pin change 16-23 interrupt service routine // Used for a pin change interrupt on PCINT18 (PIND.2) for recognizing // encoder pulses (Hall switch channel A). interrupt [HALLA_INT] void pin_change_isr2(void) { // An edge on HALLA was detected. We use both edges (x2 quadrature) // as well as both edges on HALLB giving x4 quadrature if (!HALLA) { // A falling edge. if (HALLB) { // Positive direction (arbitrary) position += rotation; } else { // Negative direction (arbitrary) position -= rotation; } } else { // A falling edge. if (!HALLB) { // Positive direction (arbitrary) position += rotation; } else { // Negative direction (arbitrary) position -= rotation; } } }
"position" & "rotation" are 16-bit register variables. I won't reproduce all the generated code, but the ISR stacks just one register which is used to hold the SREG value for restoration:
_pin_change_isr2: 00055e 93ea ST -Y,R30 00055f b7ef IN R30,SREG ; 2096 // An edge on HALLA was detected. We use both edges (x2 quadrature) ; 2097 // as well as both edges on HALLB giving x4 quadrature ; 2098 if (!HALLA) 000560 994a SBIC 0x9,2 000561 c008 RJMP _0x78 ; 2099 { ; 2100 // A falling edge. ; 2101 ; 2102 if (HALLB) 000562 9b32 SBIS 0x6,2 000563 c003 RJMP _0x79 ; 2103 { ; 2104 // Positive direction (arbitrary) ; 2105 position += rotation; 000564 + __ADDWRR 9,10,7,8 ; 2106 } ; 2107 else 000566 c002 RJMP _0x7A
You or I could >>probably<< (now the challeng is to you to get your beer back) save a cycle or two by re-crafting in ASM, but the straight C code has no apparent bloat to me and I felt that any further effort on trying to "optimize" would be wasted.
Lee
Yes,
good examples. I did not want to repeat the code example I posted to another thread some days ago, where a long variable is shifted very inconveniently for a C-compiler (on an 8/16 bit controller):
unsigned long Test; unsigned char tmp; tmp = (unsigned char) (Test>>30);
To have the CVAVR generate good code in this example you will have to use a union for Test and operate the shift only on the high byte. In ASM you just copy the two relevant bits to their destination by one of the abovementioned methods (previous posts).
Jörg.
To have the CVAVR generate good code in this example you will have to use a union for Test and operate the shift only on the high byte.
Well, not exactly. >>If<< you don't care about portable C (the difference in storage order between bigendian & littleendian), then you don't >>have<< to use a union. [The union also depends on storage order so is non-portable. But your ASM needs to use your particular sorage order as well.]
; 102 tmp = (unsigned char) *(((unsigned char *)&Test) + 3) >> 6; 00009d 81eb LDD R30,Y+3 00009e 95e2 SWAP R30 00009f 70ef ANDI R30,0xF 0000a0 95e6 LSR R30 0000a1 95e6 LSR R30 0000a2 2f1e MOV R17,R30
Using the cast of the address and specifying the particular byte (which you do in your head with the ASM solution) results in code which is probably not quite as good as what you could construct, but ain't bad either.
It would be nice if the compiler recognized the situation. [CV >>does<< recognize the situation with masking of 32-bit values: "if (ulong & 0xc0000000)" only fusses with the top byte since the others are irelevant.] But, let's put this in context: >>You<<, as the programmer, looked at the expression and thought: "I only need the top 2 bits, and that is stored at address+3. I'll grab the value at that address, and extract the top 2 bits & put them into the low 2 bits of a register, then store the result." >>I<<, as the programmer, can have EXACTLY THE SAME THOUGHT PROCESSES. We can be writing in two different languages, but C does not prevent the programmer from doing what needs to be done. >>You<<, as the programmer often "know" what is in a register pair or 16-bit storage location. >>I<< can also know that. If my variable is a signed 16-bit value, an int, I can know, just as you do, that at this particular stage of computation there is a small positive integer stored in that location. The ASM programmer would just grab the low byte & use it. The C programmer can give the compiler writer a chance with a well-placed cast:
uchar2 = (unsigned char)sint * uchar1;
will generate smaller and faster code than the vanilla
uchar2 = sint * uchar1;
where the compiler would not only be forced to do the 16-bit multiply, but handle mixed signd vs. unsigned as well. You as the ASM programmer make those decisions in every code sequence; the C programmer can have exactly the same thought processes.
Lee
Agreed!
There might be only one single situation left, where 'you can't do that in C', or at least you shouldn't. This is when your program has to produce a well defined, very fast (compared to the controller clock) pulse train without using PWM or timers etc. Software Uart for example. In ASM you can carefully 'balance' the clock cycles used and these will remain the same every time you use that code again. With C, your code may work at one point, but it may change with the next version of your C-compiler or when using a different optimization. This is the point where you can really use inline-ASM or call an assembler-coded function.
Somewhat constructed situation though, as the controllers are getting faster and faster, the C-compilers improve and you have more and more peripherals included in the controllers which will do most of the job for you.
Jörg.
All that said, I looked up your IAR posting and the compiler not only recognized the situation, but used a neat trick that I never thought of: Use MUL to do a >>6. Cute, if your registers are available. [BTW, that solution isn't optimal either; there is an extra register copy befor the MUL which wouldn't be needed.]
The extra register copy was the reason why I used that code only as a basis for a hand-optimized assembler version (someone didn't like that idea, groenhen?).
It costs just a few minutes and you can use this faster function whenever you want afterwards without having to bother about compiler issues (sort of a library function).
But this example also contradicts most of the assembler freaks. Be honest guys, who of you would have thought of this possibility? It was the C-compiler (or the people behind it) who did it! So at least I can sometimes learn assembler tricks from the compiler-generated code.
I am just wondering, why the IAR compiler does these unneeded register copying. It has not been there some versions before and I have noticed it quite often now. Why dont't they use extra optimization passes? I wouldn't mind some more seconds of compilation time. If this bothers someons, he can buy a faster PC, but there is no faster AVR if your code is on the limit.
Jörg.
I for one, am not going to argue with a C programmer who has a background in ASM.
I've been thinking that maybe I too should learn C.
So, to the ASM/C guys here: What are your favourite Atmel C compilers ?
Cheers Jim
I only have experience with ImageCraft's ICCAVR compiler. This is due mainly because I started with them back in the MC68HC11 days. I can't say thay I have any issues with them. But I have no experience with other compilers to make any compairisons either.
Okay guys I was a little too non specific in my challenge. I should add that the challenge is not for a two or three line snippet that can be biased to favor ASM. I'm talking about a program, say something like the Butterfly state machine for the LCD based menu system. You might be able to write bits and snatches that are better in ASM, but I warrent that an average C programmer can write such a program in about 1/10 the time it would take a good ASM programmer and the C program would be 10 times easier to maintain and 100 times easier to read.
And I don't drink beer, but if somebody meets the challenge I'll post a picture with my AVR tee-shirt pulled up.
Good Luck,
Smiley
And I don't drink beer, but if somebody meets the challenge I'll post a picture with my AVR tee-shirt pulled up.
No there's some motivation! (though after your other post, people may be more interested in your breasts) :shock: :P
Smiley,
I wrote my last pure ASM program for the AVR ~7 years ago. Reason? I had no C-compiler for the AVR at that time. It was a very hardware-related program for the variable-frequency sine-generation for an inverter (DC-AC converter). Timing was very stringent, controller running @3.6MHz.
Tried to translate that program to C afterwards, but this was quite a challenge! And nearly every new compiler version produced a different timing then! Most of the pulse generation was done in the main loop with interrupts only for emergency actions.
I agree, there is NO good reason to write a COMPLETE program with more than a handful of codelines in ASM (sadly, we will not see you with your t-shirt pulled high :( ).
Nevertheless, let's push these compiler guys to optimize the code generation of their C-compilers as much as possible. Let us show them really bad examples of generated code.
To come back to my recent example:
I really want to write:
tmp = (unsigned char)(Test>>30);
instead of:
tmp = (unsigned char) *(((unsigned char *)&Test) + 3) >> 6;
in order to get decent code. At least for me this is faster and easier to read (and write!). Let us solve the problem, let the compiler optimize the code. I just do not even want to have to look at the assembler code. I want to be sure that the compiler generates the best code possible.
Jörg.
Jorg, I think it is unreasonable to expect the compiler to cope with an optimised method of a 30 bit right shift from a long down to a char. If it was say, a 24 bit bit shift - sure, I would expect it to do a register shuffle - in fact, in an earlier version of ICCAVR it would call the generic shift routine for shifts it could perform by register shuffling, so I contacted Imagecraft and it was duly fixed. So how would one handle this problem in assembler - a register shuffle and some shifts? Or we could do a 2 bit left rotate. What 'c' compilers do you know of that would generate your expected code? Try it on VC++ and see what it does.
I notice the ICCAVR compiler generates lots of intermediate register operations when I can see an much neater solution - for the most bit I ignore it, I want the compiler to generate code that works and optimised code as a second priority. If I'm really pushing for performance - then I'll either try to write the code in a way to help the compiler or write the offending sections in assembler.
If one is really intent on seeing what they can get the compiler to generate, there's always the GCC compiler - add you own optimisations to its code generator/optimiser and one will quickly start to realise 1/it is not trivial. 2/ many specific optimisations do not give a general payoff of any great degree. People do their PHD's on these things! There's a wealth of well documented results of various optimisation strategies - it makes for boring reading! No art involved anymore -it's all science!
...expect the compiler to cope with an optimised method of a 30 bit right shift from a long down to a char. ... What 'c' compilers do you know of that would generate your expected code?
From the fragment posted earlier in the thread, IAR does it, and with an elegant MUL to do a >>6.
Lee
That we argue?
On what who has got used - on that and works.
I on Algorithm Builder (http://www.annaanna.nm.ru/AB480.... assembler) create and debugging modules. The ambassador transformation received in the text (http://www.annaanna.nm.ru/MyProg... for AB440 or AB480 ONLY. Russian comments-ExcuseMe). The text I correct as I want. Compile and fill in. The C me to not like. Not evidently as well as assembler.