Can someone recommend a good book/reference for going vanilla (i.e. not using arduino simplified language) on e.g. ATtiny85? I will need to use the equivalents of analogRead() and digitalRead() quite a bit. And is softwareserial the best method for debug output? I have less than 8KB of flash, so any advice on that (and reduction of binary for upload) would also be greatly appreciated.
-
Have you tried Atmel's datasheets and application notes?– Ignacio Vazquez-AbramsJul 7, 2016 at 23:38
-
Yes, I am looking for something to supplement those. A collection of commented programs for ATtiny85 would be good, or a beginner/medium book/reference. The avrfreaks forum is very good, but I need more.– user400344Jul 7, 2016 at 23:41
5 Answers
First, let's make this clear: The Arduino environment does not provide a “simplified language”: it provides a simple hardware abstraction layer through its core library. The language is plain C++.
Like Talk2, I don't have good book recommendations. The basics of low-level programming are covered in the Arduino tutorial on port manipulation[]. Past this you will have to dig into the datasheet of your MCU. Look also at the doc of the avr-libc and the tutorials in Nick Gammon's microprocessors pages.
I would suggest you try to develop your program like this:
- Do the initial prototype of your idea on an Arduino Uno (or similar) using the Arduino libraries. It just makes things easier, and you are more likely to get a working prototype pretty fast.
- Once the initial idea works, optimize it for the limited resources of the ATtiny85. This may involve replacing some call to the Arduino libs with avr-libc and/or direct port access.
- You may then want to remove all references to Arduino core, but you don't have to: there are some ATtiny cores available that you can use if you want.
- If it now fits in less than 8 K, port to the ATtiny.
The thing I love about the Arduino environment is that you can very
easily mix and match abstraction levels: you can have, in the same
program, calls to Arduino core, to avr-libc, direct port access, and
even inline assembly if want to. You don't even need to stick to the
setup()
and loop()
method: you can write your own main()
if you
prefer, just remember to call init()
to initialize the Arduino core if
you are going to use it. Oh, and you don't have to use the Arduino IDE
either if you don't like it (I don't).
As for the optimization tips, I would recommend :
- Use direct port access instead of
digitalRead()
, because that function is pretty big and slow. analogRead()
may not be that bad, size wise, but it has a serious shortcoming: it's a blocking function which spends 104 µs in a spin loop, just waiting for the ADC result. If your CPU has better things to do, you may want to implement a non-blocking read instead.- For debugging output, the most efficient option is likely to be the USI port. You will have to search for a driver or implement your own based on the Atmel application note AVR307: Half Duplex UART Using the USI Module. Alternatively, you could use something like AltSoftSerial. Do not use SoftwareSerial: it blocks interrupts for insanely long amounts of time.
- Use the command
avr-nm --size-sort -Crtd my_program.elf
to get a listing of the functions of your program sorted by flash usage. This will help you choose good targets for size optimization.
-
This is as near to perfect as reality permits. Thank you very much :) Jul 8, 2016 at 10:59
I can recommend the book "Make: AVR Programming", which uses avr-gcc directly. The Arduino IDE is mentioned at one point, but just in order to "place" it, and to explain how to use its libraries in your own code. You can study all the code used in the book right here (github link).
(late answer, I know, I was searching for other books that don't use the Arduino IDE and stumbled upon this question)
If you abandon the Arduino paradigm you will be pushed into dealing with setting up all the hardware that makes today's embedded processor so flexible. This usually takes an experienced embedded programmer days if not weeks to get through on a new processor. You will also need a dedicated Atmel programmer as you will no longer be using the Arduino boot loader.
Once you get past these obstacles, you can start studying C and C++. The "grand dad" C reference book would be by the "first guys" that did C, Kernighan & Ritchie. The equivalent C++ book (if you are up to it) would be by Bjarne Stroustrup.
However...
What have you gained by abandoning the Arduino paradigm?
Some would say, not much.
Most of why programming in the Arduino paradigm is easy has to do with Arduino libraries. They "abstract" the hardware down to a couple simple function calls. For example, with one function call you can set up the pulse train that can position a servo motor using a familiar term: degrees.
It should also be pointed out that the compiler Arduino uses is a C / C++ compiler. And that most Arduino libraries are purposely written in C++.
Perhaps writing a C++ Arduino library is a good way to learn C++. Start by finding the code to libraries that you already use. Then reviewing how the C++ code is put together. Finally write you own C++ Arduino library.
Sorry, I don't have any book recommendation apart from the AVR Datasheet.
You could try to use AVR-LIBC as a abstraction layer instead of playing directly with individual registers: http://www.nongnu.org/avr-libc/.
That might help you saving some Ks on your code which the Arduino layer might be adding. Just make sure you have a proper IDE to assist you with code-completion and navigation.
Also Atmel has a good link how to optimize your C code: http://www.atmel.com/images/doc8453.pdf, which I had a look when doing some bootloader coding.
Finally, you could explore the Arduino libraries, and see the overhead added to each function, like "analogRead()" from your example. Most of the Arduino funcions will be a layer on top of the AVR-GCC, so it'll be a good learning exercise - again, get a proper IDE that helps with auto-completion and navigation.
Cheers
-
avr-libc does very little to abstract the hardware: you are still going to access the hardware registers “manually”. Only it is easier with avr-libc, as it lets you write things like
PORTB |= _BV(2);
instead of* (volatile uint8_t *) 0x25 = 1 << 2;
. The generated code is the same (namelysbi 0x5, 2
). Jul 8, 2016 at 11:11
The Arduino implements a subset of c++. I am not sure what you expect to achieve by not using it.
If you are really after optimum code, there is no obligation to use any inbuilt function and you can code your own.
Most conventional compilers use a standard runtime library. The reason Arduino does not is because of the limited memory. It is necessary to omit many standard functions to save space.
By not using a library only functionality you need is actually linked in.
-
The Arduino core is a runtime library, built on top of avr-libc, which is itself another runtime library. But the linker is smart enough to only link into your program the functions you do use. Jul 8, 2016 at 10:55
-
@EdgarBonet if it only links used functions it is a library which produces a staticly-linked executable, but not a "runtime library" which is loaded in its entirety by the OS - non-existent on the Arduino. Jul 8, 2016 at 11:03
-
Yes, these are statically linked libraries. If by “runtime library” you mean a library loaded in its entirety by the OS (I would call that a “dynamic library”), then no, there is not, simply because there is no OS. There is a “C runtime” though, courtesy of avr-libc (the files crt*.o): it contains the interrupt vector table, the catchall interrupt, the initializations of r1, SREG and the stack, and the calls to
main()
andexit()
. Jul 8, 2016 at 11:27