\hypertarget{group__largedemo}{}\doxysubsection{A more sophisticated project}
\label{group__largedemo}\index{A more sophisticated project@{A more sophisticated project}}
This project extends the basic idea of the \mbox{\hyperlink{group__demo__project}{simple project}} to control a L\+ED with a P\+WM output, but adds methods to adjust the L\+ED brightness. It employs a lot of the basic concepts of avr-\/libc to achieve that goal.

Understanding this project assumes the simple project has been understood in full, as well as being acquainted with the basic hardware concepts of an A\+VR microcontroller.\hypertarget{group__largedemo_largedemo_hw}{}\doxysubsubsection{Hardware setup}\label{group__largedemo_largedemo_hw}
The demo is set up in a way so it can be run on the A\+Tmega16 that ships with the S\+T\+K500 development kit. The only external part needed is a potentiometer attached to the A\+DC. It is connected to a 10-\/pin ribbon cable for port A, both ends of the potentiometer to pins 9 (G\+ND) and 10 (V\+CC), and the wiper to pin 1 (port A0). A bypass capacitor from pin 1 to pin 9 (like 47 nF) is recommendable.

 
\begin{DoxyImage}
\includegraphics[width=12cm]{largedemo-setup}
\doxyfigcaption{Setup of the S\+T\+K500}
\end{DoxyImage}


The coloured patch cables are used to provide various interconnections. As there are only four of them in the S\+T\+K500, there are two options to connect them for this demo. The second option for the yellow-\/green cable is shown in parenthesis in the table. Alternatively, the \char`\"{}squid\char`\"{} cable from the J\+T\+AG I\+CE kit can be used if available.

\tabulinesep=1mm
\begin{longtabu}spread 0pt [c]{*{5}{|X[-1]}|}
\hline
{\bfseries{Port}}&{\bfseries{Header}}&{\bfseries{Color}}&{\bfseries{Function}}&{\bfseries{Connect to}} \\\cline{1-5}
D0 &1 &brown &RxD &R\+XD of the R\+S-\/232 header \\\cline{1-5}
D1 &2 &grey &TxD &T\+XD of the R\+S-\/232 header \\\cline{1-5}
D2 &3 &black &button \char`\"{}down\char`\"{} &S\+W0 (pin 1 switches header) \\\cline{1-5}
D3 &4 &red &button \char`\"{}up\char`\"{} &S\+W1 (pin 2 switches header) \\\cline{1-5}
D4 &5 &green &button \char`\"{}\+A\+D\+C\char`\"{} &S\+W2 (pin 3 switches header) \\\cline{1-5}
D5 &6 &blue &L\+ED &L\+E\+D0 (pin 1 L\+E\+Ds header) \\\cline{1-5}
D6 &7 &(green)&clock out &L\+E\+D1 (pin 2 L\+E\+Ds header) \\\cline{1-5}
D7 &8 &white &1-\/second flash&L\+E\+D2 (pin 3 L\+E\+Ds header) \\\cline{1-5}
G\+ND&9 &&unused \\\cline{1-5}
V\+CC&10&&unused \\\cline{1-5}
\end{longtabu}


 
\begin{DoxyImage}
\includegraphics[width=12cm]{largedemo-wiring}
\doxyfigcaption{Wiring of the S\+T\+K500}
\end{DoxyImage}


