\hypertarget{group__asmdemo}{}\doxysubsection{Combining C and assembly source files}
\label{group__asmdemo}\index{Combining C and assembly source files@{Combining C and assembly source files}}
For time-\/ or space-\/critical applications, it can often be desirable to combine C code (for easy maintenance) and assembly code (for maximal speed or minimal code size) together. This demo provides an example of how to do that.

The objective of the demo is to decode radio-\/controlled model P\+WM signals, and control an output P\+WM based on the current input signal\textquotesingle{}s value. The incoming P\+WM pulses follow a standard encoding scheme where a pulse width of 920 microseconds denotes one end of the scale (represented as 0 \% pulse width on output), and 2120 microseconds mark the other end (100 \% output P\+WM). Normally, multiple channels would be encoded that way in subsequent pulses, followed by a larger gap, so the entire frame will repeat each 14 through 20 ms, but this is ignored for the purpose of the demo, so only a single input P\+WM channel is assumed.

The basic challenge is to use the cheapest controller available for the task, an A\+Ttiny13 that has only a single timer channel. As this timer channel is required to run the outgoing P\+WM signal generation, the incoming P\+WM decoding had to be adjusted to the constraints set by the outgoing P\+WM.

As P\+WM generation toggles the counting direction of timer 0 between up and down after each 256 timer cycles, the current time cannot be deduced by reading T\+C\+N\+T0 only, but the current counting direction of the timer needs to be considered as well. This requires servicing interrupts whenever the timer hits {\itshape T\+OP} (255) and {\itshape B\+O\+T\+T\+OM} (0) to learn about each change of the counting direction. For P\+WM generation, it is usually desired to run it at the highest possible speed so filtering the P\+WM frequency from the modulated output signal is made easy. Thus, the P\+WM timer runs at full C\+PU speed. This causes the overflow and compare match interrupts to be triggered each 256 C\+PU clocks, so they must run with the minimal number of processor cycles possible in order to not impose a too high C\+PU load by these interrupt service routines. This is the main reason to implement the entire interrupt handling in fine-\/tuned assembly code rather than in C.

In order to verify parts of the algorithm, and the underlying hardware, the demo has been set up in a way so the pin-\/compatible but more expensive A\+Ttiny45 (or its siblings A\+Ttiny25 and A\+Ttiny85) could be used as well. In that case, no separate assembly code is required, as two timer channels are avaible.\hypertarget{group__asmdemo_asmdemo_hw}{}\doxysubsubsection{Hardware setup}\label{group__asmdemo_asmdemo_hw}
The incoming P\+WM pulse train is fed into P\+B4. It will generate a pin change interrupt there on eache edge of the incoming signal.

The outgoing P\+WM is generated through O\+C0B of timer channel 0 (P\+B1). For demonstration purposes, a L\+ED should be connected to that pin (like, one of the L\+E\+Ds of an S\+T\+K500).

The controllers run on their internal calibrated RC oscillators, 1.\+2 M\+Hz on the A\+Ttiny13, and 1.\+0 M\+Hz on the A\+Ttiny45.\hypertarget{group__asmdemo_asmdemo_code}{}\doxysubsubsection{A code walkthrough}\label{group__asmdemo_asmdemo_code}
\hypertarget{group__asmdemo_asmdemo_main}{}\doxyparagraph{asmdemo.\+c}\label{group__asmdemo_asmdemo_main}
After the usual include files, two variables are defined. The first one, {\ttfamily pwm\+\_\+incoming} is used to communicate the most recent pulse width detected by the incoming P\+WM decoder up to the main loop.

The second variable actually only constitutes of a single bit, {\ttfamily intbits.\+pwm\+\_\+received}. This bit will be set whenever the incoming P\+WM decoder has updated {\ttfamily pwm\+\_\+incoming}.

Both variables are marked {\itshape volatile} to ensure their readers will always pick up an updated value, as both variables will be set by interrupt service routines.

The function {\ttfamily ioinit()} initializes the microcontroller peripheral devices. In particular, it starts timer 0 to generate the outgoing P\+WM signal on O\+C0B. Setting O\+C\+R0A to 255 (which is the {\itshape T\+OP} value of timer 0) is used to generate a timer 0 overflow A interrupt on the A\+Ttiny13. This interrupt is used to inform the incoming P\+WM decoder that the counting direction of channel 0 is just changing from up to down. Likewise, an overflow interrupt will be generated whenever the countdown reached {\itshape B\+O\+T\+T\+OM} (value 0), where the counter will again alter its counting direction to upwards. This information is needed in order to know whether the current counter value of {\ttfamily T\+C\+N\+T0} is to be evaluated from bottom or top.

Further, {\ttfamily ioinit()} activates the pin-\/change interrupt {\ttfamily P\+C\+I\+N\+T0} on any edge of P\+B4. Finally, P\+B1 (O\+C0B) will be activated as an output pin, and global interrupts are being enabled.

In the A\+Ttiny45 setup, the C code contains an I\+SR for {\ttfamily P\+C\+I\+N\+T0}. At each pin-\/change interrupt, it will first be analyzed whether the interrupt was caused by a rising or a falling edge. In case of the rising edge, timer 1 will be started with a prescaler of 16 after clearing the current timer value. Then, at the falling edge, the current timer value will be recorded (and timer 1 stopped), the pin-\/change interrupt will be suspended, and the upper layer will be notified that the incoming P\+WM measurement data is available.