The following picture shows the alternate wiring where L\+E\+D1 is connected but S\+W2 is not\+:

 
\begin{DoxyImage}
\includegraphics[width=12cm]{largedemo-wiring2}
\doxyfigcaption{Wiring option \#2 of the S\+T\+K500}
\end{DoxyImage}


As an alternative, this demo can also be run on the popular A\+Tmega8 controller, or its successor A\+Tmega88 as well as the A\+Tmega48 and A\+Tmega168 variants of the latter. These controllers do not have a port named \char`\"{}\+A\char`\"{}, so their A\+DC inputs are located on port C instead, thus the potentiometer needs to be attached to port C. Likewise, the O\+C1A output is not on port D pin 5 but on port B pin 1 (P\+B1). Thus, the above cabling scheme needs to be changed so that P\+B1 connects to the L\+E\+D0 pin. (P\+D6 remains unconnected.) When using the S\+T\+K500, use one of the jumper cables for this connection. All other port D pins should be connected the same way as described for the A\+Tmega16 above.

When not using an S\+T\+K500 starter kit, attach the L\+E\+Ds through some resistor to Vcc (low-\/active L\+E\+Ds), and attach pushbuttons from the respective input pins to G\+ND. The internal pull-\/up resistors are enabled for the pushbutton pins, so no external resistors are needed.

Finally, the demo has been ported to the A\+Ttiny2313 as well. As this A\+VR does not offer an A\+DC, everything related to handling the A\+DC is disabled in the code for that M\+CU type. Also, port D of this controller type only features 6 pins, so the 1-\/second flash L\+ED had to be moved from P\+D6 to P\+D4. (P\+D4 is used as the A\+DC control button on the other M\+CU types, but that is not needed here.) O\+C1A is located at P\+B3 on this device.

The {\ttfamily M\+C\+U\+\_\+\+T\+A\+R\+G\+ET} macro in the Makefile needs to be adjusted appropriately for the alternative controller types.

The flash R\+OM and R\+AM consumption of this demo are way below the resources of even an A\+Tmega48, and still well within the capabilities of an A\+Ttiny2313. The major advantage of experimenting with the A\+Tmega16 (in addition that it ships together with an S\+T\+K500 anyway) is that it can be debugged online via J\+T\+AG. Likewise, the A\+Tmega48/88/168 and A\+Ttiny2313 devices can be debugged through debug\+Wire, using the Atmel J\+T\+AG I\+CE mk\+II or the low-\/cost A\+VR Dragon.

Note that in the explanation below, all port/pin names are applicable to the A\+Tmega16 setup.\hypertarget{group__largedemo_largedemo_overview}{}\doxysubsubsection{Functional overview}\label{group__largedemo_largedemo_overview}
P\+D6 will be toggled with each internal clock tick (approx. 10 ms). P\+D7 will flash once per second.

P\+D0 and P\+D1 are configured as U\+A\+RT IO, and can be used to connect the demo kit to a PC (9600 Bd, 8N1 frame format). The demo application talks to the serial port, and it can be controlled from the serial port.

P\+D2 through P\+D4 are configured as inputs, and control the application unless control has been taken over by the serial port. Shorting P\+D2 to G\+ND will decrease the current P\+WM value, shorting P\+D3 to G\+ND will increase it.

While P\+D4 is shorted to G\+ND, one A\+DC conversion for channel 0 (A\+DC input is on P\+A0) will be triggered each internal clock tick, and the resulting value will be used as the P\+WM value. So the brightness of the L\+ED follows the analog input value on P\+C0. V\+A\+R\+EF on the S\+T\+K500 should be set to the same value as V\+CC.

When running in serial control mode, the function of the watchdog timer can be demonstrated by typing an \`{}r\textquotesingle{}. This will make the demo application run in a tight loop without retriggering the watchdog so after some seconds, the watchdog will reset the M\+CU. This situation can be figured out on startup by reading the M\+C\+U\+C\+SR register.

The current value of the P\+WM is backed up in an E\+E\+P\+R\+OM cell after about 3 seconds of idle time after the last change. If that E\+E\+P\+R\+OM cell contains a reasonable (i. e. non-\/erased) value at startup, it is taken as the initial value for the P\+WM. This virtually preserves the last value across power cycles. By not updating the E\+E\+P\+R\+OM immmediately but only after a timeout, E\+E\+P\+R\+OM wear is reduced considerably compared to immediately writing the value at each change.\hypertarget{group__largedemo_largedemo_code}{}\doxysubsubsection{A code walkthrough}\label{group__largedemo_largedemo_code}
This section explains the ideas behind individual parts of the code. The \mbox{\hyperlink{group__largedemo_largedemo_src}{source code}} has been divided into numbered parts, and the following subsections explain each of these parts.\hypertarget{group__largedemo_largedemo_code_p1}{}\doxyparagraph{Part 1\+: Macro definitions}\label{group__largedemo_largedemo_code_p1}
A number of preprocessor macros are defined to improve readability and/or portability of the application.

The first macros describe the IO pins our L\+E\+Ds and pushbuttons are connected to. This provides some kind of mini-\/\+H\+AL (hardware abstraction layer) so should some of the connections be changed, they don\textquotesingle{}t need to be changed inside the code but only on top. Note that the location of the P\+WM output itself is mandated by the hardware, so it cannot be easily changed. As the A\+Tmega48/88/168 controllers belong to a more recent generation of A\+V\+Rs, a number of register and bit names have been changed there, so they are mapped back to their A\+Tmega8/16 equivalents to keep the actual program code portable.

The name {\ttfamily F\+\_\+\+C\+PU} is the conventional name to describe the C\+PU clock frequency of the controller. This demo project just uses the internal calibrated 1 M\+Hz RC oscillator that is enabled by default. Note that when using the {\ttfamily $<$\mbox{\hyperlink{delay_8h}{util/delay.\+h}}$>$} functions, {\ttfamily F\+\_\+\+C\+PU} needs to be defined before including that file.

The remaining macros have their own comments in the source code. The macro {\ttfamily T\+M\+R1\+\_\+\+S\+C\+A\+LE} shows how to use the preprocessor and the compiler\textquotesingle{}s constant expression computation to calculate the value of timer 1\textquotesingle{}s post-\/scaler in a way so it only depends on {\ttfamily F\+\_\+\+C\+PU} and the desired software clock frequency. While the formula looks a bit complicated, using a macro offers the advantage that the application will automatically scale to new target softclock or master C\+PU frequencies without having to manually re-\/calculate hardcoded constants.\hypertarget{group__largedemo_largedemo_code_p2}{}\doxyparagraph{Part 2\+: Variable definitions}\label{group__largedemo_largedemo_code_p2}
The {\ttfamily intflags} structure demonstrates a way to allocate bit variables in memory. Each of the interrupt service routines just sets one bit within that structure, and the application\textquotesingle{}s main loop then monitors the bits in order to act appropriately.

Like all variables that are used to communicate values between an interrupt service routine and the main application, it is declared \mbox{\hyperlink{FAQ_faq_volatile}{volatile}}.

The variable {\ttfamily ee\+\_\+pwm} is not a variable in the classical C sense that could be used as an lvalue or within an expression to obtain its value. Instead, the


\begin{DoxyCode}{0}
\DoxyCodeLine{\mbox{\hyperlink{power_8h_a577a0eebac2a6c2d105e61d9c8f04140}{\_\_attribute\_\_}}((section(\textcolor{stringliteral}{".eeprom"}))) }
\end{DoxyCode}


marks it as belonging to the \mbox{\hyperlink{mem_sections_sec_dot_eeprom}{E\+E\+P\+R\+OM section}}. This section is merely used as a placeholder so the compiler can arrange for each individual variable\textquotesingle{}s location in E\+E\+P\+R\+OM. The compiler will also keep track of initial values assigned, and usually the Makefile is arranged to extract these initial values into a separate load file ({\ttfamily largedemo\+\_\+eeprom}.$\ast$ in this case) that can be used to initialize the E\+E\+P\+R\+OM.

The actual E\+E\+P\+R\+OM IO must be performed manually.

Similarly, the variable {\ttfamily mcucsr} is kept in the \mbox{\hyperlink{mem_sections_sec_dot_noinit}{.noinit}} section in order to prevent it from being cleared upon application startup.\hypertarget{group__largedemo_largedemo_code_p3}{}\doxyparagraph{Part 3\+: Interrupt service routines}\label{group__largedemo_largedemo_code_p3}
The I\+SR to handle timer 1\textquotesingle{}s overflow interrupt arranges for the software clock. While timer 1 runs the P\+WM, it calls its overflow handler rather frequently, so the {\ttfamily T\+M\+R1\+\_\+\+S\+C\+A\+LE} value is used as a postscaler to reduce the internal software clock frequency further. If the software clock triggers, it sets the {\ttfamily tmr\+\_\+int} bitfield, and defers all further tasks to the main loop.

The A\+DC I\+SR just fetches the value from the A\+DC conversion, disables the A\+DC interrupt again, and announces the presence of the new value in the {\ttfamily adc\+\_\+int} bitfield. The interrupt is kept disabled while not needed, because the A\+DC will also be triggered by executing the S\+L\+E\+EP instruction in idle mode (which is the default sleep mode). Another option would be to turn off the A\+DC completely here, but that increases the A\+DC\textquotesingle{}s startup time (not that it would matter much for this application).\hypertarget{group__largedemo_largedemo_code_p4}{}\doxyparagraph{Part 4\+: Auxiliary functions}\label{group__largedemo_largedemo_code_p4}
The function {\ttfamily handle\+\_\+mcucsr()} uses two {\ttfamily \+\_\+\+\_\+attribute\+\_\+\+\_\+} declarators to achieve specific goals. First, it will instruct the compiler to place the generated code into the \mbox{\hyperlink{mem_sections_sec_dot_init}{.init3}} section of the output. Thus, it will become part of the application initialization sequence. This is done in order to fetch (and clear) the reason of the last hardware reset from {\ttfamily M\+C\+U\+C\+SR} as early as possible. There is a short period of time where the next reset could already trigger before the current reason has been evaluated. This also explains why the variable {\ttfamily mcucsr} that mirrors the register\textquotesingle{}s value needs to be placed into the .noinit section, because otherwise the default initialization (which happens after .init3) would blank the value again.

As the initialization code is not called using C\+A\+L\+L/\+R\+ET instructions but rather concatenated together, the compiler needs to be instructed to omit the entire function prologue and epilogue. This is performed by the {\itshape naked} attribute. So while syntactically, {\ttfamily handle\+\_\+mcucsr()} is a function to the compiler, the compiler will just emit the instructions for it without setting up any stack frame, and not even a R\+ET instruction at the end.

Function {\ttfamily ioinit()} centralizes all hardware setup. The very last part of that function demonstrates the use of the E\+E\+P\+R\+OM variable {\ttfamily ee\+\_\+pwm} to obtain an E\+E\+P\+R\+OM address that can in turn be applied as an argument to {\ttfamily \mbox{\hyperlink{group__avr__eeprom_gabeef2e14398b47268f88462b3d7738dc}{eeprom\+\_\+read\+\_\+word()}}}.

The following functions handle U\+A\+RT character and string output. (U\+A\+RT input is handled by an I\+SR.) There are two string output functions, {\ttfamily printstr()} and {\ttfamily printstr\+\_\+p()}. The latter function fetches the string from \mbox{\hyperlink{group__avr__pgmspace}{program memory}}. Both functions translate a newline character into a carriage return/newline sequence, so a simple {\ttfamily \textbackslash{}n} can be used in the source code.

The function {\ttfamily set\+\_\+pwm()} propagates the new P\+WM value to the P\+WM, performing range checking. When the value has been changed, the new percentage will be announced on the serial link. The current value is mirrored in the variable {\ttfamily pwm} so others can use it in calculations. In order to allow for a simple calculation of a percentage value without requiring floating-\/point mathematics, the maximal value of the P\+WM is restricted to 1000 rather than 1023, so a simple division by 10 can be used. Due to the nature of the human eye, the difference in L\+ED brightness between 1000 and 1023 is not noticable anyway.\hypertarget{group__largedemo_largedemo_code_p5}{}\doxyparagraph{Part 5\+: main()}\label{group__largedemo_largedemo_code_p5}
At the start of {\ttfamily main()}, a variable {\ttfamily mode} is declared to keep the current mode of operation. An enumeration is used to improve the readability. By default, the compiler would allocate a variable of type {\itshape int} for an enumeration. The {\itshape packed} attribute declarator instructs the compiler to use the smallest possible integer type (which would be an 8-\/bit type here).

After some initialization actions, the application\textquotesingle{}s main loop follows. In an embedded application, this is normally an infinite loop as there is nothing an application could \char`\"{}exit\char`\"{} into anyway.

At the beginning of the loop, the watchdog timer will be retriggered. If that timer is not triggered for about 2 seconds, it will issue a hardware reset. Care needs to be taken that no code path blocks longer than this, or it needs to frequently perform watchdog resets of its own. An example of such a code path would be the string IO functions\+: for an overly large string to print (about 2000 characters at 9600 Bd), they might block for too long.

The loop itself then acts on the interrupt indication bitfields as appropriate, and will eventually put the C\+PU on sleep at its end to conserve power.

The first interrupt bit that is handled is the (software) timer, at a frequency of approximately 100 Hz. The {\ttfamily C\+L\+O\+C\+K\+O\+UT} pin will be toggled here, so e. g. an oscilloscope can be used on that pin to measure the accuracy of our software clock. Then, the L\+ED flasher for L\+E\+D2 (\char`\"{}\+We are alive\char`\"{}-\/L\+ED) is built. It will flash that L\+ED for about 50 ms, and pause it for another 950 ms. Various actions depending on the operation mode follow. Finally, the 3-\/second backup timer is implemented that will write the P\+WM value back to E\+E\+P\+R\+OM once it is not changing anymore.

The A\+DC interrupt will just adjust the P\+WM value only.

Finally, the U\+A\+RT Rx interrupt will dispatch on the last character received from the U\+A\+RT.

All the string literals that are used as informational messages within {\ttfamily main()} are placed in \mbox{\hyperlink{group__avr__pgmspace}{program memory}} so no S\+R\+AM needs to be allocated for them. This is done by using the P\+S\+TR macro, and passing the string to {\ttfamily printstr\+\_\+p()}.\hypertarget{group__largedemo_largedemo_src}{}\doxysubsubsection{The source code}\label{group__largedemo_largedemo_src}


 
The source code is installed under

\texttt{\$prefix/share/doc/avr-libc/examples/largedemo/largedemo.c},

where \texttt{\$prefix} is a configuration option.  For Unix
systems, it is usually set to either \texttt{/usr} or
\texttt{/usr/local}.
 