Function {\ttfamily main()} first initializes the hardware by calling {\ttfamily ioinit()}, and then waits until some incoming P\+WM value is available. If it is, the output P\+WM will be adjusted by computing the relative value of the incoming P\+WM. Finally, the pin-\/change interrupt is re-\/enabled, and the C\+PU is put to sleep.\hypertarget{group__asmdemo_asmdemo_project}{}\doxyparagraph{project.\+h}\label{group__asmdemo_asmdemo_project}
In order for the interrupt service routines to be as fast as possible, some of the C\+PU registers are set aside completely for use by these routines, so the compiler would not use them for C code. This is arranged for in {\ttfamily \mbox{\hyperlink{project_8h_source}{project.\+h}}}.

The file is divided into one section that will be used by the assembly source code, and another one to be used by C code. The assembly part is distinguished by the preprocessing macro {\ttfamily \+\_\+\+\_\+\+A\+S\+S\+E\+M\+B\+L\+E\+R\+\_\+\+\_\+} (which will be automatically set by the compiler front-\/end when preprocessing an assembly-\/language file), and it contains just macros that give symbolic names to a number of C\+PU registers. The preprocessor will then replace the symbolic names by their right-\/hand side definitions before calling the assembler.

In C code, the compiler needs to see variable declarations for these objects. This is done by using declarations that bind a variable permanently to a C\+PU register (see \mbox{\hyperlink{FAQ_faq_regbind}{How to permanently bind a variable to a register?}}). Even in case the C code never has a need to access these variables, declaring the register binding that way causes the compiler to not use these registers in C code at all.

The {\ttfamily flags} variable needs to be in the range of r16 through r31 as it is the target of a {\itshape load immediate} (or {\ttfamily S\+ER}) instruction that is not applicable to the entire register file.\hypertarget{group__asmdemo_asmdemo_isrs}{}\doxyparagraph{isrs.\+S}\label{group__asmdemo_asmdemo_isrs}
This file is a preprocessed assembly source file. The C preprocessor will be run by the compiler front-\/end first, resolving all {\ttfamily \#include}, {\ttfamily \#define} etc. directives. The resulting program text will then be passed on to the assembler.

As the C preprocessor strips all C-\/style comments, preprocessed assembly source files can have both, C-\/style ({\ttfamily /}{\ttfamily $\ast$ ... $\ast$}{\ttfamily /}, {\ttfamily // ...}) as well as assembly-\/style ({\ttfamily ; ...}) comments.

At the top, the IO register definition file {\ttfamily \mbox{\hyperlink{io_8h}{avr/io.\+h}}} and the project declaration file {\ttfamily \mbox{\hyperlink{project_8h_source}{project.\+h}}} are included. The remainder of the file is conditionally assembled only if the target M\+CU type is an A\+Ttiny13, so it will be completely ignored for the A\+Ttiny45 option.

Next are the two interrupt service routines for timer 0 compare A match (timer 0 hits {\itshape T\+OP}, as O\+C\+R0A is set to 255) and timer 0 overflow (timer 0 hits {\itshape B\+O\+T\+T\+OM}). As discussed above, these are kept as short as possible. They only save {\ttfamily S\+R\+EG} (as the flags will be modified by the {\ttfamily I\+NC} instruction), increment the {\ttfamily counter\+\_\+hi} variable which forms the high part of the current time counter (the low part is formed by querying {\ttfamily T\+C\+N\+T0} directly), and clear or set the variable {\ttfamily flags}, respectively, in order to note the current counting direction. The {\ttfamily R\+E\+TI} instruction terminates these interrupt service routines. Total cycle count is 8 C\+PU cycles, so together with the 4 C\+PU cycles needed for interrupt setup, and the 2 cycles for the R\+J\+MP from the interrupt vector to the handler, these routines will require 14 out of each 256 C\+PU cycles, or about 5 \% of the overall C\+PU time.

The pin-\/change interrupt {\ttfamily P\+C\+I\+N\+T0} will be handled in the final part of this file. The basic algorithm is to quickly evaluate the current system time by fetching the current timer value of {\ttfamily T\+C\+N\+T0}, and combining it with the overflow part in {\ttfamily counter\+\_\+hi}. If the counter is currently counting down rather than up, the value fetched from {\ttfamily T\+C\+N\+T0} must be negated. Finally, if this pin-\/change interrupt was triggered by a rising edge, the time computed will be recorded as the start time only. Then, at the falling edge, this start time will be subracted from the current time to compute the actual pulse width seen (left in {\ttfamily pwm\+\_\+incoming}), and the upper layers are informed of the new value by setting bit 0 in the {\ttfamily intbits} flags. At the same time, this pin-\/change interrupt will be disabled so no new measurement can be performed until the upper layer had a chance to process the current value.\hypertarget{group__asmdemo_asmdemo_src}{}\doxysubsubsection{The source code}\label{group__asmdemo_asmdemo_src}


 
The source code is installed under

\texttt{\$prefix/share/doc/avr-libc/examples/asmdemo/},

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