tag:blogger.com,1999:blog-41460809411783490952024-03-08T02:02:18.619-08:00Pure C ArduinoBlog dedicated to popularize development for Arduino boards in pure Ctomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.comBlogger18125tag:blogger.com,1999:blog-4146080941178349095.post-50937905019561930962014-10-19T13:56:00.007-07:002014-10-19T14:01:08.115-07:00Tic-Tac-Toe on Arduino (MiniMax)<div style="text-align: justify;">
While playing around with Arduino and Nokia LCD Screen I've decided to create some simple game. Obviously there's nothing simpler than tic-tac-toe. The game itself is trivial, everyone knows it so it should be pretty simple to learn the machine to be a good opponent. Yeah... Of, course I could write something really simple, like a translation table, in a sense that if player made a move A, then computer should do a move B... and describe all of the possible situations or "strategies". But that would be pretty primitive and not very appealing, wouldn't it ?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Instead the obvious choice is to implement the MiniMax algorithm for this game. Of course, there a dozens of great articles available describing the basics and fundamentals of MiniMax and especially in tic-tac-toe context so, I'm not going to go into details regarding how it works. Instead I would like you to have a look on any of the links bellow to get at least some essentials:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li><a href="http://beej.us/blog/data/minimax/">http://beej.us/blog/data/minimax/</a></li>
<li><a href="https://chessprogramming.wikispaces.com/Negamax">https://chessprogramming.wikispaces.com/Negamax</a></li>
<li><a href="http://ai-depot.com/articles/minimax-explained/">http://ai-depot.com/articles/minimax-explained/</a></li>
</ul>
<br />
<div style="text-align: justify;">
<div>
Tic-Tac-Toe indeed is a very simple game, even in MiniMax context; in comparison to chess or checkers or any other game alike. However the game tree may become pretty complex anyway. Let's think about it. The first level of the tree will have 9 nodes (since there's 9 possible initial moves), the second will have 9*8 nodes, the third 9*8*7 ... and so on, so already on the third level we will have a total of 9 + 9*8 + 9*8*7 = 585 nodes. OK, assuming that we game tree node is defined the following way:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>struct node_t {</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char *children;</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// it's either 0 - empty, 1 - X, 2 - O, </b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// two bits per field, 9*2 = 18 bits = 3 bytes</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char game[3];</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char children_cnt;</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>};</b></span></div>
<div>
<br /></div>
<div>
Which is 6 bytes per node on Arduino, and on the first level we'll need 8 children, which would give roughly:</div>
<div>
<div>
<br />
<ol>
<li>lvl: 9*6 = 54</li>
<li>lvl: 9*8*6 = 432</li>
<li>lvl: 9*8*7*6 = 3024</li>
</ol>
</div>
<div>
= 3024 bytes of memory only for 3 level deep tree ! That's a little disappointing. Even though, there's still some room for optimization in the tree node definition it's obvious that this approach is a dead end.</div>
</div>
<div>
<br /></div>
<div>
It's still possible to build and analyze the whole game tree even in 2kB of RAM with which Arduino is equipped. The answer is: recursion. In worst case (first move), the function will never recurse deeper than 8 times. This is pretty good it means that even if we would dedicate 1 kB of RAM only for the function to solve the current game state it would give 128 bytes available for local data - which in this case is a lot more than enough. </div>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let's consider the general pseudocode for negamax first (negamax is a version of minimax for symmetrical games - meaning, player's A win is player's B loss):<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int negaMax( int depth ) {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if ( depth == 0 ) return evaluate();</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> int max = -oo;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> for ( all moves ) {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> score = -negaMax( depth - 1 );</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if( score > max )</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span> max = score;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> return max;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span></b><br />
<div>
<br /></div>
<div>
Let's try to put it more in the context of the Tic-Tac-Toe game. For the sake of simplicity first let's operate on the pre-build game-tree:</div>
</div>
<div style="text-align: justify;">
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>struct node {</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>struct node *children[8];</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b> uint8_t _ch_no;</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b> uint8_t grid[3];</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>};</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>int negamax(struct node *game_state, int depth) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b> if (d == MAX_DEPTH) return evaluate();</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b> for (int i = 0; i < game_state->_ch_no; i++) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>score = -1 * negamax(game_state->children[i], depth + 1);</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>if (score > max_score) max_score = score; </b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>}</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>return max_score;</b></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><b>}</b></span><br />
<div>
<br /></div>
<br /></div>
<div style="text-align: justify;">
That's a simplified version, but well describing the intention. We iterate through all children of the current game state as player A looking for the worst move of player B. We know though, that having the full game tree pre-built is a luxury. Instead we must build each game state we want to analyse iteratively in order to consider it, let's look on the modified code:</div>
<div>
<br /></div>
<div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">int negamax(int *grid, int depth) {</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (d == MAX_DEPTH) return evaluate();</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>for (int i = 0; i < GRID_SIZE; i++) {</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// looking for an empty field in the grid</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (grid[i] != EMPTY) continue;</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>grid[i] = MARK_X;</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>score = -1 * negamax(grid, depth + 1);</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>grid[i] = EMPTY;</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (score > max_score) max_score = score;</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>return max_score;</span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span></b></div>
</div>
<div>
<br /></div>
<div>
<div>
That's pretty simple. Instead of having a pre-built list of nodes we simply create every node on the fly and analyse it, after that the game grid is restored to it's original state. That's the essence. This will be slightly slower than having the tree but it will work and it's good enough.</div>
</div>
<div>
<div>
<br /></div>
<div>
<div style="text-align: justify;">
The key to a good playing program is the evaluation function. That function takes the current game state and should return how likely it is for the current player to win. If your program is doing simple mistakes or looses in "obvious win" situation the evaluation function is to blame. There are many approaches, to count the potentially winning rows and columns, count empty columns etc. It all comes down to exploring all the different possibilities. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
It took me a while to test all the different approaches and decide on the evaluation function. Finally I've decided to describe each game using a score between -100..100. A game which is a loss gets a score of -100, a game which is a win gets 100 points. What about all the values in between ? I'm using them to score a non-terminal game state. I'm counting all the rows, columns and diagonals on the board which do not contain the opponent's marking - meaning they can be potential wins. I'm doing the same for the opponent. After that I have two numbers: A- potential winning rows,cols and diags for player A and B - potential winning rows,cols & diags for player B. The game is scored by substracting those two numbers. Let's consider the following examples:</div>
<div style="text-align: justify;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-Jql_qUMVMf4/VEQZnnVvDaI/AAAAAAAABCg/9Aj8b04BLNI/s1600/game_evaluation.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-Jql_qUMVMf4/VEQZnnVvDaI/AAAAAAAABCg/9Aj8b04BLNI/s1600/game_evaluation.png" height="167" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Game Evaluation example.</td></tr>
</tbody></table>
<div style="text-align: justify;">
The values will vary within range [-8..8] which isn't much in comparison to the win/loss score, it's enough though to take a reasonable game decisions (well... in most cases :)). </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
It's time to consider the full code.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<script src="https://gist.github.com/dagon666/aafa2dce24166faebe1f.js"></script>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
This code is machine independent and can be compiled and executed on a standard x86 as well. Let's try that first. Since I was kinda lazy about the interface and my goal was to implement the MiniMax algorithm, the interface is clunky - but usable. In order to play type a number 0 - 8 in order to mark the field on the game grid. Human player starts first and uses the X mark. Let's play a game:<br />
<br />
$ make<br />
$ ./ttt</div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>- - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>4</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- X -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>CPU</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> - X -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> - - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>2</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O - X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- X -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>- - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>CPU</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O - X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> - X -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>3</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O - X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>X X -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>CPU</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O - X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> X X O</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>1</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O X X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>X X O</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O - -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>CPU</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O X X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> X X O</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O O -</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>8</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O X X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>X X O</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>O O X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>CPU</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O X X</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> X X O</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> O O X</b></span><br />
<div>
<br /></div>
Not bad. I must say that it plays pretty good in most of the cases. Try it out yourself. Putting this code onto an Arduino shouldn't be a problem now. The execution speed comparison may be interesting as well. As far as on a pretty old Core 2 Duo laptop there was no delay visible, I'm sure that little Atmega will require some time (at least in the beginning) to determine the best move.</div>
<div style="text-align: justify;">
<br />
Let's prepare the project. Clone the following repository<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>$ git clone git@github.com:dagon666/dev_MiniMax.git</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>$ cd dev_MiniMax</b></span><br />
<br />
We need libpca as well:<br />
<b><span style="font-family: Courier New, Courier, monospace;">$ git clone git@github.com:dagon666/avr_Libpca pca</span></b><br />
<br />
Now, we can build it:<br />
<br />
$ cd arduino<br />
$ make<br />
$ make install<br />
<br />
As expected, since initially the tree of possible games to explore is quite bit it takes around 2 - 3 seconds for the Arduino to find the first move. The game set is much smaller afterwards - there seems to be no delays in second and further moves.<br />
<br />
Just for fun (since I had it already connected) I decided to run the game on the Nokia LCD as well (there is an option in the code to do that - just change the LCD_OUTPUT to 1 in main.c). Here's how the game looks on the LCD:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-U0Q8Lf8Bu70/U9_h0BQiNbI/AAAAAAAAA-0/lk1F0QBpcE0/s1600/20140804_202415.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-U0Q8Lf8Bu70/U9_h0BQiNbI/AAAAAAAAA-0/lk1F0QBpcE0/s1600/20140804_202415.jpg" height="400" width="225" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-42MIO9kjUio/U9_hx4FC7TI/AAAAAAAAA-w/L3JYBXiv3bM/s1600/20140804_202503.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-42MIO9kjUio/U9_hx4FC7TI/AAAAAAAAA-w/L3JYBXiv3bM/s1600/20140804_202503.jpg" height="400" width="225" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-ApgRl2BS-g0/U9_hzTeL76I/AAAAAAAAA8k/2ODwqwAL4bI/s1600/20140804_202529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-ApgRl2BS-g0/U9_hzTeL76I/AAAAAAAAA8k/2ODwqwAL4bI/s1600/20140804_202529.jpg" height="400" width="225" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-_EPI-hO0-XU/U9_iDggTt0I/AAAAAAAAA80/Y09n7gs4-4E/s1600/20140804_202547.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-_EPI-hO0-XU/U9_iDggTt0I/AAAAAAAAA80/Y09n7gs4-4E/s1600/20140804_202547.jpg" height="400" width="225" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-XEcdh0tEWoc/U9_iFol-_PI/AAAAAAAAA88/0zDW1Giq7TY/s1600/20140804_202603.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-XEcdh0tEWoc/U9_iFol-_PI/AAAAAAAAA88/0zDW1Giq7TY/s1600/20140804_202603.jpg" height="400" width="225" /></a></div>
<br />
<br />
I hope that this post was useful and educating. Have fun programming!</div>
</div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-85387467493630937782014-07-20T14:40:00.001-07:002014-10-19T14:01:00.320-07:00Nokia 3310 scope experiments part 1<div style="text-align: justify;">
Continuing with the nokia 3310 display experiments, I wanted to try out if visualizing signals with this display could be any useful. For that purpose I wanted to build a simple scope with Arduino. I simply configured the ADC, used the internal 1.1 V reference voltage, configured the analog comparator as a trigger and tried to visualize the incoming samples. All of this has been done using the libpca and the following simple sketch. </div>
<div style="text-align: justify;">
<br />
<br />
<script src="https://gist.github.com/dagon666/4d7b8291f9fa58dc0bd0.js"></script>
<br /></div>
<div style="text-align: justify;">
So far, with enough accuracy I did some experiments with signals up to 8 kHz. I don't want to go into details at the moment especially that I consider this project as a work in progress. The ADC has been fed with a sine signal generated using Audacity. The quality of the measurement strictly depends on the ADC frequency. A couple of pictures bellow:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-dMbkWrAagbs/U8w0K_XEzDI/AAAAAAAAA34/c2b9tN_LogY/s1600/IMG_2669_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-dMbkWrAagbs/U8w0K_XEzDI/AAAAAAAAA34/c2b9tN_LogY/s1600/IMG_2669_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">1kHz, sampled with prescaler = 4</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-75DwlkKLewI/U8w0bpYwvCI/AAAAAAAAA4E/9Ox3jDy0-gU/s1600/IMG_2672_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-75DwlkKLewI/U8w0bpYwvCI/AAAAAAAAA4E/9Ox3jDy0-gU/s1600/IMG_2672_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">2 kHz, prescaler = 4, visible trigger jitter</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-UsE08YqhcyE/U8w0cc1PwOI/AAAAAAAAA4Q/lvi7Xb-CXRc/s1600/IMG_2673_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-UsE08YqhcyE/U8w0cc1PwOI/AAAAAAAAA4Q/lvi7Xb-CXRc/s1600/IMG_2673_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">... same signal, bigger amplitude</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-wZKta5Pbae4/U8w0tGTvJEI/AAAAAAAAA4o/ARbv2Ep_UKk/s1600/IMG_2676_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-wZKta5Pbae4/U8w0tGTvJEI/AAAAAAAAA4o/ARbv2Ep_UKk/s1600/IMG_2676_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">4 kHz, prescaler = 4</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-4YPb7B6MhjQ/U8w09QbPf-I/AAAAAAAAA5E/Ilzhy7GxmYY/s1600/IMG_2678_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-4YPb7B6MhjQ/U8w09QbPf-I/AAAAAAAAA5E/Ilzhy7GxmYY/s1600/IMG_2678_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">6 kHz, prescaler = 4, very distorted</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-TGm7ZXuSNl0/U8w1PiE4VoI/AAAAAAAAA5U/zDonnWfwsOk/s1600/IMG_2681_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-TGm7ZXuSNl0/U8w1PiE4VoI/AAAAAAAAA5U/zDonnWfwsOk/s1600/IMG_2681_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">800 Hz, prescaler = 4, visible distortions</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-XnCT22JBbiI/U8w1QS822dI/AAAAAAAAA5c/RJ6qiQygaXQ/s1600/IMG_2682_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-XnCT22JBbiI/U8w1QS822dI/AAAAAAAAA5c/RJ6qiQygaXQ/s1600/IMG_2682_01.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">800 Hz, prescaler = 32, a lot better quality</td></tr>
</tbody></table>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-62410925411839199452014-05-11T11:52:00.004-07:002014-05-11T11:52:59.602-07:00Nokia 3310 display fun<div style="text-align: justify;">
Recently I wrote a driver for a nokia 3310 (pcd8544 based) lcd display which I had lying around.Again, I decided to create my own driver just to learn something about it and to see how much effort it will require - turned out that this driver is pretty easy to handle. Despite the fact that it's suggested to use 3V3 logic (maximum accepted voltage accordingly to the datasheet it's 7V), it works great with arduino powered with 5V and using 5V logic outputs.</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Adafruit's Library</h3>
<div style="text-align: justify;">
I had a look on Adafruit's library for that display just as a reference (<a href="https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library" target="_blank">github</a>) and it seems very primitive to be honest - it allocates a huge display buffer without asking the user whether it is really needed (it consumes more than 25% of available RAM on Arduino) and what's even worse it uses bit banged SPI to communicate with the display. Why ? Why bother when there is fast & reliable hardware bus available on that MCU (and of course like all Arduino IDE libraries it's written in C++ which makes things even more slower). And it doesn't come with any font, so in fact the user must take care about it himself. Not being very humble - the implementation in libpca is far more superior.</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Hello World</h3>
<div style="text-align: justify;">
Just to test the driver & the display - let's first play around with a code template and generate some easy graphics (and of course mandatory for every project - "Hello World" program)<br />
<br />
<br /></div>
<script src="https://gist.github.com/dagon666/44babadb8e3710e6ec4f.js"></script>
<br />
<div style="text-align: justify;">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-iEdSx6Dv_OY/U2-7d9OW3HI/AAAAAAAAA0c/VCU9rTBpZ68/s1600/IMG_2611.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-iEdSx6Dv_OY/U2-7d9OW3HI/AAAAAAAAA0c/VCU9rTBpZ68/s1600/IMG_2611.JPG" height="266" width="400" /></a></div>
<br />
Simple, isn't it ? This code in a couple of lines initializes the SPI bus in the simplest manner, initializes the display itself, installs it as an STDOUT output and prints the "Hello World" string. That's fancy, plain and simple, no unnecesary C++ mumbo jumbo (don't get me wrong I love C++, but the way it is used in the Arduino libraries - it's a joke really). This is how it looks on the display:<br />
<br />
I'll use that code as a template and will enhance it further on to generate some other effects. I'll be simply replacing the "Hello World" printf line with some other code.<br />
<br />
Let's start with something simple - checker board. Each byte in the display represents 8 rows, 48 rows are distributed amongst 6 bytes. The memory organization of the display looks the following way:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-bu6LgFqrTWs/U2-apj4svsI/AAAAAAAAA0M/xKppNbXtJt0/s1600/pcd8544_memorg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-bu6LgFqrTWs/U2-apj4svsI/AAAAAAAAA0M/xKppNbXtJt0/s1600/pcd8544_memorg.png" height="157" width="400" /></a></div>
<br />
Which means that if we'll fill the display with a pattern of 0b10101010 (0xaa) - we'll get something like a very high grained stripes. Let's test that. Replacing the 37th line (<span class="n">printf</span><span class="p">(</span><span class="s">"Hello world !!!"</span><span class="p">);) line with the following code:</span><br />
<br />
<span class="p"><span style="font-family: "Courier New",Courier,monospace;">pcd8544_fill(&lcd, 0xaa);</span> </span><br />
<span class="p"><br /></span>
<span class="p">You'll get:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-3ZOt9RtLLa8/U2-8Kytz-QI/AAAAAAAAA0k/VVQHX9tNqj0/s1600/IMG_2618.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-3ZOt9RtLLa8/U2-8Kytz-QI/AAAAAAAAA0k/VVQHX9tNqj0/s1600/IMG_2618.JPG" height="266" width="400" /></a></div>
<br />
<span class="p"></span>
<span class="p">Ok, let's do something fancier. There's an old trick which I love to use (back from the dos 7.0 world and the famous software interrupt 13 which brought you into the 320x240 graphics mode) - generating the Sierpinski's triangle with just logical AND operation. Let's replace the line 37th again with the following code:</span><br />
<br />
<script src="https://gist.github.com/dagon666/eed1dd0b936a92830927.js"></script>
<span class="p"><br /></span>The result:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-XwxgyXfa-8I/U2-8qpJ324I/AAAAAAAAA00/DP8f0Z2sGjI/s1600/IMG_2626.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-XwxgyXfa-8I/U2-8qpJ324I/AAAAAAAAA00/DP8f0Z2sGjI/s1600/IMG_2626.JPG" height="266" width="400" /></a></div>
<br />
<br />
<span class="p">Yeah, that's nice, but we can still do better without much effort. Each pixel on the display can be either turned on or off - it's a 1-bit color depth. In other words it's physically impossible to display any shade of grey. But this is not a problem really - that limitation has been overcome long time ago with dithering alghorithms - we could implement simple error diffusion dithering or floyd-steinberg dithering to get awesome effects - but that would require some more effort than I really want to spend at the moment. Let's focus on an ordered dithering using an 8x8 Bayer lookup table - thanks to that method we'll be able to effectively simulate a 6-bit color depth (0 - 63) on a 1-bit color depth capable hardware and guess what - yes libpca implements that method for your convenience as well all you have to do is simply use it.</span><br />
<br />
<span class="p">I recommend having a look on those articles if you are really interested in dithering - it's a lot of fun.</span><br />
<br />
<ul>
<li><span class="p"><a href="http://www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/">www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/</a> </span></li>
</ul>
<ul>
<li><span class="p"><a href="http://en.literateprograms.org/Floyd-Steinberg_dithering_%28C%29">http://en.literateprograms.org/Floyd-Steinberg_dithering_%28C%29</a></span></li>
</ul>
<ul>
<li><span class="p"><a href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT">http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT</a> </span></li>
</ul>
<br />
<span class="p">First, let's generate a gradient. This will be the code:</span><br />
<br />
<script src="https://gist.github.com/dagon666/88b9ab35784ab1ba6117.js"></script>
<span class="p">And the effect:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-Nf4gm5yVQBc/U2-9FknXd8I/AAAAAAAAA08/7ABK9GBEm58/s1600/IMG_2628.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-Nf4gm5yVQBc/U2-9FknXd8I/AAAAAAAAA08/7ABK9GBEm58/s1600/IMG_2628.JPG" height="266" width="400" /></a></div>
<br />
<br />
<span class="p">Ok. That's pretty nice. We can tell how this method works - it generates different patterns (with different intensity) in order to simulate a particular shade - it's not as good as floyd-steinberg but good enough and what's most important - fast enough.</span><br />
<br />
<span class="p">Let's see if good old atmega is fast enough to generate another old-school graphics effect - famous <a href="http://en.wikipedia.org/wiki/Plasma_effect" target="_blank">plasma effect</a> This will be a challenging task for small Atmega - this effect heavilly depends on the sinus function and sqrt, power of two functions - everything of which our CPU is not very good at. Let's try anyway. </span><br />
<br />
<span class="p">The general alghorithm for the basic plasma effect is:</span><br />
<span class="p"><br /></span>
<span class="p" style="font-family: Courier New, Courier, monospace;">for every x</span><br />
<span class="p" style="font-family: Courier New, Courier, monospace;">for every y</span><br />
<span class="p" style="font-family: Courier New, Courier, monospace;">color = sin( sqrt(x*x + y*y) );</span><br />
<span class="p" style="font-family: Courier New, Courier, monospace;">putpixel (x,y,color); </span><br />
<span class="p"><br /></span>
<span class="p">Surprisingly previously I was using a "buffer" variable as a display buffer, but for the plasma effect it's not really needed. First thing which I've done was generating the sin function lookup table:</span><br />
<br />
<span class="p"><span style="font-family: Courier New, Courier, monospace;"> for (uint16_t i = 0; i < 256; i++) {<br /> sin_table[i] = (cos(i/2)*sin(i))*31 + 32;<br /> }</span><br /><br />In order to avoid two loops, one which generates the image in the buffer and the other one which copies the data to the display I'm trying to do everything in one loop (just to make it quicker). The complete code looks the following way:</span><br />
<span class="p"><br /></span>
<script src="https://gist.github.com/dagon666/1b80851a0ff1ad10d0c6.js"></script>
<br />
What I'm trying to achieve is to generate a byte of image (vertical) and copy it to the display, so in fact I'm using a single byte as a processing buffer. I'm using the ordered dithering function the same way as previously. This code on my Arduino is able to generate the plasma effect with something around 2, 3 frames per second. Have a look:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-M-eaNbBfTtQ/U2-_qDtU_pI/AAAAAAAAA1I/XQod_otjY3A/s1600/IMG_2630.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-M-eaNbBfTtQ/U2-_qDtU_pI/AAAAAAAAA1I/XQod_otjY3A/s1600/IMG_2630.JPG" height="266" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/Krf6vsO0MiM?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
The code is available on github. You need libpca:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">git clone git@github.com:dagon666/avr_Libpca pca</span><br />
<br />
and the my avr projects repository:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">git clone git@github.com:dagon666/avr_ArduinoProjects projects</span><br />
<br />
In the projects directory you'll find a directory called nokia_spi.<br />
<br />
A snapshot is available also <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/nokia_spi.tgz" target="_blank">here</a>.<br />
<span class="p"> </span>
<span class="p"><br /></span>
<br />
<br />
<br /></div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com1tag:blogger.com,1999:blog-4146080941178349095.post-66808727178183574942014-05-08T14:07:00.001-07:002014-05-08T14:07:28.038-07:00A(rduino) OS - Simple pre-emptive Arduino Scheduler<div style="text-align: justify;">
A(rduino)OS (AOS) is an attempt to write a simple pre-emptive scheduler - mostly to learn about how such system works but it's a fully functional implementation which can be used in a practical way good as well. First of all, if you have no theoretical background about context switching I would recommend to have a look on a great description regarding schedulers published by avrfreaks:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<a href="http://www.avrfreaks.net/index.php?module=FreaksArticles&func=downloadArticle&id=14" target="_blank">Multitasking on an AVR</a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
AOS depends on libpca - it uses some routines from it in order to avoid code duplication. It is completely written in C from scratch with a little of assembler (in order to realize context switching). It comes with a documentation and some examples as well, which is hosted along with the repository on github:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<a href="http://dagon666.github.io/avr_Aos/" target="_blank">AOS Doxygen documentation</a></div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Overview</h3>
<div style="text-align: justify;">
Most of the pre-emptive schedulers (besides cooperative schedulers) is implements and is driven around a "tick" - an interrupt which happens periodically with a programmed frequency and which is responsible for context switching. In other words, assuming that there are two tasks in the system: <i>taskA</i> and <i>taskB</i> and <i>taskA</i> is currently running, once the tick interrupt happens it will check how much time <i>taskA</i> has already consumed and will switch to <i>taskB</i> if <i>taskA</i> has used all of it's assigned slot.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Context switch reprograms most of the CPU registers and re-positions the stack pointer - which means that every individual task has it's own memory area dedicated for the stack.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I strongly encourage you to give it a try. The doxygen documentation contains a description on how to prepare the project and use the system. In the near future I'm going to try to provide some more practical examples of using this scheduler.</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-27180218132356298682014-01-27T14:09:00.004-08:002014-01-27T14:09:57.070-08:00Standalone Project: Multi functional ClockI would like to share my project with you. It's an RTC clock with thermometer powered by atmega328p.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-NWzFrU_g-VI/UsBqquR9GhI/AAAAAAAAAf4/DOxIARB9NgM/s1600/display_time.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-NWzFrU_g-VI/UsBqquR9GhI/AAAAAAAAAf4/DOxIARB9NgM/s1600/display_time.jpg" height="255" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Clock, displaying current time, date & day of week.</td></tr>
</tbody></table>
It took me a while to finish this project since I wanted to polish the software. I wanted to implement a couple of features which will make my clock more interesting than any other similar device like that build before. I'll try to go through all the details now so, if you find this project interesting you can build it yourself (everything. including the software, is available for free).<br />
<br />
<h3>
Hardware </h3>
<div style="text-align: justify;">
The hardware itself is pretty simple. I used a ds18b20 digital One-Wire temperature sensor as a thermometer, a DS1307 RTC module which comes with a battery and a classic hd44780 LCD 16x2 display. Everything is pretty generic in that matter. There's a diode as well used to indicate that the clock is running and a couple of buttons. Besides that I use a couple of transistors in order to be able to control the LCD's brightness and contrast through software, using PWM timer. This is the schematics:</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-k9uUKsEzSWQ/UsCNTzMJ6YI/AAAAAAAAAiY/i3LUdDMQgqU/s1600/clock_schematics.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-k9uUKsEzSWQ/UsCNTzMJ6YI/AAAAAAAAAiY/i3LUdDMQgqU/s1600/clock_schematics.png" height="400" width="361" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Clock schematics</td></tr>
</tbody></table>
<br />
<br />
I've taken some pictures during the building:<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-VPRZokqnPjc/UsByXxu-NtI/AAAAAAAAAgI/GSckm9ip6Qw/s1600/wip.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-VPRZokqnPjc/UsByXxu-NtI/AAAAAAAAAgI/GSckm9ip6Qw/s1600/wip.jpg" height="248" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">All elements populated, making the connections on the perf board.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-Q-SqPogNbwc/UsBy4nPedOI/AAAAAAAAAgU/BQpE0VHWgs0/s1600/cutting_tracks.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-Q-SqPogNbwc/UsBy4nPedOI/AAAAAAAAAgU/BQpE0VHWgs0/s1600/cutting_tracks.jpg" height="278" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Cutting the connections on the universal board.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-eU3_lqljfYY/UsBzYFDwjrI/AAAAAAAAAgY/xUYp34izPqQ/s1600/side.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-eU3_lqljfYY/UsBzYFDwjrI/AAAAAAAAAgY/xUYp34izPqQ/s1600/side.jpg" height="281" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">View from the side.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-ZduOcNais8o/UsBzz6rGJKI/AAAAAAAAAgg/hpwLVgU1txE/s1600/backside.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-ZduOcNais8o/UsBzz6rGJKI/AAAAAAAAAgg/hpwLVgU1txE/s1600/backside.jpg" height="280" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Making the connections.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-aQ5YmnKKdfI/UsB0IR8b1-I/AAAAAAAAAgo/TTKc-Gvk6Ns/s1600/completed.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-aQ5YmnKKdfI/UsB0IR8b1-I/AAAAAAAAAgo/TTKc-Gvk6Ns/s1600/completed.jpg" height="296" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Completed device.</td></tr>
</tbody></table>
<br />
<h3>
Software</h3>
<div>
As usual, the software is written purely in C - WITHOUT any 3rd party libraries. The code is 100 % mine - that includes the I2C driver, LCD driver, Software One Wire driver - all available in the libpca library. The software itself is pretty complicated as for a project like this it contains two state machines; the main one and the temperature measurement dedicated, handles two interrupt sources (INT0 from RTC, as well as Timer overflow interrupt) a fully independent menu system which can be used in any other project and some other additional routines.</div>
<div>
<br /></div>
<div>
<b>Features:</b></div>
<div>
<ul>
<li>Event driven state machine - buttons, interrupts, FSM itself, generate events</li>
<li>PWM controlled LCD backlight brightness</li>
<li>PWM controlled LCD contrast</li>
<li>LCD backlight fade-in/fade-out on keypress (handled in interrupt)</li>
<li>Multiple information screens (scrolling from one to another)</li>
<li>Independent scrolling strings</li>
<li>Animated transitions between the "screens"</li>
<li>The clock maintains all the data like current time and temperature measurements (maximum temperature / minimum temperature) without the external power (stored in RTC)</li>
<li>Displays a proverbs for every day of year</li>
<li>Displays a unique nameday for every day of year</li>
<li>Software "integration" key de-bouncing algorithm</li>
</ul>
<div>
<div style="text-align: justify;">
The software is 31 kB is size - it takes almost whole available FLASH space. The code itself is somewhere around 15 kB, but since I wanted to display an occasional proverbs and name-days information those additional assets consume the remaining space (it's quite a lot considering the fact that you need at least one (let's say 16 bytes long only) for every day of the year 16 * 365 ~ 6 kB !!!.<br />
<br /></div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-1EjedYAB8I4/UuPFaxPI6YI/AAAAAAAAAlI/kio4kzk9hAM/s1600/soft_schema.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-1EjedYAB8I4/UuPFaxPI6YI/AAAAAAAAAlI/kio4kzk9hAM/s1600/soft_schema.png" height="400" width="352" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Software Functional Block Diagram.</td></tr>
</tbody></table>
<br />
<div style="text-align: justify;">
Although the software may look over complicated it is acutally very simple. Let's talk about the interrupts first. I use the RTC's square wave output as an external interrupt (INT0) source. Thanks to that I don't have to constantly poll the RTC in order to update the time - since it will only change once every second. The rest of the time I can use the CPU for any different task. This 1 Hz interrupt is crutial to the system. It generates 1 Hz event in order to update the time, decrements the internal timers - so for example I can program a variable to a value and I know it will be decremented with every second - this can be used to generate timeouts and I use it to generate screen timeouts. For example, once the finite state machine enters Time Display mode the timer is programmed to i.e. 30 seconds - this timer is decremented in the 1 Hz interrupt handler. Once zero a TIMEOUT event will be generate which will force the FSM to transite into another screen (like temperature display or any other). It is used as well to control the backlight on time. If the backlight time is configured to a fixed value (like 30 seconds) the backlight timer is decremented in the 1 Hz interrupt handler if there is no keypress. The 1 Hz interrupt triggers the temperature measurement as well.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Temperature measurement</h3>
<div style="text-align: justify;">
Temperature measurement is kind of tricky, since in order to get the results I need to wait for around 800 ms in for the sensors to finish the conversion. There were two solutions really - do it with every second - it will synchronous with the clock or do it asynchronously - I wanted to try the second one. This method is slightly more complicated and requires the second Timer interrupt to come into play. In order to synchronize two interrupts and a main loop a small finite state machine dedicated to temperature measurement had to be created. Bellow diagram depicts the process of triggering the temperature sensor and obtaining the results.</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-HjJBkJXJyhw/UuPMz9h0GkI/AAAAAAAAAlY/wturJt5cUmA/s1600/tmp_msr.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-HjJBkJXJyhw/UuPMz9h0GkI/AAAAAAAAAlY/wturJt5cUmA/s1600/tmp_msr.png" height="333" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Temperature measurement.</td></tr>
</tbody></table>
<h3>
Timer interrupt & Screen Transition</h3>
The timer interrupt is needed for other purposes. I use to for transitions between screens and for dimming in/out the backlight of the screen (change the PWM duty cycle from/to programmed one from/to zero).<br />
<br />
In order to realize the transitions between screens I use a nice property of the hd44780 display. Although it is 16x2 characters it has a lot more DISPLAY RAM it is actually 2 x 40 characters. What I do is during the transition generate the content of for example time display screen to the display RAM at zeroth character and generate the second screen at character 17th (currently outside of the display frame), during the transition I simply move the display frame from 0 to 17 changing the screen content in result<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-c-HIate94l8/UuPZrzCD-qI/AAAAAAAAAlo/cKRb6gte6U0/s1600/transition.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-c-HIate94l8/UuPZrzCD-qI/AAAAAAAAAlo/cKRb6gte6U0/s1600/transition.png" height="223" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Screen Transition</td></tr>
</tbody></table>
<h3>
Menu system</h3>
Menu system has been implemented as a separate module. With a small adjustments it's possible to use it in any different project. The menu definition looks the following way:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">struct menu_item {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>const char *name;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// 1 - inactive/active</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// 0 - cb/submenu</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>uint8_t config;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>union {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>menu_callback_t cb;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>struct menu *submenu;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>} ptr;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">};</span></b><br />
<div>
<br /></div>
<div>
Each item has a name, and respective callback pointer called once the item has been selected. The menu definition for the clock looks the following way:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>static struct menu_item items[] = {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Set Time", MENU_ITEM_OWNER, { menu_set_time } }, </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Set Date", MENU_ITEM_OWNER, { menu_set_date } }, </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Time Mode",MENU_ITEM_DEFAULT, { menu_set_time_mode } }, </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "LCD Brightness", MENU_ITEM_DEFAULT, { menu_set_lcd_brightness } }, </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "LCD Contrast", MENU_ITEM_DEFAULT, { menu_set_lcd_contrast } },</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "LCD Backlight Time", MENU_ITEM_DEFAULT, { menu_set_lcd_backlight } }, </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Reset temperature", MENU_ITEM_DEFAULT, { menu_reset_temperature } },</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Temperature Display Time", MENU_ITEM_DEFAULT, { menu_set_temp_disp_time } },</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Time Display Time", MENU_ITEM_DEFAULT, { menu_set_time_disp_time } },</b></span></div>
<div>
<b style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span></b><b style="font-family: 'Courier New', Courier, monospace;">{ "Nameday Display Time", MENU_ITEM_DEFAULT, { menu_set_nameday_disp_time } },</b></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Words Of Wisdom Display Time", MENU_ITEM_DEFAULT, { menu_set_wow_disp_time } },</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "Save Settings to EEPROM", MENU_ITEM_DEFAULT, { menu_save_settings } }</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>};</b></span></div>
</div>
<div>
<br /></div>
<div>
Of course if any string is longer than the the display line, the string will be scrolled. The implementation for that is generic and modular as well so can be taken straight away.</div>
<h3>
Overview</h3>
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-Ann39DXpHTY/UsB-JkyiHeI/AAAAAAAAAhA/fu2i0vmaY04/s1600/display_nameday.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-Ann39DXpHTY/UsB-JkyiHeI/AAAAAAAAAhA/fu2i0vmaY04/s1600/display_nameday.jpg" height="240" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Clock displaying nameday.</td></tr>
</tbody></table>
<br />
Picture bellow shows the transition in progress, from the Time Screen to the Settings Menu. It also depicts how long does it take to switch a character in this LCD, since the new character is overlaying on the remnants of the old one.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-dVzXtMUZXmo/UsB-inovljI/AAAAAAAAAhI/YYTyB0CHYAg/s1600/clk_transition.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-dVzXtMUZXmo/UsB-inovljI/AAAAAAAAAhI/YYTyB0CHYAg/s1600/clk_transition.jpg" height="267" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Transition from Menu Screen to Time Screen</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-jKolqgwgk8w/UsB-jJStscI/AAAAAAAAAhY/5f7z7dDCyJQ/s1600/display_menu_01.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-jKolqgwgk8w/UsB-jJStscI/AAAAAAAAAhY/5f7z7dDCyJQ/s1600/display_menu_01.jpg" height="262" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Menu Screen</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-6Stvz2Q7wAM/UsB-uuNhOKI/AAAAAAAAAhg/97efzTCzsug/s1600/display_menu_02.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-6Stvz2Q7wAM/UsB-uuNhOKI/AAAAAAAAAhg/97efzTCzsug/s1600/display_menu_02.jpg" height="263" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">More options in the Menu Screen</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-3-0N3WJpBbo/UsB-vClN7ZI/AAAAAAAAAhk/PoMjjgaq0Tw/s1600/display_menu_03.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-3-0N3WJpBbo/UsB-vClN7ZI/AAAAAAAAAhk/PoMjjgaq0Tw/s1600/display_menu_03.jpg" height="271" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Long Option name is being scrolled in the menu screen.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-Y4QIZpwafuQ/UsB-vMTLfxI/AAAAAAAAAho/dgr7-IQnXr4/s1600/transition2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-Y4QIZpwafuQ/UsB-vMTLfxI/AAAAAAAAAho/dgr7-IQnXr4/s1600/transition2.jpg" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Transition in progress.</td></tr>
</tbody></table>
<br />
Simple progress bar implemented for the menu.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-OOQXJFYImwI/UsB-iyd5nRI/AAAAAAAAAhM/WdQFPiveC5g/s1600/brightness.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-OOQXJFYImwI/UsB-iyd5nRI/AAAAAAAAAhM/WdQFPiveC5g/s1600/brightness.jpg" height="262" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Brightness regulation.</td></tr>
</tbody></table>
<br />
Video demonstration:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/duFpNzlXzls?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
As usual, the source code as well as all the documentation is available on my github account:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_ArduinoProjects projects</b></span><br />
<br />
Look for subdirectory <span style="font-family: Courier New, Courier, monospace;">projects/clk</span>.</div>
</div>
<br />tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com1tag:blogger.com,1999:blog-4146080941178349095.post-78865642265486692122014-01-01T07:46:00.004-08:002014-01-01T07:47:54.618-08:00Simple Serial Port Command Line Interface (CLI)<div style="text-align: justify;">
It's often very useful to have some sort of interface through which a basic management can be done of our application. Whether you're designing a giant Marquee with a <span style="font-family: Courier New, Courier, monospace;">LED</span> display or a plotter or you simply need to get some diagnostics from your device occasionally, a simple <span style="font-family: Courier New, Courier, monospace;">CLI</span> system can come very handy. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Of course, designing something similar to "bash" or any other unix shell is completely out of scope since those applications are huge and are simply an overkill for our needs. It's pretty simple though to create some basic, yet flexible & easilly extensible <span style="font-family: Courier New, Courier, monospace;">CLI</span> system.<br />
<br />
First thing needed is a command type definition. This will bind a keyword with an actual underlying routine executed for that keyword typed in the <span style="font-family: Courier New, Courier, monospace;">CLI</span>.<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>typedef struct _t_cmd {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>const char *cmd;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>void (*fh)(void*);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>} t_cmd;</b></span><br />
<br />
<br />
The command type is pretty simple. There's the <span style="font-family: Courier New, Courier, monospace;">CLI</span> command/keyword pointer, it holds a pointer to the execution function and that's it.<br />
<br />
OK, so far so good. Now we need to define a set of commands since a single command <span style="font-family: Courier New, Courier, monospace;">CLI</span> isn't much useful. Let's create a <span style="font-family: Courier New, Courier, monospace;">CLI</span> context type for that which will hold entire <span style="font-family: Courier New, Courier, monospace;">CLI</span> state - this has two advantages, first - it aggregates all the data in one place, second - if we'll write our functions to depend only on the context (which I'm going to do), then it will be possible to declare a couple of independent <span style="font-family: Courier New, Courier, monospace;">CLIs</span> on different interfaces for example running concurrently.<br />
<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">typedef struct _t_cli_ctx {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// command set</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>t_cmd *cmds;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// cmd</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>char cmd[CLI_CMD_BUFFER_SIZE];</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char cpos;</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">} t_cli_ctx;</span></b><br />
<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
OK, the context is pretty simple. It contains the command set pointer and current command buffer "<span style="font-family: Courier New, Courier, monospace;">cmd</span>" - this buffer will hold everything you type before hitting ENTER and interpreting the command. It contains current cursor position as well. Once again, at the moment the context is pretty simple - but it will be enhanced later on to implement some more features.<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>static t_cmd g_cmds[] = {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "hw", fh_hello },</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "hi", fh_hi }</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// null</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ {0x00}, 0x00, 0x00 }</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>};</b></span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<br />
Let's prepare an initialization function for the <span style="font-family: Courier New, Courier, monospace;">CLI</span> context definition in order to prepare it for execution.<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>void cli_init(t_cli_ctx *a_ctx, t_cmd *a_cmds) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>memset(a_ctx, 0x00, sizeof(t_cli_ctx));</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>a_ctx->cmds = a_cmds;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span><br />
<br />
<br />
Believe it or not but more or less that's it. We can now declare some commands and proceed with the implementation of the <span style="font-family: Courier New, Courier, monospace;">CLI</span> interpreter. We haven't yet used or done anything hardware specific so, the code can be compiled on a usual x86 machine for tests. The only platform specific code will be <span style="font-family: Courier New, Courier, monospace;">IO</span> related. We need to create it now in order to proceed. For the <span style="font-family: Courier New, Courier, monospace;">AVR</span> it will be quite simple. Our <span style="font-family: Courier New, Courier, monospace;">CLI</span> system needs to be fed one key at a time. We can use a function from libpca:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>unsigned char serial_getc(unsigned char *a_data);</b></span><br />
<br />
It returns one if there is a character available and place it in the pointer provided. In order to perform some offline tests a similar function for x86 Linux terminal is needed. Unfortunately such function doesn't exist. There are two options<br />
<br />
<br />
<ol>
<li>Use ncurses which implements getch() function - to retrieve a single character.</li>
<li>Disabled so called "canonical mode" for a standard linux terminal and use getchar() in non blocking mode.</li>
</ol>
<br />
<br />
Let's focus on the second approach. Ncurses is a bit of an overkill as far as I'm concerned though using it would be platform independent - but it's only a test application so, it's not that important. Let's have a look on the test program bellow.<br />
<br />
<script src="https://gist.github.com/dagon666/8194870.js"></script>
<br />
I implemented here two functions <span style="font-family: Courier New, Courier, monospace;">cm_off</span> & <span style="font-family: Courier New, Courier, monospace;">cm_on</span> in order to turn the "canonical" mode on & off. When this mode is turned off - I'm able to get a direct input using the getchar() routine without having to press ENTER after every key. Our final <span style="font-family: Courier New, Courier, monospace;">linux_getc</span>() along with <span style="font-family: Courier New, Courier, monospace;">linux_putc()</span> routine will look the following way:<br />
<br />
<script src="https://gist.github.com/dagon666/8194890.js"></script>
<br />
Let's implement the <span style="font-family: Courier New, Courier, monospace;">CLI</span> interpreter itself now.<br />
<br />
<script src="https://gist.github.com/dagon666/8194896.js"></script>
<br />
It doesn't do much at the moment. In fact it doesn't even run the commands. All it does is handle some basic input. We echo back the incoming characters, interpret backspace key and the ENTER key, printing some fancy prompt:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>$ ./a.out </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> command</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> some other cmd </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> aaa</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> </b></span><br />
<br />
That is not very exciting in particular. Let's implement a command interpretation first:<br />
<br />
<script src="https://gist.github.com/dagon666/8194909.js"></script>
<br />
I'll place that function in the <span style="font-family: Courier New, Courier, monospace;">KEY_CODE_ENTER</span> switch case:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>case KEY_CODE_ENTER: // new line</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>a_ctx->cmd[POSINC(a_ctx->cpos)] = '\0';</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT("\r\n", 2);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>res = _cli_interpret_cmd(a_ctx);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>a_ctx->cpos = 0;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>memset(a_ctx->cmd, 0x00, CLI_CMD_BUFFER_SIZE);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>_cli_prompt(a_ctx, 1);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>break;</b></span><br />
<br />
<br />
I need some dummy commands implementation as well:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>static void fh_hw(void *a_data) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT("hello_world", 11);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>static void fh_hi(void *a_data) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT("hi", 2);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span><br />
<br />
Let's do the test<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>./a.out </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#> hw</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>hello_world</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#> hi</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>hi</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#> test</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> </b></span><br />
<br />
Looks good, although there are is a problem - there is no info that a particular command is unknown. This must be fixed. Let's create another function and place it just after <span style="font-family: Courier New, Courier, monospace;">_cli_interpret_cmd</span> in the switch case for ENTER key.<br />
<br />
<script src="https://gist.github.com/dagon666/8199035.js"></script>
<br />
The switch case for ENTER will look the following way now:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>case KEY_CODE_ENTER: // new line</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>a_ctx->cmd[POSINC(a_ctx->cpos)] = '\0';</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT("\r\n", 2);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>res = _cli_interpret_cmd(a_ctx);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>_cli_reinterpret_cmd(a_ctx, res);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>a_ctx->cpos = 0;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>memset(a_ctx->cmd, 0x00, CLI_CMD_BUFFER_SIZE);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>_cli_prompt(a_ctx, 1);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>break;</b></span><br />
<br />
Let's test it:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>./a.out</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> test</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>Command not found</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#> other</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>Command not found</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#> hw</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>hello_world</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#></b></span><br />
<br />
That's starting to look very good. At the moment we have a functional very basic <span style="font-family: Courier New, Courier, monospace;">CLI</span> system. Let's consider what else is missing. When pressing an arrow keys nothing happens - we are unable to correct any mistakes in the middle of the command. This can be implemented. But first, let's checkout the key codes produced by those keys. On my terminal those are:<br />
<br />
<br />
<ul>
<li>Left: 1b 5b 44</li>
<li>Right: 1b 5b 43</li>
<li>Up: 1b 5b 41</li>
<li>Down: 1b 5b 42</li>
</ul>
<br />
<br />
They may be completely different on yours. It's all terminal dependent, things like character encoding and terminal settings have a major influence here. That complicates the situation slightly, since a single key produces 3 codes and the key itself can be distinguished only by the third one. Our present implementation is unable to cope with that kind of input. Let's define a structure for that kind of input representing a single key<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define MULTICODE_INPUT_MAX_LEN 5</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>typedef struct _t_multicode_input {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char buf[MULTICODE_INPUT_MAX_LEN];</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char pos;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>} t_multicode_input;</b></span><br />
<br />
<br />
... and a related command:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>typedef struct _t_multicode_cmd {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char pattern[MULTICODE_INPUT_MAX_LEN];</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char len;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>void (*fh)(void*);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>} t_multicode_cmd;</b></span><br />
<br />
<br />
OK. The "input code" can be up to 5 characters long. What I want to do is to simply read the whole multi-code input and compare it against known ones in order to trigger some actions. First the CLI context structure must be extended:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>typedef struct _t_cli_ctx {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// command set</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_cmd *cmds;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_multicode_cmd *mcmds;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// cmd</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char cmd[CLI_CMD_BUFFER_SIZE];</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char cpos;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// multicode input</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_multicode_input mchar;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>} t_cli_ctx;</b></span><br />
<br />
<br />
The interpreter must be extended as well:<br />
<br />
<script src="https://gist.github.com/dagon666/8199064.js"></script>
<br />
What I'm doing here is simply matching a whole multi-code input sequence against the known ones and fire an action if there is a match. Still, there's no associated actions defined. Let's create a couple:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">t_multicode_cmd g_mc_cmds[] = {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x44 }, 3, _cli_key_left },</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x43 }, 3, _cli_key_right },</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>// null</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{ {0x00}, 0, 0x00}</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">};</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">static void _cli_key_left(void *a_data) {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>t_cli_ctx *ctx = (t_cli_ctx *)a_data;</span></b><br />
<span class="Apple-tab-span" style="font-family: Courier New, Courier, monospace; white-space: pre;"><b> </b></span><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (ctx->cpos) {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>ctx->cmd[ctx->cpos--] = '\0';</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT("\b \b", 3);</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">}</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">static void _cli_key_right(void *a_data) {</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">}</span></b><br />
<br />
Just to make things simple - the left arrow key will behave the same way as backspace key. The right key won't do anything. That's great we can now handle even more complex input type. Let's think what else is still missing ?<br />
<br />
What happends when you hit an up arrow key in bash ? It brings back the previous command. Some simple history implementation would be very fancy and would make the <span style="font-family: Courier New, Courier, monospace;">CLI</span> system very attractive. Let's implement it as well. First some additional data fields are needed in the <span style="font-family: Courier New, Courier, monospace;">CLI</span> context. Let's have a look on it once again:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define CLI_CMD_HISTORY_LEN 8</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>typedef struct _t_cli_ctx {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// command set</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_cmd *cmds;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_multicode_cmd *mcmds;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// cmd</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char cmd[CLI_CMD_BUFFER_SIZE];</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char cpos;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// history</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char history[CLI_CMD_HISTORY_LEN][CLI_CMD_BUFFER_SIZE];</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char hpos;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>unsigned char hhead, htail;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// multicode input</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_multicode_input mchar;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>} t_cli_ctx;</b></span><br />
<br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">CLI</span> will hold last 8 commands typed into it. After pressing ENTER we need to save current command line into the history. Let's do it in the <span style="font-family: Courier New, Courier, monospace;">_cli_reinterpret_cmd</span> function to sift any junk input from contaminating the history:<br />
<br />
<script src="https://gist.github.com/dagon666/8199096.js"></script>
<br />
Handlers for up/down arrow keys are needed to make this feature complete:<br />
<br />
<script src="https://gist.github.com/dagon666/8199108.js"></script>
<br />
Now, those commands must be attached to our multicode_input command array.<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>t_multicode_cmd g_mc_cmds[] = {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x44 }, 3, _cli_key_left },</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x43 }, 3, _cli_key_right },</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x41 }, 3, _cli_history_up },</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x42 }, 3, _cli_history_down },</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>// null</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ {0x00}, 0, 0x00}</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>};</b></span><br />
<br />
And we're ready to go. Let's test it.<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">$ ./a.out</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">#> command1</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">Command not found</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">#> cmd2</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">Command not found</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">#> cmd3</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">Command not found</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">#></span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">(3/8)cmd3</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">(2/8)cmd2</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">(1/8)command1</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">Command not found</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">#></span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">(4/8)command1</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">(3/8)cmd3</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;"><br /></span></b>
<b><span style="font-family: Courier New, Courier, monospace;">Command not found</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">#></span></b><br />
<br />
That seems to work very well. Our <span style="font-family: Courier New, Courier, monospace;">CLI</span> starts to look very attractive now. One thing is still missing though - the basic command argument support. I left it for the end deliberately. Let's not forget that the final product will run on a small micro-controller with not much <span style="font-family: Courier New, Courier, monospace;">RAM</span> on board. The only generic useful information would be an <span style="font-family: Courier New, Courier, monospace;">argc</span> - an integer defining how many space delimited words have been typed into the <span style="font-family: Courier New, Courier, monospace;">CLI</span>. If the command really needs to parse arguments then it should do it itself, just to save resources. Let's modify the code for <span style="font-family: Courier New, Courier, monospace;">_cli_interpret_cmd</span> first and add a call to the argument counting routine:<br />
<br />
<b style="font-family: 'Courier New', Courier, monospace;">a_ctx->argc = _cli_count_arguments(a_ctx);</b><br />
<br />
The routine itself:<br />
<br />
<script src="https://gist.github.com/dagon666/8199128.js"></script>
<br />
Let's write a test command for that as well:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{ "argc", fh_argc },</span></b><br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>static void fh_argc(void *a_data) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>char tmp[16] = { 0x00 };</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>t_cli_ctx *ctx = (t_cli_ctx *)a_data;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>sprintf(tmp, "argc: %d", ctx->argc);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT(tmp, strlen(tmp));</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span><br />
<br />
and test it:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>$ ./a.out</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>#> argc</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>argc: 1</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#> argc a1 a2 a4</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>argc: 4</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#></b></span><br />
<br />
That works fine as well. At this stage we are done with testing on the x86 platform and we can move the code to the MCU itself. It's a good point to summarize the complete code so far. I reorganized the whole thing and split the code into files<br />
<br />
<script src="https://gist.github.com/dagon666/8199158.js"></script><br />
<br />
The test application can be compiled without a Makefile, the following way:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>gcc main.c linux_io.c cli.c -I. -o cli</b></span><br />
<br />
<h3>
Moving the CLI to the MCU</h3>
<br />
There's not much to do actually since the <span style="font-family: Courier New, Courier, monospace;">CLI</span> has been written with a hardware independent code. However there are some gotchas which will come out later on. First let's prepare the project, change the <span style="font-family: Courier New, Courier, monospace;">IO</span> routines for the <span style="font-family: Courier New, Courier, monospace;">CLI</span>, compile the project and try to run it. Of course, I'm going to use the serial routines implemented in libpca for the <span style="font-family: Courier New, Courier, monospace;">IO</span>. The <span style="font-family: Courier New, Courier, monospace;">IO</span> definitions look the following way:<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>/**</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> * @brief IO input routine - change it accordingly to your implementation</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> */</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define CLI_IO_INPUT(__data) \</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>serial_getc(__data)</b></span><br />
<span class="Apple-tab-span" style="font-family: Courier New, Courier, monospace; white-space: pre;"><b> </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>/**</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> * @brief IO output routine - change it accordingly to your implementation</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> */</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define CLI_IO_OUTPUT(__data, __len) \</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>serial_poll_send(__data, __len)</b></span><br />
<br />
After flashing the arduino and connecting a minicom terminal, first thing to notice is lack of any response for ENTER key. Minicom emulates <span style="font-family: Courier New, Courier, monospace;">VT102</span> terminal and sends only a <span style="font-family: Courier New, Courier, monospace;">0x0d</span> code for a new line character, the devinition for <span style="font-family: Courier New, Courier, monospace;">KEY_CODE_ENTER</span> must be changed accordingly. Let's recompile and verify the rest of the keys. The arrow keys works. The backspace key and the delete key don't work though, again it's the matter of the incorrect keycodes. We can discover those by echoing them back after receiving:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>sprintf(tmp, "%02x\n", i);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>CLI_IO_OUTPUT(tmp,strlen(tmp));</b></span><br />
<br />
Minicom on my machine sends 0x08 code for backspace and a set of codes for backspace key: 0x1b 0x5b 33 7e. The code needs to be adjusted slightly. First the value of <span style="font-family: Courier New, Courier, monospace;">KEY_CODE_BACKSPACE</span> must be corrected. The <span style="font-family: Courier New, Courier, monospace;">DELETE</span> key needs to be interpreted in "multicode" fashion. I'll attach the same action to it as for <span style="font-family: Courier New, Courier, monospace;">BACKSPACE</span> and left arrow key:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>{ { 0x1b, 0x5b, 0x33, 0x7e }, 4, _cli_delete }, // delete</b></span><br />
<br />
Let's recompile and test once again. Everything seems to work now. The basic <span style="font-family: Courier New, Courier, monospace;">CLI</span> code is complete. This code proves how much <span style="font-family: Courier New, Courier, monospace;">CLI</span> systems and interpreters are terminal dependent. We can either try to be as much compliant and flexible with most of popular terminal emulators or simply require from the user to use only one specific type i.e. <span style="font-family: Courier New, Courier, monospace;">VT100</span> / <span style="font-family: Courier New, Courier, monospace;">VT102</span> or any other.<br />
<br />
As usual a set of sources can be downloaded either from my google drive or from github. Snapshot, containing a version of libpca as well as the source code discussed in this post is available <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/cli.tgz"><span id="goog_1725105347"></span>here<span id="goog_1725105348"></span></a><br />
<br />
The code is available in my GitHub repositories. First you need libpca:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span><br />
<br />
and my projects repository:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_ArduinoProjects projects</b></span><br />
<br />
Navigate to <span style="font-family: Courier New, Courier, monospace;"><b>projects/cli_mcu</b></span> to find the source code.<br />
<div>
<br /></div>
<br /></div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com4tag:blogger.com,1999:blog-4146080941178349095.post-24276089655569470732013-12-13T05:31:00.002-08:002013-12-27T02:13:50.709-08:00Simple GPIO APIPractically with every project, I buy a new device - with which I need to familiarize myself. Most of the time those are devices using already very well known buses like <span style="font-family: Courier New, Courier, monospace;">I2C</span>, <span style="font-family: Courier New, Courier, monospace;">OneWire </span>or <span style="font-family: Courier New, Courier, monospace;">SPI</span>. But from time to time it's a parallel device with a very specific interface. There's a need for the driver then. There are two ways: the easy one - get the driver from the internet and use it - now don't get me wrong that's a perfectly good way to solve the problem - your device is up and running pretty fast and you do not have to worry about it, since most of the problems have been already taken care for you.<br />
<br />
<div style="text-align: justify;">
The hard way is to write the driver yourself. Now a question arise why to do it in the first place ? The are a couple of reasons for that. First of all - you want to learn something - most obviously you will, since you will have to learn about the device thoroughly. Second - you want to make it smaller/faster - that's more pragmatic reason, since the downloaded driver may not represent the "state of the art" or simply maybe bloated with features which are not desired or simply not needed. Another good reason is that the available drivers are simply not compatible with our already existing program and making both fit one to each other may take more time and effort than simply creating a new driver from scratch.</div>
<br />
<div style="text-align: justify;">
OK, but what does this all have in common with <span style="font-family: Courier New, Courier, monospace;">GPIO </span>lines ? Devices use <span style="font-family: Courier New, Courier, monospace;">GPIOs</span>, in case we need to "bit bang" some sort of communication standards will operate on <span style="font-family: Courier New, Courier, monospace;">GPIOs</span>. </div>
<br />
Why not use the PORT{B,C,D} directly though ? Because it will be pretty hard to change the code when you decide to move your device to different pins. In that case most people use preprocessor like that:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define PORT<span class="Apple-tab-span" style="white-space: pre;"> </span>PORTD</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define DDR<span class="Apple-tab-span" style="white-space: pre;"> </span>DDRD</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define INP<span class="Apple-tab-span" style="white-space: pre;"> </span>PIND</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define PIN<span class="Apple-tab-span" style="white-space: pre;"> </span>6</b></span><br />
<br />
... and in the code<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>DDR |= _BV(PIN);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>PORT &= ~_BV(PIN);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>PORT |= _BV(PIN);</b></span><br />
<div>
<br /></div>
<div>
<div>
... and so on. For a simple case that's pretty good approach, but if we have a lot of lines that may become a problem since the pin declaration becomes very complicated and extensive. It can be done a lot slicker and elegant. In order to have complete control over a port we need 4 values: the port's data register (<span style="font-family: Courier New, Courier, monospace;">PORTX</span>), the port's direction register (<span style="font-family: Courier New, Courier, monospace;">DDRX</span>), the port's input register (<span style="font-family: Courier New, Courier, monospace;">PINX</span>) and the pin number. OK, but going through the datasheet a nice dependency occurs. The <span style="font-family: Courier New, Courier, monospace;">PORT </span>addresses are consecutive:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>PORTB = 0x05</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>DDRB = 0x04</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>PINB = 0x03</b></span></div>
<div>
<br /></div>
<div>
So, having only the <span style="font-family: Courier New, Courier, monospace;">PORTX </span>address, we are able to determine every other needed memory location. Let's make some macros for that:</div>
</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>/**</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> * @brief get pointer to DDR register from PORT register</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> *</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> * @param __val pointer to PORT register </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> *</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> * @return pointer to DDR register</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> */</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GET_DDRX_FROM_PORTX(__portx) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>(__portx - 1)<span class="Apple-tab-span" style="white-space: pre;"> </span></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>/**</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> * @brief get pointer to PIN register from PORT register</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> *</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> * @param __val pointer to PORT register </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> *</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> * @return pointer to PIN register</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> */</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GET_PINX_FROM_PORTX(__portx) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>(__portx - 2)<span class="Apple-tab-span" style="white-space: pre;"> </span></b></span></div>
</div>
<div>
<br /></div>
<div>
<div>
It's pretty simple to use them:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>volatile uint8_t ddr = GET_DDRX_FROM_PORTX(&PORTB);</b></span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Now, we need only the <span style="font-family: Courier New, Courier, monospace;">PORTX </span>address and the pin number. We can make it even more flexible and universal. Let's desribe a single gpio:</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>typedef struct _gpio_pin {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>volatile uint8_t *port;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>uint8_t pin;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>} gpio_pin;</b></span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Now, we can declare a single pin like that:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>gpio_pin x;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>x.port = &PORTB;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>x.pin = 3;</b></span></div>
<div>
<br /></div>
<div>
At the moment it's not very convenient to use this type, since just to change the value we need to:</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>*x.port &= ~_BV(x.pin);</b></span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
But we can create some macros for that as well:</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GPIO_CONFIGURE_AS_OUTPUT(__gpio) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>*(GET_DDRX_FROM_PORTX((__gpio)->port)) |= _BV((__gpio)->pin)</b></span></div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"><span style="font-family: Courier New, Courier, monospace;"><b> </b></span></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GPIO_CONFIGURE_AS_INPUT(__gpio) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>*(GET_DDRX_FROM_PORTX((__gpio)->port)) &= ~_BV((__gpio)->pin)</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GPIO_GET(__gpio) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>(*(GET_PINX_FROM_PORTX((__gpio)->port)) & _BV((__gpio)->pin))</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GPIO_SET_LOW(__gpio) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>(*(__gpio)->port) &= ~_BV((__gpio)->pin)</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GPIO_SET_HIGH(__gpio) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>(*(__gpio)->port) |= _BV((__gpio)->pin)</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define GPIO_TOGGLE(__gpio) \</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>*(GET_PINX_FROM_PORTX((__gpio)->port)) = _BV((__gpio)->pin)</b></span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
OK. Now we've everything we need. Let's have a look at a full blinking <span style="font-family: Courier New, Courier, monospace;">LED </span>example using this API. The example presents two options. First using the <span style="font-family: Courier New, Courier, monospace;">TOGGLE </span>call, second using the <span style="font-family: Courier New, Courier, monospace;">LOW/HIGH</span> calls. In order to test the second one, you should comment out the first one.</div>
<div>
<br />
<script src="https://gist.github.com/dagon666/7944242.js"></script>
<br />
</div>
<div>
This all may look unnecessarily over complicated but it's very useful when trying to write a flexible driver. Just imagine that you wrote a great driver for an <span style="font-family: Courier New, Courier, monospace;">LCD </span>display. You used in your device on let's say on a couple of pins of <span style="font-family: Courier New, Courier, monospace;">PORTB</span>, then you want to use it again in a completely different device on a completely different set of pins - there's not a problem at all - since thanks to this abstraction you just need to redefine the pin numbers. The driver uses the <span style="font-family: Courier New, Courier, monospace;">GPIO </span>API and is completely hardware independent ! That's a great advantage !</div>
<div>
<br /></div>
<div>
I hope that this tip was useful. I'm currently working on the software for one of my standalone devices - Clock with Thermometer - want to polish it as much as possible and implement some cool ideas so, it takes pretty long. Can't wait to publish some details regarding this project</div>
</div>
<div>
<br /></div>
<div>
<br /></div>tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-25044701645103215782013-11-17T11:54:00.000-08:002013-12-27T02:14:15.490-08:00RTC without RTC ? How good is my crystal ?<div style="text-align: justify;">
Clock - I think that it's the most popular idea for a project with the <span style="font-family: Courier New, Courier, monospace;">MCU</span>. It's not that hard from both software and hardware side to realize but not that trivial as well, not mentioning the fact that once realized it sits somewhere in the house, constantly reminding about itself and brings a kind of satisfaction :). There are a lot of options really to implement, a buzzer alarm, perhaps a thermometer, display and buttons servicing, perhaps maybe even serial port usage for <span style="font-family: Courier New, Courier, monospace;">NTP</span> synchronization. But ...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The most challenging thing - like in every clock is the time reference source. There are a couple of options:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li>well calibrated frequency source acting as an interrupt source</li>
<li>Real Time Clock module with external crystal ( < 20 ppm )</li>
<li>internal clock</li>
</ul>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
These days <span style="font-family: Courier New, Courier, monospace;">RTC</span> chips are so cheap and widely available that they are really the only reasonable choice, but if we're only planning to play around a bit with the software without paying much attention to accuracy and just for the sake of curiosity let's check how good the crystal to generate the system clock on the Arduino board is.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
System Clock</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
System clock is generated using an external 16 MHz crystal. This crystal is not ideal, although it's quite stable - it may be surprising that it doesn't resonate exactly with the referenced frequency. In fact this frequency is a little bit different. </div>
<div style="text-align: justify;">
<br /></div>
<h3>
Stability</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
A crystal accuracy is measured with <span style="font-family: Courier New, Courier, monospace;">ppms</span> (parts per million). A typical crystal used to generate a system clock is something around +/- 50 - 100 ppm. Let's assume 80 ppm. The day has:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>day = 24 * 60 * 60 = 86400 s</b></span></div>
<div style="text-align: justify;">
<br />
the hour<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>hour = 60 * 60 = 3600 s</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div style="text-align: justify;">
If we would want to use this crystal as a reference for the clock application our clock would loose/gain:<br />
<br />
per day:</div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>86400 * 80 ppm = 86400 * 0,0008 = 6,91 s</b></span><br />
<br /></div>
<div style="text-align: justify;">
per hour:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">3600 * 80 ppm = 3600 * 0,0008 = 0,288 s</span></b><br />
<br />
On the worst case it would be around 9 s per day. That's not that bad for a toy project.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Resonance frequency</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Although the stability is quite satisfying, information about the exact resonance frequency is needed. How different is the resonance frequency of a typical 16 MHz crystal from the referenced 16 MHz ?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Using some code I can roughly measure it without using any laboratory equipment like frequency meters or oscilloscope. In fact I don't have access to this hardware and for most of the simple projects which I present here, although it would be helpful it's not a must.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The simplest way to estimate the crystal frequency is to use the code already created in <span style="font-family: Courier New, Courier, monospace;">libpca</span>. Let's generate a tone of let's say 1 kHz frequency with a <span style="font-family: Courier New, Courier, monospace;">libpca beeper</span> API. Now, Instead of connecting the buzzer I'll connect the pin to my laptop's microphone input directly and try to record it. The code is trivial:</div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/7499855.js"></script>
</div>
<div style="text-align: justify;">
Recorded signal:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/--Y0h01gqo8c/UodrJQHNykI/AAAAAAAAAUA/8Jc1IY_KGXE/s1600/1khz_samples.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/--Y0h01gqo8c/UodrJQHNykI/AAAAAAAAAUA/8Jc1IY_KGXE/s1600/1khz_samples.png" height="400" width="323" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">1 kHz square signal recorded from OC0A pin.</td></tr>
</tbody></table>
<br />
This rough measurement shows that the full period took 45 samples at 44,1 kHz sampling rate, this gives the period of ~1,02 ms. The crystal clock period is 16000 shorter. After dividing the measured period of 1 kHz beep by 16000 and converting it to frequency, the answer is:<br />
<br />
<b>f =~ 15,68 MHz.</b><br />
<br />
This means that our clock application will loose seconds. Every second measured will in fact be a 1,02 seconds in reality. This gives 1.2 seconds behind after every minute ! Of course the measurements done cannot be taken very seriously since they are done very inaccurately and without a proper tools, but keeping them in mind, let's write a simple application and see how much our "clock application" will be wrong from real time.<br />
<br />
<br />
<script src="https://gist.github.com/dagon666/7517380.js"></script>
<br />
The above code is self explaining more or less, the "epoch" variable is incremented in the interrupt service routine every second (since interrupt happens every 1/256 s and epoch is incremented only when the <span style="font-family: Courier New, Courier, monospace;">cnt</span> variable wraps). The time is send via Serial Port as a string.<br />
<br />
After flashing it and running. I did some comparison between the measured time and the "real" time with a stopwatch. After an hour, Arduino has been a second behind. The crystal instability (80 ppm) results in 0,3 seconds behind. Assuming 0,7 second lost per hour I can roughly estimate that my crystal is less than 16 MHz by something around 3 kHz. So, it's more like <b>15,9968</b> MHz.<br />
<br />
<h3>
Conclusion</h3>
<br />
When building a real clock application <span style="font-family: Courier New, Courier, monospace;">RTC</span> chip is a must, the system clock won't provide enough accuracy to be considered as a frequency reference good enough. Not mentioning the obvious advantage of having the <span style="font-family: Courier New, Courier, monospace;">RTC</span> - the time is counted even if the main <span style="font-family: Courier New, Courier, monospace;">CPU</span> is not powered, since most of them have a backup lithium battery circuitry.<br />
<br />
The methods used to estimate the Crystal's resonance frequency cannot be treated serously with any level of confidence and used for a real production purpose, since they present no practical level of accuracy and the results are only a general hint.<br />
<div>
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com1tag:blogger.com,1999:blog-4146080941178349095.post-22056041852083895372013-11-08T08:52:00.002-08:002013-12-27T02:13:30.926-08:00Arduino PWM Audio DAC<div style="text-align: justify;">
This post is an addendum to the previous one. To make our lives (as a software developers) even more easier it is possible to recreate a real audio without even having to built the <span style="font-family: Courier New, Courier, monospace;">R-2R</span> ladder. <span style="font-family: Courier New, Courier, monospace;">Atmega328</span> comes with a <span style="font-family: Courier New, Courier, monospace;">PWM</span> capable timers and they're good enough to produce audio quality analog signal.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
PWM fundamentals</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I'm not going to go into details about <span style="font-family: Courier New, Courier, monospace;">PWM</span> digital to analog conversion, on this blog I focus on my code and do not intend to cover the theoretical background very thoroughly. Please take some time and familiarize yourself with the <span style="font-family: Courier New, Courier, monospace;">PWM</span> theory explained on those sites:<br />
<br />
<ol>
<li><a href="http://www.openmusiclabs.com/learning/digital/pwm-dac/" target="_blank">Open Music - PWM DAC</a></li>
<li><a href="http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/" target="_blank">Open Music - Dual PWM</a></li>
<li><a href="http://www.openmusiclabs.com/learning/digital/pwm-dac/pwm-distortion-analysis/" target="_blank">Open Music - Distortion Analysis</a></li>
<li><a href="http://wiki.openmusiclabs.com/wiki/PWMDAC" target="_blank">Open Music - PWM Tutorial</a></li>
</ol>
<div>
<br />
In general every <span style="font-family: Courier New, Courier, monospace;">PWM DAC</span> can be described by a <span style="font-family: Courier New, Courier, monospace;">PWM</span> frequency - <span style="font-family: Courier New, Courier, monospace;">f<span style="font-size: x-small;">pwm</span></span> (the frequency of the squarewave generated - which is constant) and the <span style="font-family: Courier New, Courier, monospace;">PWM</span> bit resolution - <span style="font-family: Courier New, Courier, monospace;">bitres</span> (which describes the granularity with which we can control the duty cycle).</div>
<div>
<br /></div>
<div>
All of three Arduino's Timers are capable of generating <span style="font-family: Courier New, Courier, monospace;">PWM</span> signal. I'll focus of course on <span style="font-family: Courier New, Courier, monospace;">Timer1</span> since it's the only 16 bit timer. As mentioned above we have two properties to configure - the <span style="font-family: Courier New, Courier, monospace;">PWM</span> frequency - <span style="font-family: 'Courier New', Courier, monospace;">f</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">pwm </span>and the bit resolution. The signal theory says that the <span style="font-family: 'Courier New', Courier, monospace;">f</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">pwm</span> should be at least two times higher than the highest frequency in our signal. How to calculate it and what is the highest possible we can achieve ? To answer that some details from the datasheet are needed and in fact an understanding of how Atmega's Timer really works.</div>
<div>
<br /></div>
<div>
<h3>
Timer in PWM mode</h3>
</div>
<div>
<br /></div>
<div>
Using either Fast (<span style="font-family: Courier New, Courier, monospace;">FPWM</span>) or Phase & Frequency Correct PWM (<span style="font-family: Courier New, Courier, monospace;">PFPWM</span>) the timer counts up from 0 to value in either <span style="font-family: Courier New, Courier, monospace;">OCR1A</span> or <span style="font-family: Courier New, Courier, monospace;">ICR1</span> register (I'll use <span style="font-family: Courier New, Courier, monospace;">ICR1</span> to define the frequency, since obviously the value in <span style="font-family: Courier New, Courier, monospace;">OCR1A</span> will control the comparator and in result the duty cycle). This means that <span style="font-family: Courier New, Courier, monospace;">ICR1</span> defines the <span style="font-family: Courier New, Courier, monospace;">TOP</span> value for the timer (and thus implicitly defines how often the timer will overflow). The <span style="font-family: Courier New, Courier, monospace;">PWM</span> frequency will be defined as:</div>
<div>
<br /></div>
<div>
Fast PWM:<br />
<br /></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace;">fpwm = fclk / [ N * (1 + ICR1) ]</span></b></div>
<div>
<br /></div>
<div>
Phase and Frequency Correct:</div>
<div>
<br />
<b><span style="font-family: Courier New, Courier, monospace;">fpwm = fclk / [ 2 * N * (1 + ICR1) ]</span></b></div>
<div>
<br /></div>
<div>
where N is prescaler.</div>
<div>
<br /></div>
<div>
I want the <span style="font-family: Courier New, Courier, monospace;">fpwm</span> to be as high as possible so, obviously the prescaler will be configured to 1. It may not be visible at first glance but the <span style="font-family: Courier New, Courier, monospace;">fpwm</span> has a major implications on the bit resolution as well. The value in <span style="font-family: Courier New, Courier, monospace;">OCR1A</span> will control the duty cycle - it can't be any bigger than the value defined in <span style="font-family: Courier New, Courier, monospace;">ICR1</span> - which defines the frequency. if it will be higher than <span style="font-family: Courier New, Courier, monospace;">ICR1</span> than the timer simply will never reach it and the result will be a flat line - 100% duty cycle. It's more clear if you look at the picture</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-v3fIU28bVBU/UnzBcCUL44I/AAAAAAAAASo/2jfDPXWRRVk/s1600/pwm_timer.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-v3fIU28bVBU/UnzBcCUL44I/AAAAAAAAASo/2jfDPXWRRVk/s1600/pwm_timer.png" height="265" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Principles of PWM with Atmega's Timers.</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
It's clear now that the demand for highest possible <span style="font-family: 'Courier New', Courier, monospace;">f</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">pwm </span>as well as highest possible bitrate is self contradicting. A golden merit must be established. In general it's worth to sacrifice some of the bit resolution just to increase the <span style="font-family: 'Courier New', Courier, monospace;">f</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">pwm</span>. I'll talk about real values in just a moment.</div>
<div>
<br /></div>
<div>
<h3>
... Need more bandwidth</h3>
</div>
<div>
<br /></div>
<div>
Indeed, just as previously the main bottleneck is the Serial Port. I did some tests pushing it to it's limits and it seems that the highest possible baud rate I can get is 230400. I don't want to change the firmware in Arduino's Atmega16U2 chip responsible for USB <-> serial communication, so I guess I'll have to live with this constrain and try to squeeze as much of the serial port as possible anyway.<br />
<br />
230400 is not that bad. It's 23kB per second. What I can play with it ? There are a three options really (not mentioning the compressed formats - but that's a completely different story):<br />
<br />
<ul>
<li>16 kHz, 8 bit = 16 kB/s</li>
<li>8 kHz, 16 bit = 16 kB/s</li>
<li><strike>22 kHz, 8 bit = 22 kB/s</strike> 18 kHz, 8bit = 18 kB/s</li>
</ul>
<div>
22 kHz sounds pretty good. This means that the highest frequency that can be recreated is around 11 kHz. As it will be shown later the bit resolution doesn't have that much of a spectacular influence on the quality, The bit resolution defines the so called "noise floor" which in simple words means that the lesser the bit resolution the noisier the signal will be and it will be impossible to recreate some very quiet - low amplitude sounds since they will drown in the digital noise itself. In this case, having the sampling rate as highest as possible is crucial.</div>
</div>
<div>
<br /></div>
<div>
22 kB/s doesn't leave much time margin though. It's almost feeding the <span style="font-family: Courier New, Courier, monospace;">DAC</span> directly from the <span style="font-family: Courier New, Courier, monospace;">USART</span> without much of a buffering - this may be a source of glitches and noise as well, not mentioning the glitches that will happen if the transmission is unsuccessful. The <span style="font-family: Courier New, Courier, monospace;">MCU</span> will be pretty busy. In fact the <span style="font-family: Courier New, Courier, monospace;">USART</span> is too slow to provide the data on time with this sampling rate. The highest I could get is 18 kHz unfortunately. 18 kHz is an absolute limit for the USART and even at that speed occasionally some glitches may happed<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-0veGAqOs4TQ/UnzraCzV-AI/AAAAAAAAATI/vQmXZSMasUw/s1600/audio_glitch.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-0veGAqOs4TQ/UnzraCzV-AI/AAAAAAAAATI/vQmXZSMasUw/s1600/audio_glitch.png" height="300" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Data delivered to slow. A short moment of silence.</td></tr>
</tbody></table>
<br />
Anyway it's pretty good though, 9 kHz of audible bandwidth should sound good.</div>
<div>
<br /></div>
<h3>
PWM frequency and bit resolution</h3>
<div>
<br /></div>
<div>
Going back to the <span style="font-family: Courier New, Courier, monospace;">PWM</span> frequency. I'll use the Phase & Frequency correct <span style="font-family: Courier New, Courier, monospace;">PWM</span> mode. Our requirement is to play an audio with highest frequency up to 9 kHz. The <span style="font-family: Courier New, Courier, monospace;">fpwm</span> must be higher than 18 kHz. We'll base our calculations on the bit resolution though, since we're not going to play anything above 8 bits (per PWM channel). Assuming that OCR1A must have an 8 bit resolution so <span style="font-family: Courier New, Courier, monospace;">ICR1</span> must be configured to 256. Taking those values into consideration:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>fpwm = 16 MHz / [ 2 * 1 * (1 + 255) ] = 31,25 kHz</b></span></div>
<div>
<br /></div>
<div>
which is 3,4 higher than the highest frequency of the signal - that'll do.</div>
<div>
<br /></div>
<h3>
16 bit playback</h3>
<div>
<br /></div>
<div>
One of the options that I have is to play 16bits 8 kHz audio. Now, how to do this when just a paragraph before I configured the PWM resolution to 8 bits ? It's actually pretty easy. Atmega has two comparators per timer <span style="font-family: Courier New, Courier, monospace;">OC1A</span> and <span style="font-family: Courier New, Courier, monospace;">OC1B</span>. Each of them has an independent register <span style="font-family: Courier New, Courier, monospace;">OCR1A</span> and <span style="font-family: Courier New, Courier, monospace;">OCR1B</span> which value is constantly compared with <span style="font-family: Courier New, Courier, monospace;">TCNT1</span> value. The <span style="font-family: Courier New, Courier, monospace;">PWM</span> duty cycle of the waveform on <span style="font-family: Courier New, Courier, monospace;">OC1A</span> and <span style="font-family: Courier New, Courier, monospace;">OC1B</span> pins is controlled by configuring <span style="font-family: Courier New, Courier, monospace;">OCR1A</span> and <span style="font-family: Courier New, Courier, monospace;">OCR1B</span> to appropriate values. In fact we can sum the signal from those two 8 bit outputs using resistors to form one combined output 16 bit output. The trick is that the resistor for the least signifficant byte has 256 smaller value than the one for the most signifficant byte - by natural way the levels of those two <span style="font-family: Courier New, Courier, monospace;">PWM</span> outputs are shifted.</div>
<div>
<br /></div>
<div>
<h3>
Playback</h3>
</div>
<div>
<br /></div>
<div>
The playback loop is slightly different than the one for R-2R ladder. Now instead of pushing the data to the ports, it is "pushed" to the <span style="font-family: Courier New, Courier, monospace;">OCR1A</span> timer registers:</div>
<div>
<br />
<br />
<script src="https://gist.github.com/dagon666/7370906.js"></script>
</div>
<div>
you noticed the <span style="font-family: Courier New, Courier, monospace;">MODE</span> macro. The software; during compilation, can be configured into any of the mentioned mode<br />
<br />
<ul>
<li><span style="font-family: 'Courier New', Courier, monospace;">#define MODE_8K_8B 0</span></li>
<li><span style="font-family: 'Courier New', Courier, monospace;">#define MODE_8K_16B 1</span></li>
<li><span style="font-family: 'Courier New', Courier, monospace;">#define MODE_16K_8B 2</span></li>
<li><span style="font-family: 'Courier New', Courier, monospace;">#define MODE_18K_8B 3</span></li>
</ul>
</div>
<div>
<br />
By default <span style="font-family: Courier New, Courier, monospace;">MODE</span> is configured to<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">#define MODE MODE_16K_8B</span></b></div>
<div>
<br /></div>
<div>
Dependently on the mode selected (16bit or 8 bit) the sample value is copied only to <span style="font-family: Courier New, Courier, monospace;">OCR1AL</span> or to both <span style="font-family: Courier New, Courier, monospace;">OCR1AL</span> and <span style="font-family: Courier New, Courier, monospace;">OCR1BL</span>. </div>
<div>
<br /></div>
<h3>
The Circuit</h3>
<div>
<br /></div>
<div>
PWM requires a couple of components forming a low pass filter in order to get rid of the PWM carrier frequency. The PWM frequency is 31,25 kHz, but we don't need anything really above 9 kHz, so the filter values should be:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>f = 1/ [ 2 * 3,14 * R*C] = 1/[2 * 3.14 * 3k9 * 4n7] = 8,69 kHz </b></span></div>
<div>
<br /></div>
<div>
The filter itself:</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-rUspmonQsKw/UnzxeQWVpdI/AAAAAAAAATY/2PP81CpzPe4/s1600/pwm_filter.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-rUspmonQsKw/UnzxeQWVpdI/AAAAAAAAATY/2PP81CpzPe4/s1600/pwm_filter.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PWM filters for both PWM channels</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-6SLs8ZgkNKs/UnzmLMUaSVI/AAAAAAAAAS4/WUJzyc2mQiY/s1600/IMG_2136.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-6SLs8ZgkNKs/UnzmLMUaSVI/AAAAAAAAAS4/WUJzyc2mQiY/s1600/IMG_2136.JPG" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PWM filters on the breadboard.</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
<h3>
Software</h3>
<br />
As mentioned the software is more or less identical as for the R-2R ladder. It has only been enhanced to support conversion into couple of different formats instead of one (8kHz, 8 bit) and the baudrate has been increased to 230400 bps. As previously everything is done in binary manner to squeeze out everything that the USART can provide. The PWM configuration is being done by the libpca functions, there's no need to go into details about that, all the settings are standard, nothing extra out of ordinary. The timer is by defauilt configured into Phase & Frequency correct PWM mode, but it's possible to play with this setting in the code to compare the quality.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>#if MODE == MODE_8K_16B</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>/* tpwm_fpwm_init(E_TIMER1, E_PWM_DOUBLE); */</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>tpwm_pwm_init(E_TIMER1, E_PWM_DOUBLE);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#else</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>/* tpwm_fpwm_init(E_TIMER1, E_PWM_SINGLE); */</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>tpwm_pwm_init(E_TIMER1, E_PWM_SINGLE);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>#endif</b></span></div>
<div>
<br /></div>
<h3>
How to use it</h3>
<div>
<br /></div>
<div>
On the PC side, as previously one should use the <span style="font-family: Courier New, Courier, monospace;">player.sh </span>script. The syntax has been changed slightly. The first argument is the mode, the rest are the audio files</div>
<div>
<br /></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace;">player.sh <16b | 16k | 8k | 18k> <audiofile(s)></span></b></div>
<div>
<br /></div>
<div>
The options are self explaining I think, In order to use the 16 kHz mode we should invoke the script like this:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>./player.sh 16k myfile.mp3</b></span></div>
<div>
<br /></div>
<div>
One must remember to adjust the Arduino's serial port name in the <span style="font-family: Courier New, Courier, monospace;">wpwm.pl</span> script accordingly if needed.</div>
<div>
<br /></div>
<div>
On the Arduino side, we must select the mode which we want to try by adjusting the <span style="font-family: Courier New, Courier, monospace;">MODE</span> macro in <span style="font-family: Courier New, Courier, monospace;">main.c</span> file (as mentioned previously). After compiling and flashing the firmware, one should be able to successfully use the player script in order to hear some music. </div>
<div>
<br /></div>
<div>
I connect my Arduino directly to the MIC-IN of my laptop in order to record the sound - I don't use any amplifiers whatsoever.</div>
<div>
<br /></div>
<div>
The software as usual is available either as a snapshot from <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/dac.tgz" target="_blank">here</a> (containing libpca snapshot and the project itself) or it can be clones from my github repositories:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_ArduinoProjects projects</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>cd projects/dac</b></span></div>
<div>
<br /></div>
<div>
Building & flashing:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>make</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>make install</b></span></div>
<div>
<br /></div>
<div>
Let's hear some music finally</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Just as expected the difference between 8 and 16 bits is almost unrecognizable. Only at the begining when the dynamic is quite low, the noise level for 16 bits is signifficantly lower. The most spectacular change comes along with the sampling rate - the higher the better.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/XLm-QY0Bmno?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<br />
Throughout the clip some glitches are noticable from time to time - they're the result of corrupted frames (CRC does not match) or simply the fact that the data was not delivered on time (18 kHz mode). In 18 kHz the USART is really operating on it's limit (as well as the CPU - which must service the RX interrupt), I mostly wanted to demonstrate that it's possible to go that high, but the audio is far more stable and less glitchy in 16 kHz mode.</div>
<div>
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-36319069540065827522013-11-02T12:55:00.004-07:002013-11-04T00:30:12.182-08:00Arduino R-2R ladder Audio DAC<div style="text-align: justify;">
There is a lot of projects out there which use <span style="font-family: Courier New, Courier, monospace;">R-2R</span> ladder and an Arduino to recreate sounds from either SD card or short audio clips programmed directly to <span style="font-family: Courier New, Courier, monospace;">MCU's</span> flash memory. Although using SD card is fairly reasonable and provides a lot of flexibility it's not very challenging (from the software point of view) and it requires some additional hardware. Believe it or not we already have all the needed hardware in the Arduino itself.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Assumptions</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
In this project I'll play mp3 or any other multimedia files from the PC using Arduino. Bellow are the details:</div>
<div style="text-align: justify;">
</div>
<ul>
<li>Play PCM 8kHz 8bit Audio with Arduino</li>
<li>Audio samples will be transfered via <span style="font-family: Courier New, Courier, monospace;">USART</span> from the PC in binary format using <span style="font-family: Courier New, Courier, monospace;">SLIP</span></li>
<li>Audio files will be decoded on the PC side and only the <span style="font-family: Courier New, Courier, monospace;">RAW</span> data will be send to Arduino</li>
</ul>
<h3>
</h3>
<h3>
</h3>
<h3>
Timing</h3>
<div>
<br /></div>
<div>
<div style="text-align: justify;">
Arduino is a powerful machine, powerful enough that it's possible to play audio with even higher sampling rates and bit-resolutions than assumed above, the bottleneck in this case is the Serial Port. Assuming that I'll use the highest standard <span style="font-family: Courier New, Courier, monospace;">USART</span> speed available which is 115200 bps (8 data bits one start bit and stop bit = 10 bits to send a byte) it's possible to send up to 11520 bytes per second. In order to play a second of 8 kHz 8 bit Audio I need to have at least 8 kB of data. So the <span style="font-family: Courier New, Courier, monospace;">USART</span> is around 30% faster as a data producer than the audio samples consumption rate, which means that 8kHz standard sampling rate is the highest I can get. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The timing is crucial thing in this project. The data must be buffered but what kind of buffer do I need to have ? At first I thought that the bigger the better, but that's not exactly true. Accordingly to assumptions in implementation of the SLIP protocol in <a href="http://pcarduino.blogspot.co.uk/2013/10/transmitterreceiver-synchronization.html" target="_blank">libpca</a>, one SLIP frame can carry up to 256 bytes of data, we must not forget that this transfer is not instantaneous it takes time and we're in the middle of the playback not really knowing (at the PC side) how much audio samples have already been consumed (the consequence is that it's hard to tell how much space is available in the buffer). If the buffer at Arduino side doesn't have enough data to hold the new upcoming chunk - the data will be lost and we'll hear an audio glitch - and that situation for sure will happen since we're sending faster than consuming. </div>
<br />
First approach that came to my mind is to simply wait after each data block in order to be sure that there will always be enough space in the buffer (since most of the data will be consumed). Let's think about it for a moment and evaluate some rough timing calculations.<br />
<br />
<ul>
<li>playing 256 samples takes 1/8000 * 256 = 32 ms</li>
<li>sending 256 samples takes 256 + 2 (SLIP END characters) / 11520 = 22 ms </li>
</ul>
<br />
<span style="text-align: justify;">The second calculation does not take into consideration any additional <span style="font-family: Courier New, Courier, monospace;">SLIP ESCAPE</span> characters that may be included. But more or less I have a 10 ms I can wait after sending the chunk before sending another one, right ? WRONG. Those calculations do not consider that during those 22 ms when we were sending the data already something around 176 samples have been played (68% of the data). OK, so if I'll wait 32%*10ms = 3.2 ms then it should be fine, right ? WRONG again. By waiting, everything that is done is only hopelessly trying to make the data transfer speed equal to the audio consumption rate. It's impossible to synchronize ideally those two independent processes since there are so many factors that can have it's influence on the timing that all the efforts by definition have simply no point. If the sending rate will be too low, the audio will be chopped since there will be gaps in the playback, if the data will come too fast, there will be no space available and will have drop the data from time to time.</span><br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
It's even worse. Let's look on the <span style="font-family: Courier New, Courier, monospace;">slip_recv</span> function prototype:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>uint8_t slip_recv(uint8_t *a_buff, uint8_t a_buflen);</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
It takes a pointer to a buffer for the incoming data, since this is a transmission buffer it can't be used to realize another transmission until the data is completely consumed. That means that after the reception we must COPY the data from the frame to the proper audio buffer. Which makes the timing COMPLETELY unpredictable with the required precision.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
How to cope with this situation then ? First of all we cannot afford to copy the data from one buffer to another - it's simply a waste of time and by clever memory organization this problem can be easily eliminated. The playback must be done from the transmission buffer directly. But how to perform the transmission and audio playback using the same buffer in the same time ? It's actually pretty easy. Have a look:</div>
</div>
<div>
<br />
<script src="https://gist.github.com/dagon666/7237860.js"></script>
</div>
<div>
I have four transmission buffers (let's call them buffer banks) each of them holding 64 samples. The audio will be played directly from the samples table. The beauty of the picked size is that</div>
<br />
<b>64 * 4 = 256</b><br />
<br />
which means that the audio data can be addressed using a single byte, the following way:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>sample = p[(g_tail >> 6) & 0x03].samples[g_tail & 0x3f];</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>g_tail++;</b></span><br />
<br />
Since <span style="font-family: Courier New, Courier, monospace;">g_tail </span>is an 8 bit variable 2 upper bits select the "<span style="font-family: Courier New, Courier, monospace;">bank</span>" (0-3), and the rest, addresses the audio data (0 - 63). I address both the buffer bank and the audio data with a single variable. It more or less looks like using a single continuous buffer.<br />
<br />
When receiving data I track which buffer bank is free (1-4) and I write to it. The playback happens from the previous buffers. If there is no free buffer available I send a "<span style="font-family: Courier New, Courier, monospace;">WAIT</span>" command to the PC so it can wait a little while (a time shorter than the time needed to consume 3 buffers = 192 audio samples, basically the time must be longer than 8 ms (consume 64 bytes = 1 bank) and shorter than 24 ms). I chose 1,9 ms which lasts for around 15 audio samples. It's too short isn't it ? No it's not. Let's assume 2 ms of explicit waiting (due to the function inaccuracies) + time needed to receive the "<span style="font-family: Courier New, Courier, monospace;">WAIT</span>" string through the Serial Line: 350 us which already makes it let's say 2.5 ms not mentioning any other processing times and of course the time needed to transfer 64 bytes block >= 8 ms, which in total gives at least 10,5 ms. Of course the time is much more longer (<span style="font-family: Courier New, Courier, monospace;">SLIP</span> special characters have not been taken into consideration and as mentioned indeterminable processing time has been omitted as well).<br />
<br />
The transmission/consumption process is depicted bellow:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://1.bp.blogspot.com/-HiOZzXPs144/UnFXgohdoeI/AAAAAAAAAQ0/noBselj0L5E/s1600/data_transmission.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://1.bp.blogspot.com/-HiOZzXPs144/UnFXgohdoeI/AAAAAAAAAQ0/noBselj0L5E/s1600/data_transmission.png" height="640" width="392" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Transmission of binary frames through the Serial Port and new data placement in the Arduino's buffers.</td></tr>
</tbody></table>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<h3>
Playback</h3>
<br />
Let's talk about how to play the samples ? I use timer in <span style="font-family: Courier New, Courier, monospace;">CTC</span> mode and play the samples by placing them on the port directly, but again there's a little catch here as well. The only "full" 8 bit port available on Arduino is <span style="font-family: Courier New, Courier, monospace;">PORTD</span>, unfortunately we can't use it's two lower <span style="font-family: Courier New, Courier, monospace;">PINS</span> 0,1 since they are shared with <span style="font-family: Courier New, Courier, monospace;">USART</span> and I'm using <span style="font-family: Courier New, Courier, monospace;">USART</span> as a data source. Because of that The bottom part of the byte (bits 0 - 5) is placed on <span style="font-family: Courier New, Courier, monospace;">PINS</span> 2-7 of <span style="font-family: Courier New, Courier, monospace;">PORTD</span> and the remaing two most significant bits (6 - 7) are placed on the adjacent <span style="font-family: Courier New, Courier, monospace;">PORTB</span>. This may have an influence on the audio quality since placing the data on two ports is not an atomic operation - first we place one piece of data - which in effect generates some sort of voltage on the R-2R output, then we place the remaining piece of data on the other port - this will probably generate a high frequency glitch for every sample. Have a look on the schematics.<br />
<br />
<br />
<h3>
R-2R Ladder</h3>
<br />
A word about the Ladder itself. I chose a value of R = 5k. I had more in mind the 2R value = 10k which is the standard one. I had 4k7 resistors laying near hand so I decided to use them. It wasn't a good idea. The R-2R relation must be as good as possible. It's best to use the same resistors for both R and 2R and connect two of them in parallel to form a R value, so in my case R = 5k (two 10k connected in parallel) and 2R = 10k. I took some measurements using Arduinos <span style="font-family: Courier New, Courier, monospace;">ADC</span> (the R-2R ladder output connected to the <span style="font-family: Courier New, Courier, monospace;">ADC</span>) and below are the results. It's pretty visible that using 4,7k and 10k for R-2R ladder is a bad idea.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-KCmGgP9BJZI/UnFk5LCEDGI/AAAAAAAAARE/kfh6WPWJuyg/s1600/r2r_4k7.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-KCmGgP9BJZI/UnFk5LCEDGI/AAAAAAAAARE/kfh6WPWJuyg/s1600/r2r_4k7.png" height="223" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">R-2R = 4k7-10k Ladder signal response (sawtooth).</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-usMrzRUpXSs/UnFmXpUjrpI/AAAAAAAAARQ/Y1q0LLWSccI/s1600/r2r_4k7_sine.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-usMrzRUpXSs/UnFmXpUjrpI/AAAAAAAAARQ/Y1q0LLWSccI/s1600/r2r_4k7_sine.png" height="223" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">R-2R = 4k7-10k Ladder signal response (sine wave).</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-lnPizD4DYfc/UnFn2Xz0aYI/AAAAAAAAARc/tSw6Tr6pQ5g/s1600/r2r_5k_sine.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-lnPizD4DYfc/UnFn2Xz0aYI/AAAAAAAAARc/tSw6Tr6pQ5g/s1600/r2r_5k_sine.png" height="253" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Major differences when using two 10k in parallel as 5k.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-C_bdP2m09hc/UnFn4Mf3qVI/AAAAAAAAARk/Lxiky33mnoo/s1600/r2r_5k_sine_detailed.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-C_bdP2m09hc/UnFn4Mf3qVI/AAAAAAAAARk/Lxiky33mnoo/s1600/r2r_5k_sine_detailed.png" height="271" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">"Steps" visible anyway - the curve magnified.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-3Q_gz8mVHr8/UnKou2Scp6I/AAAAAAAAAR0/MZFp5qATq7s/s1600/IMG_2043.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-3Q_gz8mVHr8/UnKou2Scp6I/AAAAAAAAAR0/MZFp5qATq7s/s1600/IMG_2043.JPG" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">R-2R Ladder with 4k7 and 10k resistors. Work in progress.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-IJg34ciZ8Q8/UnKovXdL89I/AAAAAAAAAR4/8GWE0K3-GNY/s1600/IMG_2045.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-IJg34ciZ8Q8/UnKovXdL89I/AAAAAAAAAR4/8GWE0K3-GNY/s1600/IMG_2045.JPG" height="266" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">R-2R Ladder with 10k restistors connected in parallel.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-nS_iiS_QsI4/UnQJ2sQe1NI/AAAAAAAAASM/KoiAEZiVqvA/s1600/r2r_ladder.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-nS_iiS_QsI4/UnQJ2sQe1NI/AAAAAAAAASM/KoiAEZiVqvA/s1600/r2r_ladder.png" height="318" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">R-2R Ladder Schematics.</td></tr>
</tbody></table>
<br />
<h3>
The source code.</h3>
<h4>
Arduino Side</h4>
<br />
Arduino program is pretty simple. I already mentioned that samples are played in the timer interrupt. Besides that a standard data collection algorithm happens in the while loop in a very similar fashion to the one from the Arduino MIDI player.<br />
<br />
The function collecting the samples, takes a pointer to the destination buffer. The buffer is selected from four available by using 2 most significant bits of the <span style="font-family: Courier New, Courier, monospace;">g_head</span> counter. <span style="font-family: Courier New, Courier, monospace;">g_head</span> & <span style="font-family: Courier New, Courier, monospace;">g_tail</span> indexes realize a queue on the buffers. The <span style="font-family: Courier New, Courier, monospace;">g_tail</span> is incremented by the timer interrupt whenever new sample is played. The <span style="font-family: Courier New, Courier, monospace;">g_head</span> is incremented along with new data received. As long as <span style="font-family: Courier New, Courier, monospace;">g_tail</span> != <span style="font-family: Courier New, Courier, monospace;">g_head</span> I know that there is still data available in the buffers.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>serial_collect_samples((void *)&p[(g_head >> 6) & 0x03]);</b></span><br />
<br />
A word about the sample collect function<br />
<br />
<script src="https://gist.github.com/dagon666/7237955.js"></script>
<br />
<div>
<br />
First thing is to check if number of available samples is higher than 192 (3 banks) if yes, then the "<span style="font-family: Courier New, Courier, monospace;">WAIT</span>" command is send, to tell the PC side to refrain from sending new data for a while. The <span style="font-family: Courier New, Courier, monospace;">slip_recv</span> call is blocking. It will block until new data has been collected, after <span style="font-family: Courier New, Courier, monospace;">CRC</span> verification and making sure that the data is genuine the <span style="font-family: Courier New, Courier, monospace;">g_head</span> index is incremented by the number of samples received in the frame.<br />
<br />
<h4>
PC Side</h4>
<br />
Perl script is responsible for feeding Arduino with data. This script accepts a 8 kHz 8 bit WAVE file as an input. It's pretty straight forward and similar to previous script for the Arduino MIDI player. First it initialize the Serial port, then it tries to open the WAVE file and read it's header. After that is successful I read 44 bytes of header and unpack them.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>die "Unable to read WAV header\n" </b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> unless($offset = read $g_fh, $header, 44);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b>my @header = unpack "a4la4a4ls2l2s2a4l", $header;</b></span><br />
<br />
It get's more sense if you look on the WAVE file header:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-5IpfLS166hY/UnFV4ysOq9I/AAAAAAAAAQo/Q-ZQ2g_ybws/s1600/wav-sound-format.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-5IpfLS166hY/UnFV4ysOq9I/AAAAAAAAAQo/Q-ZQ2g_ybws/s1600/wav-sound-format.gif" height="370" width="400" /></a></div>
<br />
<br />
So, the unpack call extracts <span style="font-family: Courier New, Courier, monospace;">RIFF</span> file id, the <span style="font-family: Courier New, Courier, monospace;">WAVE</span> file format and the rest of the header fields. The purpose is to detect if it's a <span style="font-family: Courier New, Courier, monospace;">WAVE</span> file and if it has the only compatible sampling rate and bit rate. Once that is confirmed, the script goes to the "transfer loop". If there is no "<span style="font-family: Courier New, Courier, monospace;">WAIT</span>" command received from Arduino it simply reads the 64 byte data chunk from the file and feeds the Arduino. If "<span style="font-family: Courier New, Courier, monospace;">WAIT</span>" has been received, the script will wait for around 2 ms (1900 us). The loop continues until the whole file is processed. The frame contains two bytes of <span style="font-family: Courier New, Courier, monospace;">CRC</span>, one byte indicating how many samples it conveys and the samples themselves.<br />
<br />
Although it's completely fine to use this script directly I use it in a wrapper (I could've made everything in the single script, but I was too lazy :)). The "player.sh" shell script accepts any audio format as an input it uses sox to convert the provided audio file to an intermediate <span style="font-family: Courier New, Courier, monospace;">WAVE</span> file which then will be provided to Perl in order to be played by Arduino. It's a lot more useful than converting the files manually every time.<br />
<br />
<h3>
How to use it ?</h3>
<br />
The whole project snapshot can be obtained <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/r2r_dac.tgz" target="_blank">here</a>. One can fetch the newest version of <span style="font-family: Courier New, Courier, monospace;">libpca</span> and the project itself from my public GitHub repository as well. The snapshot and the GitHub version have a slightly different Makefile, paths to the <span style="font-family: Courier New, Courier, monospace;">libpca</span> are a little bit different, everything else is exactly the same.<br />
<br />
<h4>
GitHub</h4>
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_ArduinoProjects projects</b></span><br />
<br />
The project resides under dac directory. After navigating to it. One should change the branch to <span style="font-family: Courier New, Courier, monospace;">r2r_dac</span>:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">git checkout -b r2r_dac origin/r2r_dac</span></b><br />
<h4>
</h4>
<h4>
Snapshot</h4>
<br />
Download and unpack the snapshot from <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/r2r_dac.tgz" target="_blank">here</a><br />
<br />
... the rest is common:<br />
<div>
<br /></div>
<div>
<div>
Build and flash the Arduino firmware:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>cd projects/dac</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>make</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>make install</b></span></div>
<div>
<br /></div>
<div>
Launch the player.sh script with an audio file as a parameter:</div>
</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>$ ./player.sh audio.mp3</b></span></div>
<div>
<br /></div>
<h3>
The Presentation</h3>
<br />
Finally we can play some audio. The video presents an Arduino playing mp3 of my metal project Tangible Void - you can check it out on youtube - <a href="http://www.youtube.com/user/TangibleVoid/videos" target="_blank">here</a>.<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/vmJDBtalEjs?feature=player_embedded' frameborder='0'></iframe></div>
<br /></div>
<div>
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com3tag:blogger.com,1999:blog-4146080941178349095.post-52659035858998347642013-10-26T02:48:00.000-07:002013-10-26T02:49:16.320-07:00Arduino MIDI Music Box<div style="text-align: justify;">
It's time to do something useful with our small 8-bit computer. Music box is a fun and easy project. It's not demanding from the hardware point of view but it can be a little bit tricky from the software point of view itself - ideal project to learn a lot and not to spend the whole day soldering. What we will need: </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li>an Arduino (of course) </li>
<li>Piezo buzzer</li>
</ul>
<br />
<div style="text-align: justify;">
... and that's all. Now a couple of words of what we want to achieve. </div>
<div style="text-align: justify;">
<br /></div>
<h3>
Requirements </h3>
<div>
<br /></div>
<div style="text-align: justify;">
Let's point them out:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li>play monophonic melodies by generating tones (1 channel MIDI instrument)</li>
<li>the notes will be send by the PC through the serial port </li>
<li>our musicbox should be visible to the PC as a MIDI port </li>
<li>be able to use MIDI player of choice on PC to play MIDI files on our musicbox </li>
</ul>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The requirements are specified. Unlike most of the simple projects around which play the same melody everytime, which most of the times is hardcoded in the program memory and in order to change it one must modify the tone frequencies and the timing between them and then re-flash the Arduino, our musicbox will simply act as a simple MIDI device and become a "MIDI sink" for incoming serial data. That means that more or less we can play any MIDI file with it that comes in our hands. The only limitation is the number of channels - the firmware which I'm going to discuss will play only one - the user will have to select what channel data should be send & played, but in general it's not impossible to enhance the implementation to support more, for demonstration purposes one is enough though. </div>
<div style="text-align: justify;">
<br /></div>
<h3>
Technologies </h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I need to discuss what kind of tools and technologies will be used. No matter how trivial a musicbox can look in the first place there will be quite a lot going on under the hood. Here are the things that will be used (in terms of software) on the Arduino side: </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li>beeper module from libpca - the timer will be used for tone generation </li>
<li>SLIP module from libpca - the data will be send in binary format in SLIP frames from PC to the Arduino </li>
</ul>
<br />
<div style="text-align: justify;">
Everything has been already covered in my previous posts on this blog. If you're following the blog any of the above require no explanation. At the time being creating a more sophisticated project like this one is only a matter of putting the building blocks together.
On the PC side I will use Perl to do the dirty work. No matter what you have heard or have been told, Perl is a great language far more superior than Python and I hope that again I'll prove it to every of you. Things that will be needed: </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<ul>
<li>Device::SerialPort - serial port communication </li>
<li>MIDI::ALSA - for doing all the MIDI dirty work </li>
<li>Digest::CRC - to calculate CRC checksum of the outgoing data
PC side</li>
</ul>
<br />
<div style="text-align: justify;">
<br /></div>
<h3>
PC side</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let's start with the PC side first. The Perl script will register new MIDI port and wait for the data written to it which then will be send through the Serial port to Arduino - pretty simple. The data I'm interested in from the MIDI stream incoming are so called "<span style="font-family: Courier New, Courier, monospace;">note_on/note_off</span>" events. Unfortunately their not exactly in a format convenient and appropriate for this project. The note_on event defines the beginning of a particular not (a trigger to start generating tone of given key), we should stop generation when receiving note_off. This is not acceptable since it blocks possibility to generate any other tone in between and we would have to track when to really stop the generation on each incoming note_off event. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Fortunately enough again Perl and CPAN saves the day. The <span style="font-family: Courier New, Courier, monospace;">MIDI::ALSA</span> module defines a notion of "score" - a set of midi tracks in which every event has it's own length defined, so instead of two events <span style="font-family: Courier New, Courier, monospace;">note_on/note_off</span> we have only one - note, which provides the following information:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>{'note', start_time, duration, channel, note, velocity}</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Exactly what we need. The bad news is that it doesn't work very well. In fact it seems that duration has some constantly increasing value along with the position in the MIDI file and in result isn't very useful at all, but at least instead of processing two events we have only one. From the data above I'm interested only in the event type -> '<span style="font-family: Courier New, Courier, monospace;">note</span>' the '<span style="font-family: Courier New, Courier, monospace;">note</span>' itself of course and the channel - I'll filter the data from one or couple of channels only to be send and played by Arduino since it would produce a complete chaos if we would want to try to play everything using only one instrument at once.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Since we will be sending the frequency to the Arduino, we need to convert the MIDI note number <span style="font-family: Courier New, Courier, monospace;">(0-127)</span> into frequency domain. After doing a quick Google search for MIDI note frequencies I come up declaring the following array:</div>
<div style="text-align: justify;">
<br /></div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"># midi notes<br />my @notes = (<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>8.1757989156,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>8.6619572180,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>9.1770239974,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>10.3008611535,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>10.3008611535,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>10.9133822323,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>11.5623257097,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>12.2498573744,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>12.9782717994,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>13.7500000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>14.5676175474,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>15.4338531643,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>16.3515978313,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>17.3239144361,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>18.3540479948,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>19.4454364826,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>20.6017223071,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>21.8267644646,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>23.1246514195,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>24.4997147489,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>25.9565435987,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>27.5000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>29.1352350949,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>30.8677063285,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>32.7031956626,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>34.6478288721,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>36.7080959897,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>38.8908729653,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>41.2034446141,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>43.6535289291,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>46.2493028390,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>48.9994294977,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>51.9130871975,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>55.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>58.2704701898,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>61.7354126570,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>65.4063913251,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>69.2956577442,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>73.4161919794,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>77.7817459305,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>82.4068892282,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>87.3070578583,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>92.4986056779,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>97.9988589954,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>103.8261743950,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>110.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>116.5409403795,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>123.4708253140,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>130.8127826503,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>138.5913154884,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>146.8323839587,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>155.5634918610,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>164.8137784564,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>174.6141157165,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>184.9972113558,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>195.9977179909,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>207.6523487900,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>220.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>233.0818807590,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>246.9416506281,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>261.6255653006,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>277.1826309769,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>293.6647679174,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>311.1269837221,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>329.6275569129,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>349.2282314330,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>369.9944227116,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>391.9954359817,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>415.3046975799,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>440.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>466.1637615181,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>493.8833012561,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>523.2511306012,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>554.3652619537,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>587.3295358348,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>622.2539674442,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>659.2551138257,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>698.4564628660,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>739.9888454233,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>783.9908719635,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>830.6093951599,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>880.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>932.3275230362,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>987.7666025122,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_046.5022612024,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_108.7305239075,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_174.6590716696,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_244.5079348883,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_318.5102276515,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_396.9129257320,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_479.9776908465,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_567.9817439270,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_661.2187903198,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_760.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_864.6550460724,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>1_975.5332050245,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_093.0045224048,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_217.4610478150,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_349.3181433393,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_489.0158697766,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_637.0204553030,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_793.8258514640,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>2_959.9553816931,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>3_135.9634878540,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>3_322.4375806396,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>3_520.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>3_729.3100921447,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>3_951.0664100490,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>4_186.0090448096,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>4_434.9220956300,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>4_698.6362866785,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>4_978.0317395533,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>5_274.0409106059,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>5_587.6517029281,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>5_919.9107633862,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>5_919.9107633862,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>6_644.8751612791,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>7_040.0000000000,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>7_458.6201842894,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>7_902.1328200980,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>8_372.0180896192,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>8_869.8441912599,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>9_397.2725733570,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>9_956.0634791066,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>10_548.0818212118,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>11_175.3034058561,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>11_839.8215267723,<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>12_543.8539514160,<br />); # notes</span></blockquote>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Great, one problem less. </div>
<div style="text-align: justify;">
<br /></div>
<h3>
The MIDI sequencer</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
A MIDI sequencer must be registered on the PC side to provide an output for MIDI playback software. It's extremely easy with <span style="font-family: Courier New, Courier, monospace;">MIDI::ALSA</span> module and Perl:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: 'Courier New', Courier, monospace;"><b>MIDI::ALSA::client('Arduino MIDI Beeper', 1, 1, 0);</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
and that's all. I register a new sequencer with one input port and one output port. We can already see it in the system:</div>
<div style="text-align: justify;">
<br /></div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><b>$ aconnect -oil</b></span><span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span><span style="font-family: Courier New, Courier, monospace;"><b>client 0: 'System' [type=kernel]</b></span><span style="font-family: Courier New, Courier, monospace;"><b> 0 'Timer '</b></span><span style="font-family: Courier New, Courier, monospace;"><b> 1 'Announce '</b></span><span style="font-family: Courier New, Courier, monospace;"><b>client 14: 'Midi Through' [type=kernel]</b></span><span style="font-family: Courier New, Courier, monospace;"><b> 0 'Midi Through Port-0'</b></span><span style="font-family: Courier New, Courier, monospace;"><b>client 128: 'Arduino MIDI Beeper' [type=user]</b></span><span style="font-family: Courier New, Courier, monospace;"><b> 0 'Input port '</b></span><span style="font-family: Courier New, Courier, monospace;"><b> 1 'Output port '</b></span></blockquote>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Ok, we are almost done, all that's left is to take the MIDI data and send it to Arduino. Let's analyze the main program loop, again there will be some Perl trickery but I'll try to de-crypt everything which is not obvious to everyone not very familiar with Perl.</div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/7029630.js"></script>
</div>
<div style="text-align: justify;">
<div>
The call to <span style="font-family: Courier New, Courier, monospace;">MIDI::ALSA::input()</span> is blocking, it means that we will wait on the first line for the MIDI event before we'll send anything to the Arduino - that's a good thing, that way we do not have to worry about the timing, the notes will be played as soon as they arrive. Next I detect if the incoming event does not define the MIDI file end - I exit the loop if that's the case. </div>
<div>
<br /></div>
<div>
Next thing is to convert the MIDI event to a "score event". Next two lines simply skip to another loop roll if the event does not contain any useful information (it's either empty or it's not a 'note' event). Just for the debugging purposes I dump the event to the console. Going further I filter the events (by skipping them) if in the command line channels to be player are specified, if not then data from every channel will be sent. Later on I simply convert the MIDI note to frequency and because of the problems with getting the reliable event 'duration' information from <span style="font-family: Courier New, Courier, monospace;">MIDI::ALSA</span> I simply define a fixed duration for every note in milliseconds (50 in this example). Next the data is being placed in the <span style="font-family: Courier New, Courier, monospace;">SLIP</span> frame and sent to Arduino to be played. Arduino should return the data back (again just for debugging purposes) - and that's all.</div>
<div>
<br /></div>
<h3>
Arduino Side</h3>
<div>
<br /></div>
<div>
Basically all the hard work has been already done and is hidden in <span style="font-family: Courier New, Courier, monospace;">libpca</span>. Please refer to my previous posts for more details, since every aspect and function used for this mini project has been already thoroughly discussed. </div>
<div>
<br /></div>
<div>
Arduino firmware will be very simple, all that needs to be done is to simply receive the SLIP frame, verify it and play the note inside. Let's have a look on the message format first.<br />
<br />
<script src="https://gist.github.com/dagon666/7029686.js"></script>
Each note is defined as a pair of numbers - frequency and the duration. Each packet coming from the host contains the <span style="font-family: Courier New, Courier, monospace;">CRC16</span> checksum, a byte denoting how many notes have been sent and the notes themselves. I decided that in a single packet it will be possible to send up to four notes - that would require some timing information for each note itself so even though it's possible to sent up to 4 notes in one shot in the final version of this project I'm always sending only one.<br />
<br />
The listing bellow present a complete source for the Arduino firmware.<br />
<br />
<script src="https://gist.github.com/dagon666/7029749.js"></script>
<br />
In the while loop it wait's for a new SLIP frame, verify the data integrity and play the notes from the packet. After flashing the Arduino we can finally do some tests.<br />
<br />
<h3>
How to use it ?</h3>
<br />
The whole project snapshot can be obtained here. One can fetch the newest version of <span style="font-family: Courier New, Courier, monospace;">libpca</span> and the project itself from my public <a href="https://github.com/dagon666/avr_Libpca" target="_blank">GitHub</a> repository as well. The snapshot and the GitHub version have a slightly different Makefile, paths to the <span style="font-family: Courier New, Courier, monospace;">libpca</span> are a little bit different, everything else is exactly the same. </div>
<div>
<br /></div>
<div>
<h4>
GitHub</h4>
<div>
<br /></div>
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_ArduinoProjects projects</b></span><br />
<br />
<h4>
Snapshot</h4>
<br />
Download and unpack the snapshot from <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/musicbox.tgz" target="_blank">here</a><br />
<br />
<br />
... the rest is common:<br />
<br />
Build and flash the Arduino firmware:<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">cd projects/musicbox</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">make</span></b><br />
<b><span style="font-family: Courier New, Courier, monospace;">make install</span></b><br />
<br />
Launch the <span style="font-family: Courier New, Courier, monospace;">mid_converter.pl</span> script (optionally provide channel numbers in the command line which will be played), get the sequencer details:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ aconnect -oil</span><br />
<br />
play your midi file using your player of choice (I'll use aplaymidi):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">aplaymidi -p 128:0 <midi_file></span><br />
<br />
<h3>
Musicbox in action </h3>
<br />
Now that everything has been said it's time to see the thing in action. I'm using Timer 0 and OC0A compare output (which is located on <span style="font-family: Courier New, Courier, monospace;">PORTD6</span> - <span style="font-family: Courier New, Courier, monospace;">Pin6</span> on Arduino) to which the buzzer is connected.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/M4pZ0iXUkyI?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<br />
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com1tag:blogger.com,1999:blog-4146080941178349095.post-38721078886034825452013-10-13T09:29:00.002-07:002013-10-13T09:29:37.698-07:00Transmitter/Receiver synchronization during binary transfers with SLIP protocol<div style="text-align: justify;">
<i>A word of warning, this post will be kind of long. I will try to cover the binary communication over serial port basics in 2 languages (C & perl), but I hope every one will bare with me until the end.</i></div>
<div style="text-align: justify;">
<i><br /></i></div>
<div style="text-align: justify;">
I'm almost ready to go into some of my "real" projects. In order to do that all that needs to be done is to talk a little about <span style="font-family: Georgia, Times New Roman, serif;">SLIP</span> protocol. SLIP protocol is used to synchronize data between receiver and transmitter on a serial line (not only <span style="font-family: Courier New, Courier, monospace;">RS232</span>, ethernet as well and many other mediums). <span style="font-family: Courier New, Courier, monospace;">SLIP</span> is one of the most commonly used option, the other one is <span style="font-family: Courier New, Courier, monospace;">Modbus RTU</span>, which describes some timing constraints and requirements during the data transfer. I haven't tried <span style="font-family: Courier New, Courier, monospace;">Modbus RTU</span> yet, since <span style="font-family: Courier New, Courier, monospace;">SLIP</span> is doing pretty good job for me. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
First of all why do we need to synchronize the data at all and what does it mean in details in the first place ? The reason for that is simple (maybe not so obvious in the first place). Consider the following situations:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>We want to send 8 bytes of binary data from A to B over Serial line:</b></div>
<br />
<div style="text-align: justify;">
</div>
<ul>
<li>B is not yet ready to listen for data</li>
<li>A already send the first byte</li>
<li>B become ready to receive data</li>
<li>A is sending more data</li>
<li>B received only 7 bytes out of 8. 1 byte has been LOST</li>
</ul>
<br />
<div style="text-align: justify;">
What comes to one's mind straight away when analyzing this example, let's force A to wait for some time so B for sure will become ready. Let's think about it:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>A sends 8 bytes of data in two packs to B:</b></div>
<div style="text-align: justify;">
</div>
<ul>
<li>A waits a second (waiting for B to become ready to receive)</li>
<li>B becomes ready to listen</li>
<li>A sends first pack (4 bytes of data) to B</li>
<li>B receives 4 bytes and process it</li>
<li>A sends another pack of 4 bytes</li>
<li>B has not finished processing of previous package and lost some of the data from the second pack</li>
</ul>
<br />
<div style="text-align: justify;">
As time decreases and transmission speeds are getting higher this leads to more and more problems. As long as we can get away with sending text data between peers without any kind of synchronization. It's very difficult to do that and to have a stable reliable binary data transfer without any. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">SLIP</span> is a very simple, almost primitive solution, which solve that kind of problem. I'm not going to duplicate the description here, please refer to the <a href="http://www.ietf.org/rfc/rfc1055.txt" target="_blank">rfc1055</a> for more details regarding it, briefly <span style="font-family: Courier New, Courier, monospace;">SLIP</span> defines two special characters: an <span style="font-family: Courier New, Courier, monospace;">END</span> byte and <span style="font-family: Courier New, Courier, monospace;">ESC</span> byte. Receiver knows about the end of the data stream by listening for an <span style="font-family: Courier New, Courier, monospace;">END</span> byte, when the data stream contains the <span style="font-family: Courier New, Courier, monospace;">END</span> or <span style="font-family: Courier New, Courier, monospace;">ESC</span> byte in it, then transmitter replaces it with the <span style="font-family: Courier New, Courier, monospace;">ESC</span> byte and the <span style="font-family: Courier New, Courier, monospace;">ESC_END</span> or <span style="font-family: Courier New, Courier, monospace;">ESC_ESC</span> byte - those are replaced to the valid data by the receiving side. That's all - as I mentioned it's very simple. <span style="font-family: Courier New, Courier, monospace;">SLIP</span> defines the exact values for <span style="font-family: Courier New, Courier, monospace;">END, ESC, ESC_ESC & ESC_END</span> but those can have any values - it doesn't really matter:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>/// 192 -> 0xc0</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_END 0300</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>/// 219 -> 0xdb</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_ESC 0333</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>/// 220 -> 0xdc</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_ESC_END 0334</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>/// 221 -> 0xdd</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_ESC_ESC 0335</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
For details of implementation (just as the protocol itself it is very simple), have a look into libpca (src/slip.c). One more thing must be mentioned, SLIP implementation from libpca can be used over many different links. One must only define the IO routines which will be used to retrieve data. Let's have a look on the fragment of slip.h header from the library:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/6951288.js"></script>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
By default libpca use the serial port IO routines, but this can be overridden if the user will provide it's own definition for symbols <span style="font-family: Courier New, Courier, monospace;">SLIP_CHAR_RECV/SLIP_CHAR_SEND</span>.</div>
<div style="text-align: justify;">
<div>
<br /></div>
<div>
Let's consider how we can use it, for that I'll define a simple software timer and a data model for our binary informations which will be exchanged on the serial line in order to modify the timer parameters. For the sake of simplicity we'll use LED on one of the port which will be toggled on every timer overflow. The "<span style="font-family: Courier New, Courier, monospace;">software timer</span>" is defined as follows:</div>
<div>
<br />
<script src="https://gist.github.com/dagon666/6951334.js"></script>
It's pretty simple we have the <span style="font-family: Courier New, Courier, monospace;">cnt</span> variable itself and the maximum (<span style="font-family: Courier New, Courier, monospace;">max</span>) value to which the timer can count, before being reseted to zero. Everything will get more obvious in the code using it. Let's define the data-model for the messages:<br />
<br />
<script src="https://gist.github.com/dagon666/6951360.js"></script>
</div>
</div>
<div style="text-align: justify;">
I use "<span style="font-family: Courier New, Courier, monospace;">packed</span>" attribute here. It is needed (especially for the host machine) to prevent the compiler from aligning the structure to the machine architecture size. It doesn't have any influence on Arduino since it's an 8-bit machine, but since the header is shared between Arduino and the host machine when trying to compile the code on host machine without "<span style="font-family: Courier New, Courier, monospace;">packed</span>" attribute applied to the structures probably size of struct timer_data would be 8 instead of 5 (alignment to the nearest 4-byte boundary, since most <span style="font-family: Courier New, Courier, monospace;">x86</span> are 32-bit machines). Of course the crc16 field is not mandatory in our communication, but just for demonstration purposes it's nice to know that if the data interchanged is really crucial it may be verified using CRC (I use crc16 but it's possible to use any other CRC32, CRC8, by default I decided to implement crc16 only in libpca). The host application will send new <span style="font-family: Courier New, Courier, monospace;">timer_data</span> structure with new setting to reprogram the timer and in result the blinking speed will change. One thing must be mentioned here, Arduino will reset itself after establishing the serial connection, it's because of the board design itself - one should not worry about that. This behavior can be disabled by disabling the jumper on Arduino UNO rev 3. board (there are plenty of solutions available in the web for different boards - I don't want to go into details here).<br />
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-ukUAOVVZlQg/UllxX8YI7II/AAAAAAAAAOM/CT_P9hqFsBQ/s1600/reset_pin.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-ukUAOVVZlQg/UllxX8YI7II/AAAAAAAAAOM/CT_P9hqFsBQ/s1600/reset_pin.png" height="308" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">This connection must be disabled in order to disable auto-reset on serial connect.</td></tr>
</tbody></table>
<b><br /></b>
<b><br /></b>
<br />
<h4>
Arduino Side</h4>
<br />
Let's have a look on the Arduino program first, and do a little walk-through:<br />
<br />
<script src="https://gist.github.com/dagon666/6955129.js"></script>
<br />
It looks pretty complicated at first glance but that's only the appearance. First of all the usual stuff, I configure <span style="font-family: Courier New, Courier, monospace;">Timer 0</span> to <span style="font-family: Courier New, Courier, monospace;">CTC</span> mode and unmask it's interrupt (one must remember to disable the Timer's 0 interrupt implementation in libpca - <span style="font-family: Courier New, Courier, monospace;">#define TDELAY_IMPLEMENT_T0_INT 0</span>, since we're defining our own custom handler). In the while loop, Arduino is waiting for a complete <span style="font-family: Courier New, Courier, monospace;">SLIP</span> frame, any junk frames (which size is smaller than the struct timer_data) are discarded, the last step is to verify the data checksum of the frame and to send a <span style="font-family: Courier New, Courier, monospace;">SLIP</span> frame containing <span style="font-family: Courier New, Courier, monospace;">struct response</span> with <span style="font-family: Courier New, Courier, monospace;">NACK</span> status in case the <span style="font-family: Courier New, Courier, monospace;">CRC</span> doesn't match. <span style="font-family: Courier New, Courier, monospace;">slip_verify_crc16()</span> takes the buffer, it's length and third argument which defines a position in the buffer of the <span style="font-family: Courier New, Courier, monospace;">CRC</span> checksum - in our case the <span style="font-family: Courier New, Courier, monospace;">CRC</span> is placed at the very beginning, so the position equals zero. If the <span style="font-family: Courier New, Courier, monospace;">CRC</span> verification is successful then at line 104 we can be sure that the data is genuine and not corrupted in communication. Next step is to reprogram the timer and finally send the <span style="font-family: Courier New, Courier, monospace;">SLIP</span> frame with<span style="font-family: Courier New, Courier, monospace;"> struct response</span> with <span style="font-family: Courier New, Courier, monospace;">ACK</span> status. This frame has a checksum calculated as well, and we will be able to verify it on the other side. The code is more or less straight forward.<br />
<br />
The conclusion is that the LED attached to the Arduino will blink with different speed, and the "timing" details are programmed remotely through the serial line and the binary messages exchanged using SLIP protocol.<br />
<br />
<h4>
</h4>
<h4>
Host side</h4>
<br />
We can now focus on discussing the details of the host application. To be honest writing an IO application to communicate through the serial port in C for the host machine is a little bit tedious and quite time consuming, that's why it is far more convenient and simply quicker to create such tool in a scripting language of choice (Perl, Python, Lua) since most of the dirty work has been already done under the hood. For the purpose of comparison and education I'll present a script in Perl which will talk to our Arduino as well as in C.<br />
<br />
Let's start with Perl since it's far more simpler and I believe it will be easier to understand.<br />
<br />
<h4>
</h4>
<h4>
Host Slip Communication in Perl</h4>
<br />
The biggest advantage of Perl over any other scripting language is CPAN and the amount of modules available. I'll use some of the already available building blocks in order to make my life a little bit easier. First of all we need to somehow use the Serial Port, the second thing is the CRC checksum calculation. We will need the following modules (they are available in Arch Linux package manager - which is my distro of choice, the package names are listed as well - those can be named similarly in your distribution):<br />
<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">Device::SerialPort (perl-device-serialport)</span></li>
<li><span style="font-family: Courier New, Courier, monospace;">Digest::CRC (perl-digest-crc)</span></li>
</ul>
<br />
We've got the tools, we can do the work finally. Let's have a look on the following code:<br />
<br />
<script src="https://gist.github.com/dagon666/6955339.js"></script>
<br />
For those who are not familiar with Perl it can be hard to get used to it. I'll try to be very verbatim. Starting from the top, the first interesting line is the declaration of hash <span style="font-family: Courier New, Courier, monospace;">%g_dev</span> which holds the details of the Arduino's Serial Port. Again, for those unfamiliar with Perl hashes are like associative arrays, next I define the SLIP special characters as constants. Next are two important subroutines which realize the communication. First of all, Perl does not define something like a structure and does not provide a direct access to the memory underlying the variables - just like in C, how can we talk then about binary data interchange in a format described previously by the C structures ? It happens in a little bit different way. Perl provides two functions pack/unpack to pack the variables into a string accordingly to the given template and to unpack the string to variables accordingly to the given template (please read the details in the perl documentation, <span style="font-family: Courier New, Courier, monospace;">perldoc -f pack, perldoc -f unpack, perldoc perlpacktut</span>). In order to make it more reasonable let's have a look on the <span style="font-family: Courier New, Courier, monospace;">struct timer_data</span> once again. We need to send a byte stream constructed the following way:<br />
<br />
<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">crc16</span> - unsigned short 16 bit variable - pack template: S</li>
<li><span style="font-family: Courier New, Courier, monospace;">prescaler</span> - unsigned char 8 bit variable - pack template C</li>
<li><span style="font-family: Courier New, Courier, monospace;">ocr</span> - unsigned char 8 bit variable - pack template C</li>
<li><span style="font-family: Courier New, Courier, monospace;">max_st</span> - unsigned char 8 bit variable - pack template C</li>
</ul>
<div>
<br />
That means that if we would write:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>my $data = pack ("SCCC", $crc, $prescaler, $ocr, $max_st);</b></span></div>
<div>
<br /></div>
<div>
or shorter:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>my $data = pack ("SC*", $crc, $prescaler, $ocr, $max_st);</b></span></div>
<div>
<br /></div>
<br />
the pack function will assemble our variables into a string which can be then directly send through the serial port. We need something more here, the SLIP_END characters, so the complete call could look like this:<br />
<br />
<b style="font-family: 'Courier New', Courier, monospace;">my $data = pack ("CSC*", (SLIP_END, $crc, $prescaler, $ocr, $max_st, SLIP_END));</b><br />
<b style="font-family: 'Courier New', Courier, monospace;"><br /></b>
That's exactly what is happening in the <span style="font-family: Courier New, Courier, monospace;">slip_send </span>subroutine. First the data passed to it is scanned for any SLIP special characters in order to escape them. Once that is done, the original data (unescaped) is passed to the crc16 function to calculate the checksum. A word about line 32. First a byte string is constructed containing two zeros in the beginning - which are a placeholder for the CRC, and the rest of the data. The placeholding zeros are replaced with actual CRC once it is calculated. The receiver will calculate the CRC the same way in order to verify the data. It will copy the received CRC from the frame to the temporary variable and zero it's bytes in the frame - now the frame is in the same state as on the transmitter side before the transmitter calculated the CRC. If that operation wouldn't have place of course the checksums would be different.<br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">slip_recv()</span> subroutine is exactly implemented the same way as in <span style="font-family: Courier New, Courier, monospace;">libpca</span>. One thing of explanation here, <span style="font-family: Courier New, Courier, monospace;">slip_recv() </span>has been implemented in more or less universal fashion - it takes a references to a <span style="font-family: Courier New, Courier, monospace;">getchar</span> routine (<span style="font-family: Courier New, Courier, monospace;">line 38</span>) which can be implemented over any kind of link. Next the command line input is parsed into global variables (<span style="font-family: Courier New, Courier, monospace;">lines 68-74</span>), the serial port is initialized (<span style="font-family: Courier New, Courier, monospace;">lines 76-84</span>) and we wait for 4 seconds. Now why is that ? As mentioned previously, after establishing a serial connection <span style="font-family: Courier New, Courier, monospace;">RS232</span> control lines will be toggled which in result will reset an Arduino, so we need to wait some time in order for Arduino to become ready and operational. By default (as it is visible in the code), the Arduino's Timer0 and Software timer will be initialized so the overflow happens with a frequency of ~ <span style="font-family: Courier New, Courier, monospace;">1 Hz</span>. The <span style="font-family: Courier New, Courier, monospace;">LED</span> will blink with that frequency until the <span style="font-family: Courier New, Courier, monospace;">SLIP</span> frame will be received with new configuration values for the timer. In <span style="font-family: Courier New, Courier, monospace;">lines 100-101</span> the <span style="font-family: Courier New, Courier, monospace;">SLIP</span> frame containing our binary data is send over the serial line next the script waits for the SLIP frame from Arduino containing the response. The <span style="font-family: Courier New, Courier, monospace;">struct response</span> is very simple, it contains only the CRC16 (2 bytes) and the status. It is unpacked after reception (line 107):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b># unpack the serialized data to variables</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>my ($crc, $status) = unpack("SC", $data);</b></span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b># calculate the checksum of the response for verification</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>my $crc_calcd = crc16(pack("SC", (0,$status)));</b></span><br />
<div>
<br /></div>
<div>
<div>
... and repacked again with CRC set to zero - the CRC is recalculated again for verification purposes. The last line simply presents the results.</div>
</div>
<div>
<br /></div>
<h4>
Host Slip Communication in C</h4>
<div>
<br /></div>
<div>
As far as our simple communication program was relatively short in Perl. We will have to dedicate much more effort in order to achieve the same in C (I imagine that everyone straight away lost their good mood now :)), but it's possible and sometimes it can be a better solution than any scripting language (small systems without any kind of interpreter available). Let's try to create functionally identical program in C. As previously we need some tools before we start</div>
<div>
<br /></div>
<div>
<ul>
<li>Serial Port IO and init routines</li>
<li>CRC16 implementation</li>
</ul>
<div>
The bad news is that we need to create those ourselves. Let's start with the CRC16 algorithm.<br />
<br />
<h4>
CRC16 checksum calculation</h4>
<br />
The best and most comprehensive source for any algorithm or data structure implementation is ... linux kernel. Yes, that's right, everything that you will probably ever need is already implemented there and tested, just have a look at kernel's <span style="font-family: Courier New, Courier, monospace;">lib/</span> directory and pick what you need. I'm sure it will be there. The crc16 implementation is there for sure, we need the <span style="font-family: Courier New, Courier, monospace;">crc16.c</span> file, slightly modified since we don't need the kernel specific stuff, have a look bellow:<br />
<br />
<script src="https://gist.github.com/dagon666/6963212.js"></script>
<br />
Next, the serial port IO and initialization.<br />
<br />
<h4>
Serial port initialization</h4>
<br />
Serial port is a <span style="font-family: Courier New, Courier, monospace;">tty</span> device, we need to initialize the speed, parity, flow control and other stuff through a termios API. I found this code some time ago and simply copy and paste it to my projects, there's no philosophy behind it, the<span style="font-family: Courier New, Courier, monospace;"> tty_attrib_conf() </span>initializes the port speed and other IO specifics, the <span style="font-family: Courier New, Courier, monospace;">tty_block_conf()</span> configure, whether the calls to <span style="font-family: Courier New, Courier, monospace;">read()</span> should block until the requested amount of data is collected. We will use the port by simply opening it (as like a file) and write/read to/from it using standard file IO API.<br />
<br />
<script src="https://gist.github.com/dagon666/6963233.js"></script>
<br />
The last thing is the SLIP implementation itself. Of course I'm not going to duplicate it for the host application. Since it is already implemented in the <span style="font-family: Courier New, Courier, monospace;">libpca</span> I'll use that implementation. Some preparations are needed though.<span style="font-family: Courier New, Courier, monospace;"> libpca SLIP</span> module expects to see <span style="font-family: Courier New, Courier, monospace;">common.h</span> header file and <span style="font-family: Courier New, Courier, monospace;">config.h</span> header file. We'll create dummy versions of those. <span style="font-family: Courier New, Courier, monospace;">config.h</span> will contain:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_IMPLEMENT_CRC16 0</b></span><br />
<div>
<br /></div>
<div>
to disable the CRC implementation - it relies on the functions from <span style="font-family: Courier New, Courier, monospace;">avr-libc </span>which of course are not available in libc/glibc for the standard GNU/Linux system. The <span style="font-family: Courier New, Courier, monospace;">common.h</span> will contain the overriden IO functions:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_CHAR_SEND(__x)<span class="Apple-tab-span" style="white-space: pre;"> </span>slip_sendc(__x)</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>#define SLIP_CHAR_RECV(__x) slip_getc(__x)</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>unsigned int slip_sendc(unsigned char a_char);</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>unsigned char slip_getc(unsigned char *a_data);</b></span></div>
<div>
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>unsigned int slip_sendc(unsigned char a_char) {</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>/* printf("Sending char: %02x\n", a_char); */</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>return write(g_fd, (void *)&a_char, 1);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<b style="font-family: 'Courier New', Courier, monospace;">unsigned char slip_getc(unsigned char *a_data) {</b><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span> unsigned char x = read(g_fd, a_data, 1);</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span> /* printf("Recv: %02x\n", *a_data); */</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span> return x;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span><br />
<br />
<br /></div>
</div>
<div>
The<span style="font-family: Courier New, Courier, monospace;"> slip_send</span> and <span style="font-family: Courier New, Courier, monospace;">slip_recv </span>functions in the host application will use those to perform IO. Of course we need a Makefile to solve the inclusion paths and to make the whole project compilable. Finally our C application to send the binary data will look the following way:</div>
<div>
<br />
<br />
<script src="https://gist.github.com/dagon666/6963468.js"></script>
</div>
<div>
<br /></div>
<div>
Let's shortly walk through the code. First I open and create the file descriptor for the serial port (lines: 14-17), next two lines configure the port attributes and set the port to blocking mode. Next 5 lines (22-27) simply set the data in the <span style="font-family: Courier New, Courier, monospace;">struct timer_data</span> which will be sent through the serial port to the Arduino. In line 30 and 31 the crc of the data packet is calculated and placed in the packet itself, finally on lines 42,43 and that's it.<br />
<br />
<h3>
How to use it ?</h3>
</div>
<div>
<br /></div>
<div>
That's really simple. In order to test the examples presented bellow one can obtain etheir a project snapshot from <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/binary_slip.tgz" target="_blank">here</a> - it contains a snapshot of <span style="font-family: Courier New, Courier, monospace;">libpca</span> and the source for the Arduino firmware (<span style="font-family: Courier New, Courier, monospace;">arduino_slip</span>) - simply navigate to this directory and type <span style="font-family: Courier New, Courier, monospace;">make</span> to build it and <span style="font-family: Courier New, Courier, monospace;">make install</span> to flash it to Arduino. On the host side one can use either the host_slip.pl Perl script or build the application in host_slip directory by typing <span style="font-family: Courier New, Courier, monospace;">make. </span><span style="font-family: inherit;">The application can be used the same way as host_slip.pl script.</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
It's possible to obtain all the sources from my public repositories from github in order to do that, one should</div>
<div>
<br /></div>
<div>
<ul>
<li>clone the newest version of libpca </li>
</ul>
<b><span style="font-family: Courier New, Courier, monospace;">git clone git@github.com:dagon666/avr_Libpca pca</span></b><br />
<ul>
<li>clone my Arduino projects repository </li>
</ul>
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_ArduinoProjects projects</b></span><br />
<ul>
<li>navigate to <span style="font-family: Courier New, Courier, monospace;">projects/binary_slip</span></li>
<li>build both <span style="font-family: Courier New, Courier, monospace;">arduino_slip</span> (remember to disable the <span style="font-family: 'Courier New', Courier, monospace;">TDELAY_IMPLEMENT_T0_INT </span>in libpca config.h file since we are defining our own custom interrupt handler) and <span style="font-family: Courier New, Courier, monospace;">host_slip</span> application</li>
</ul>
</div>
<div>
How to use the application ? After flashing the Arduino, regardless if we'll gonna use the perl script or the C app, the syntax is the same:</div>
<div>
<br /></div>
<div>
<div>
<b><span style="font-family: Courier New, Courier, monospace;">$ ./host_slip.pl </span></b></div>
<div>
<b><span style="font-family: Courier New, Courier, monospace;">host_slip.pl <prescaler> <ocr> <max_st></span></b></div>
</div>
<div>
<br /></div>
<div>
The first parameter is the prescaler value (0-5), the second one is the value which will be placed in the OCR, and the last is the maximum value for the software timer, by invoking:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>$ ./host_slip.pl 5 255 64</b></span></div>
<div>
<br /></div>
<div>
we'll program the timer to blink with a frequency around ~ 0.5 Hz. Experiment with the values. </div>
<div>
<br /></div>
<div>
I hope that this article shed some light on the aspects of binary data exchange between the Arduino and any other machine and I hope that it proved that it's not that very difficult. Next time I'll try to present a project using this knowledge to build some more useful stuff.</div>
<div>
<br /></div>
<br />
<br /></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-57802997696041516122013-10-08T14:04:00.003-07:002013-10-08T14:04:47.779-07:00Serial Port STDIO<div style="text-align: justify;">
In previous post I covered the basics of configuring and using the Atmega's <span style="font-family: Courier New, Courier, monospace;">USART</span> as a standard <span style="font-family: Courier New, Courier, monospace;">RS232</span> port. This post will be more a little addendum to the previous one. In our program of course we can manually send strings using the <span style="font-family: Courier New, Courier, monospace;">serial_send/serial_poll_send</span> routines, but we can use the serial port in more convenient and transparent way. If our application implements only some kind of CLI system or basically treats the serial IO as a Serial Console we can configure <span style="font-family: Courier New, Courier, monospace;">libc</span> to use our serial <span style="font-family: Courier New, Courier, monospace;">IO</span> routines for stdio functions like <span style="font-family: Courier New, Courier, monospace;">printf</span>. What we have to do is to create an input output file streams and instruct avr-libc to use those. Let's have a look at the code bellow:</div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/6891271.js"></script>
</div>
<div>
<div style="text-align: justify;">
The code refers to the serial <span style="font-family: Courier New, Courier, monospace;">IO</span> routines implemented by libpca. First of all <span style="font-family: Courier New, Courier, monospace;">_serial_putc/_serial_getc</span> are just a wrappers, interface adapters sort of speak, to adapt our serial IO API to the library's one. In <span style="font-family: Courier New, Courier, monospace;">serial_install_stdio()</span> we simply create two file streams, one to be used as <span style="font-family: Courier New, Courier, monospace;">STDOUT</span> (and associate the necessary output routine) and one for input. Next we assign our custom streams to the standard library stdio streams utilized all over the stdio library. And that's the whole magic. Those are the internals which can be used as a reference, let's have a look how it can be done with <span style="font-family: Courier New, Courier, monospace;">libpca</span>. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As usual, let's clone the newest version of the library and create a project directory:</div>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>mkdir serial_stdio</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>cd serial_stdio</b></span></div>
<div>
<br /></div>
<div>
<div>
Our example program looks as follows:
<br />
<br />
<script src="https://gist.github.com/dagon666/6891421.js"></script>
</div>
</div>
<div>
<br /></div>
<div>
After connecting to the Arduino's serial port (<span style="font-family: Courier New, Courier, monospace;">ttyACM0</span> in my case), we can see the output produced by printf(). That's great !<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>screen /dev/ttyACM0 9600</b></span></div>
<div>
<br /></div>
<div>
There is a small remark regarding the <span style="font-family: Courier New, Courier, monospace;">AVR libc printf</span> routines. Since we're talking about embedded device, the default implementation is very limited (in order to save program space) and does not support floats. When trying to print a float value, we'll see a <span style="font-family: Courier New, Courier, monospace;">'?'</span> instead of the number. We can enable the support for the floating point numbers though, by explicitly providing a linker flags (<a href="http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1" target="_blank">avr libc stdio.h</a>):</div>
<div>
<pre class="fragment" style="color: #5000a0; text-align: start;"></pre>
<pre class="fragment" style="color: #5000a0; text-align: start;"><span style="font-family: Courier New, Courier, monospace;"><b>
</b></span></pre>
<span style="font-family: Courier New, Courier, monospace;"><b>-Wl,-u,<a class="code" href="http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1" style="color: #4444ee; text-decoration: none;">vfprintf</a> -lprintf_flt -lm</b></span></div>
<div>
<br /></div>
<div>
Those must be appended to the <span style="font-family: Courier New, Courier, monospace;">LDFLAGS</span> variable in the <span style="font-family: Courier New, Courier, monospace;">Makefile</span>. as usual the example code can be downloaded <a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/serial_stdio.tgz" target="_blank">here</a>.</div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-40557340090305105272013-10-04T11:39:00.000-07:002013-10-04T11:41:12.943-07:00Atmega328's USART<div style="text-align: justify;">
It is essential to have a convenient functions allowing quick serial port setup and usage. In this post I'll try to cover the basics of using the serial port, data reception & transmission + using interrupts.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Serial driver routines are very similar to supervising a <span style="font-family: Courier New, Courier, monospace;">NIC</span>. Of course they are much more simpler and the speeds are lower as well, but the general approach is very similar. In the simplest model we can realize serial transmission/reception directly - by simply sending the data byte by byte waiting for the hardware to finish each transmission and poll the hardware status register before queuing/dequeuing new data. Although this approach will work, it's not very elegant and it requires constant CPU attention which consumes a lot of processing power. Using interrupts provides a lot more flexibility and save some processing power since we don't need to constantly check the <span style="font-family: Courier New, Courier, monospace;">USART's</span> registers in order to know whether we have any pending data or not.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As usual we need some building blocks. Regardless of how the transmission/reception will be realized, an <span style="font-family: Courier New, Courier, monospace;">USART</span> initialization routine is a must. We'll setup the port in needed mode, configure the amount of data/start/stop bits, the parity and the baud rate. Of course we need a routines to transmit/receive a byte from the port. Those will be implemented in polling fashion in the first place, then we'll introduce interrupt driven transmission/reception.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
The initialization</h3>
<div style="text-align: justify;">
Atmega328p's <span style="font-family: Courier New, Courier, monospace;">USART</span> is a very friendly peripheral to configure. For most of our applications a standard configuration of 8 data bits, 1 stop bit + no parity bits, will be sufficient and we're going to configure the port in that manner. First thing that has to be done is as usual with every Atmega's peripheral - enable to power to it, we can use the macro from avr libc <span style="font-family: Courier New, Courier, monospace;">power_usart0_enable</span>(). Next let's configure the port baud rate. This is done by setting up values in three registers. <span style="font-family: Courier New, Courier, monospace;">UBRR0H/UBRR0L</span> and <span style="font-family: Courier New, Courier, monospace;">UCSR0A</span> - where we enable so called double speed. Without going into details for most of the standard speeds there is a nice table provided in the datasheet, and we're going to use it. Arduino is using standard crystal of <span style="font-family: Courier New, Courier, monospace;">16MHz</span>, in order to configure the port for 57600 bps We need to write 34 to <span style="font-family: Courier New, Courier, monospace;">UBRR0H/UBRR0L </span>register pair and enable the double speed (to minimize the frequency error). Next thing is to enable asynchronous mode 8N1 by writing 0x06 to the <span style="font-family: Courier New, Courier, monospace;">UCSR0C</span> register and finally enable receiver and transmitter. The whole procedure looks as follow:</div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/6830358.js"></script>
</div>
<h3>
Data reception</h3>
<div style="text-align: justify;">
Accordingly to the datasheet, we must poll for the <span style="font-family: Courier New, Courier, monospace;">RXC0</span> bit to be set in the <span style="font-family: Courier New, Courier, monospace;">UCSR0A</span> status register and read the data as soon as it has been set. The data must be read as quick as possible to empty the hardware <span style="font-family: Courier New, Courier, monospace;">FIFO</span> and make some place for new data, otherwise we'll drop the incoming data. The simplest reception function will look the following way:</div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/6830405.js"></script>
</div>
<div style="text-align: justify;">
This function is blocking of course. This means that once we request for example a single byte from the serial port, the <span style="font-family: Courier New, Courier, monospace;">CPU</span> will be looping inside until the byte has been received. This may be a problem since it prevents us from doing anything else in the meantime. </div>
<div style="text-align: justify;">
<br /></div>
<h3>
Data Transmission</h3>
<div style="text-align: justify;">
It is realized in a very similar fashion, we poll the status register for the value of <span style="font-family: Courier New, Courier, monospace;">UDRE</span> bit. Low value indicates that the <span style="font-family: Courier New, Courier, monospace;">USART</span> is busy performing transmission, high value indicates that <span style="font-family: Courier New, Courier, monospace;">USART</span> is free and we can place new data into hardware <span style="font-family: Courier New, Courier, monospace;">FIFO UDR0</span> register. The data will be immediately transmitted. For code reference have a look at the <span style="font-family: Courier New, Courier, monospace;">serial_poll_send()</span> function on the previous snippet. Again, the function is blocking. It will block until a complete data buffer provided as an argument will be send. This may be a problem when our application produces a lot of data and needs some time to generate it without being interrupted. In most of the application though, blocking data transmission does not pose any issue. The interrupt driven reception is more important.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Interrupt driven IO</h3>
<div style="text-align: justify;">
If we're not particularly worried about every <span style="font-family: Courier New, Courier, monospace;">CPU</span> microsecond, and our application is flexible enough that it can work without problems with blocking IO during <span style="font-family: Courier New, Courier, monospace;">USART</span> communication, then more or less we're done and the presented set of routines is functional complete. To get the most though from our <span style="font-family: Courier New, Courier, monospace;">MCU</span> and it's <span style="font-family: Courier New, Courier, monospace;">USART</span> utilizing the interrupts is a must. By sacrificing some memory for so called reception/transmission ring buffers we can perform the <span style="font-family: Courier New, Courier, monospace;">USART</span> IO operations "in the background" interfering the main processing flow almost insignificantly.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Operating in such manner, as mentioned previously, is very similar to what <span style="font-family: Courier New, Courier, monospace;">NIC</span> device drivers perform, the principle stays the same. For both directions (or only one if there is no need for the other) we define a ring buffer which is a queue more or less. The <span style="font-family: Courier New, Courier, monospace;">USART</span> will act as a producer and the CPU will act as the consumer (in RX direction). We assume that the CPU can really read the data faster than the USART can provide thus the situation when there is no space in the ring buffer and the data must be dropped, will occur very seldom. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
In TX direction it works the opposite way, our application is the producer and USART is the consumer. If there is no space in the buffer (which means that either we have a too small transmission buffer or we produce the data too fast) the transmission will fail and will have to be retried later on.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Ring buffer</h3>
<div style="text-align: justify;">
This is the essential part of the implementation. Let's define it as:<br />
<br />
<script src="https://gist.github.com/dagon666/6830466.js"></script>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The data structure is very simple and common. One may found a lot of references describing details behind it thus I'm not going to provide a very thorough description. In principle, a "producer" pushes the data at position pointed by the head and increments it. The "consumer" takes the data pointed by tail until tail == head. The write/read operations in the ring buffer are independent. Have a look at the diagrams bellow, which depict most of the states a ring buffer may be found:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://2.bp.blogspot.com/-LFhywYEH3Hk/Uk8Gx9joC6I/AAAAAAAAAN8/E-E2uY_6mjo/s1600/buffers.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://2.bp.blogspot.com/-LFhywYEH3Hk/Uk8Gx9joC6I/AAAAAAAAAN8/E-E2uY_6mjo/s1600/buffers.png" height="640" width="445" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Operations on Ring buffer.</td></tr>
</tbody></table>
<br /></div>
<h3>
Interrupt driven data reception</h3>
<div style="text-align: justify;">
Interrupt driven reception is much more widely implemented and much more useful than interrupt driven transmission. In most of the applications there is only a need really to provide this kind of input data handling while the transmission is still realized the "simpler" polled way. Let's get into details. The model is quite simple. We have an RX ring buffer which will hold the incoming data and a bunch of routines which will simply get the data and return it out of the ring, freeing the space in it. So in a sense the incoming data is buffered and waiting before it is actually read by the application. To summarize it stepwise, it would be:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Reception:</div>
<div style="text-align: justify;">
</div>
<ol>
<li>Configure the port and install USART RX interrupt.</li>
<li>When data arrives an interrupt is called.</li>
<li>In ISR if there is space available in the ring buffer, place the new data in the ring and increment the head index.</li>
</ol>
<br />
<div style="text-align: justify;">
Application reading data:</div>
<div style="text-align: justify;">
</div>
<ol>
<li>If head != tail we have data available in the ring buffer.</li>
<li>Return data indexed by tail.</li>
<li>Increment tail.</li>
</ol>
<span style="text-align: justify;">Let's have a look on the code bellow:</span><br />
<span style="text-align: justify;"><br /></span>
<span style="text-align: justify;"><br /></span>
<br />
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/6830489.js"></script>
</div>
<h3>
Interrupt driven data transmission</h3>
<div style="text-align: justify;">
It's very similar to the reception. We will use the UDRE empty interrupt which is triggered when the data transmission FIFO is empty. This means that when the CPU and USART are idle this will be called ALWAYS. Now that's not exactly what we want. Unlike in case of data reception interrupt, we will unmask the UDRE interrupt only when there is data available in the TX buffer and mask it as soon as the last byte has been sent. Let's list the steps of the algorithm:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Application:</div>
<div style="text-align: justify;">
</div>
<ol>
<li>Queue new data for transmission if there is space in the ring buffer</li>
<li>Unmask UDRE interrupt</li>
</ol>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
ISR:</div>
<div style="text-align: justify;">
</div>
<ol>
<li>Transmit the data from the ring buffer</li>
<li>Mask the UDRE interrupt if there are no new characters to be send</li>
</ol>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
And the code:
<br />
<script src="https://gist.github.com/dagon666/6830527.js"></script>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The functions and code snippets presented are taken directly from the libpca library (with small modifications), I kept the function names in tact to be compatible with the library as well. The complete usage example will use the library, we'll create something simple, the serial echo program. As usual let's clone a fresh copy of the library and create a directory for our project:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><span style="font-family: Courier New, Courier, monospace;">git clone git@github.com:dagon666/avr_Libpca pca</span></b></div>
<div style="text-align: justify;">
<b><span style="font-family: Courier New, Courier, monospace;">mkdir serial_echo</span></b></div>
<div style="text-align: justify;">
<b><span style="font-family: Courier New, Courier, monospace;">cd serial_echo</span></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Our <span style="font-family: Courier New, Courier, monospace;">main.c</span> will look the following way:</div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/dagon666/6830590.js"></script>
</div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">libpca</span> defines an enumeration of standard serial speeds. User can specify the speed manually (by providing the number), or using the enumeration. In the above example the reception is realized using interrupts and the transmission using polling. In order for that to work one mustn't forget about enabling the RX interrupt in the library configuration file (<span style="font-family: Courier New, Courier, monospace;">include/config.h</span>):</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><span style="font-family: Courier New, Courier, monospace;">#define SERIAL_IMPLEMENT_RX_INT 1</span></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
After compiling our program, we can test it with the terminal emulator of choice. I'll use screen, my Arduino's serial port is visible as <span style="font-family: Courier New, Courier, monospace;">/dev/ttyACM0</span>, I connect to it by typing:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>screen /dev/ttyACM0 57600</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now whatever you'll type should be echoed back by the Arduino. That's all, we've mastered the serial port. The libpca project can be downloaded from here:<br />
<br />
<a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/serial_echo.tgz">https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/serial_echo.tgz</a><br />
<div>
<br /></div>
We're ready to do some more complex stuff now. Now as long as transferring text information through the serial line is quite easy and error prone, binary data transfers may be a little bit trickier. I'll try to cover the binary data transmission quirks in my next post as this knowledge will be needed in order to introduce you to some of my projects.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-59671834114034802892013-10-01T11:22:00.002-07:002013-10-01T11:22:49.480-07:00Generating Tones with Timers<div style="text-align: justify;">
Previously I presented a basic way of using timers in order to generate delays. At this time, we'll learn how to use timers and piezo buzzer to generate tones (beeps). The code for that won't be very different from what we were doing previously. Let's start with defining the requirements of our implementation. Our "beeper" function should allow us to generate a beep of given frequency and duration. Simple as that. Just to quickly summarize, when using timer for delay purposes we configured it in <b>CTC</b> mode and configured the prescaler and <span style="font-family: Courier New, Courier, monospace;">OCRXA</span> register value so the timer "overflowed" with a 1 kHz frequency (1 ms period), the delay duration was specified by the number of "overflows". Previously, as long as counting the 1 ms cycles was good enough to determine the duration, now the duration depends on both parameters, the actual duration specified as an input parameter as well as the frequency itself. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let's list steps that our "beep" generation algorithm will have to take:</div>
<ol>
<li style="text-align: justify;">Program the timer in CTC mode.</li>
<li style="text-align: justify;">Program the OCXA pin as output.</li>
<li style="text-align: justify;">Program the timer's compare output mode to toggle the OCXA on each compare match.</li>
<li style="text-align: justify;">Calculate the prescaler and the OCRXA values to generate the frequency of 2*f.</li>
<li style="text-align: justify;">Calculate the amount of cycles needed to "realize" the requested duration.</li>
<li style="text-align: justify;">Enable interrupts.</li>
<li style="text-align: justify;">Decrement the cycles counter (calculated in step 5) inside of the ISR.</li>
<li style="text-align: justify;">Stop generation and disable interrupts once cycles counter reaches zero.</li>
</ol>
<br />
<div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
That looks a lot more complicated than previously. Don't worry it only appears that way. The trickery is hidden in steps 4 and 5, the rest is more or less the same. In point 4, let's think a for moment; why does the frequency should be twice as high as requested ? The reason behind it is really trivial. The output will be generated on pin <span style="font-family: Courier New, Courier, monospace;">OCXA</span> by the hardware, which in <b>CTC</b> mode and <span style="font-family: Courier New, Courier, monospace;">COM0A1/COM0A0</span> configured to 0x01 - will be toggled each time a timers <span style="font-family: Courier New, Courier, monospace;">TCNTX</span> register value will be equal to the one programmed in <span style="font-family: Courier New, Courier, monospace;">OCRXA</span>, after that the <span style="font-family: Courier New, Courier, monospace;">TCNTX</span> register will be reloaded with zero. What that means is a single timer cycle generates only half of the square wave output. So, we need the frequency twice as high for the pin to be toggled with the one requested. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
First thing that we will have to think about is a universal function which will calculate the values of both the prescaler and the <span style="font-family: Courier New, Courier, monospace;">OCRXA</span> register to program the timer to the requested frequency. The formula for the frequency for the Timer in <b>CTC</b> mode (as stated in the datasheet) is:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<div>
<span style="font-family: Courier New, Courier, monospace;">f = fclk / [ 2 * N * (1 + OCRXY) ]</span></div>
<div>
<br /></div>
<div>
where:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">fclk</span> - system clock (16 MHz for most of the Arduinos)</div>
<div>
N - the prescaler value (1,8,64,256,1024 - for timers 0 and 1)</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">OCRXY</span> - the value in the register <span style="font-family: Courier New, Courier, monospace;">OCR0A/OCR0B</span> (register for timer 0 used as an example, by the way, through out this post and in most of my code I focus only on Output compare register and output compare A, but You can use register/output B good as well - it's a matter of preferences).</div>
<div>
<br /></div>
<div>
Using the formula above we will have to calculate the values of N and <span style="font-family: Courier New, Courier, monospace;">OCRXA</span> in runtime. </div>
<div>
<br /></div>
<div>
Let's have a look bellow on the code which does that for Timer0: </div>
<div>
<br />
<script src="https://gist.github.com/dagon666/6769590.js"></script>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
Let's analyze this code. There are some improvements introduced inside to make it a little bit faster/smaller. In fact it is completely decoupled from hardware, since it's a routine performing calculations only, so we can successfully compile it on an <span style="font-family: Courier New, Courier, monospace;">x86</span> machine and do some debugging. First of all a table of "prescalers" is declared. At first glance it contains some strange values. It stores the number by which a 0x01 should be bitshifted in order to get a valid prescaler value. It has been designed this way to save memory. The prescaler values for timer0 are 1,8,64,256,1024. To store those values we would need an <span style="font-family: Courier New, Courier, monospace;">uint16_t</span> data type, consuming 5 bytes more than now. Since the prescalers are a powers of two we can only store the number of bitshifts required to get the needed value. The Atmega is a very fast core, we have a lot more computing power than memory available, that's why in most of the applications we should try to minimize the memory usage over computing resources. The calculation of prescaler and the OCR value is done in the while loop, the formula has been transformed to the following one:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">OCR = [ fclk / (2 * N * f)] - 1</span></div>
<div>
<br /></div>
<div>
In every loop roll we compute the OCR value using another available prescaler. The loop brakes as soon as the OCR value is bellow 256 - which means that we have found a usable set of prescaler and OCR values in order to program the timer to generate the requested frequency. The values are returned by reference. Let's test this function offline. Consider & compile the followig code:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>gcc -o pocr_test pocr_test.c</b></span></div>
<div>
<br /></div>
<div>
<br />
<script src="https://gist.github.com/dagon666/6769655.js"></script>
<br />
Let's do some tests:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ ./pocr_test 1000</span><br />
<span style="font-family: Courier New, Courier, monospace;">Frequency: [1000 Hz], Prescaler: [ 64], OCR: [124]</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ ./pocr_test 13000</span><br />
<span style="font-family: Courier New, Courier, monospace;">Frequency: [13000 Hz], Prescaler: [ 8], OCR: [ 75]</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ ./pocr_test 8000</span><br />
<span style="font-family: Courier New, Courier, monospace;">Frequency: [8000 Hz], Prescaler: [ 8], OCR: [124]</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ ./pocr_test 30</span><br />
<span style="font-family: Courier New, Courier, monospace;">Frequency: [30 Hz], Prescaler: [1024], OCR: [255]</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">./pocr_test 31</span><br />
<span style="font-family: Courier New, Courier, monospace;">Frequency: [31 Hz], Prescaler: [1024], OCR: [251]</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$ ./pocr_test 20</span><br />
<span style="font-family: Courier New, Courier, monospace;">Frequency: [20 Hz], Prescaler: [1024], OCR: [255]</span><br />
<br />
Let's verify one of those manually:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">- f = 16MHz / [ 2 * 64 * (1 + 124) ] = 1000</span><br />
<span style="font-family: Courier New, Courier, monospace;">- f = 16MHz / [ 2 * 8 * (1 + 75) ] = 13157</span><br />
<span style="font-family: Courier New, Courier, monospace;">- f = 16MHz / [ 2 * 8 * (1 + 124) ] = 8000</span><br />
<span style="font-family: Courier New, Courier, monospace;">- f = 16MHz / [ 2 * 1024 * (1 + 255) ] = 30</span><br />
<br />
Looks quite promising. Of course the function does not minimize the frequency error, it only tries to find first matching pair of values in order to satisfy to request. In the second example a values of (prescaler: 8, ocr: 76) would provide a better fit (12987 Hz, 13 Hz difference instead of 157), but for most of the applications (especially tone generation using buzzer) such error is really acceptable. For more precision we would have to gather the <span style="font-family: Courier New, Courier, monospace;">OCR</span> results for all prescaler values and return the one which is less different from the requested frequency. To have a real control we would probably define those values ourselves and use some sort of lookup table. At the moment we do not have to worry about that.<br />
<br />
Second thing that we need to do is to determine how many timer overflows we need to count in order to determine the duration. Let's think about it. For a given frequency 1 cycle lasts for :<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">T = 1/(2*f)</span><br />
<br />
The frequency is multiplied by two since, the timer is running with frequency twice as high as needed. The duration will be specified in millisecods, so we need to determine how many cycles (x) do we need do realize it. This can be calculated using proportions:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">duration * (1/1000) = x * (1/2*f)</span><br />
<br />
so, x:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">x = (2 * f * duration) / 1000</span><br />
<br />
Simplifying:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">x = (f * duration) / 500</span><br />
<br />
<br />
and that's the answer. Now we have all the necessary tools to finish our implementation. Let's start:<br />
<br />
<script src="https://gist.github.com/dagon666/6769476.js"></script>
<br />
Let's connect the buzzer to the Arduino board digital pin 7 (PORTD6) (no resistor is needed), and test our code.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-IrGZQp3shL0/UksR-kJhh_I/AAAAAAAAANs/oLhhSbu5tiY/s1600/IMG_1980.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://3.bp.blogspot.com/-IrGZQp3shL0/UksR-kJhh_I/AAAAAAAAANs/oLhhSbu5tiY/s1600/IMG_1980.JPG" height="265" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Connecting piezo buzzer to Timer0 OC0A output.</td></tr>
</tbody></table>
<br />
This functionality is covered by the libpca as well. As previously it's very easy to use. The timer_freq_prescale() function equivalent is implemented there as well in a very similar fashion (it's called _timer_freq_prescale()). Again, it's done in way to provide flexibility and be as much universal as it's possible. Let's cover the implementation in the beeper library module. Most important functions are:<br />
<br />
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">- void beeper_init(e_timer a_timer);</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">- void beeper_beep(e_timer a_timer, uint32_t freq, uint32_t duration);</span></div>
<div style="text-align: left;">
<br /></div>
The interface is self explanatory. Let's write a simple program which will do more or less the same as our previous example:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ git clone git@github.com:dagon666/avr_Libpca pca</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ mkdir beep_libpca</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ cd beep_libpca</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ touch beep_libpca.c</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
<div>
<br /></div>
<br />
<script src="https://gist.github.com/dagon666/6769790.js"></script>
</div>
</div>
<div>
We cannot forget to enable the Timer interrupt implementation in the library configuration file in order for the code to work (this will be TDELAY_IMPLEMENT_T0_INT variable which must be defined as 1). The implementation presented as well as the one in the library can be extended further on. We could use the PWM capability to provide the volume control to the beep generator. For the moment though I do not plan to cover this topic. I hope that this post has been useful. In my next posts I'm going to cover the basic usage of the UART port. After that I'll proceed to some more interesting stuff (I hope :)).</div>
<div>
<br /></div>
</div>
<div style="text-align: justify;">
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-12737050550183891082013-09-27T01:48:00.001-07:002013-09-30T13:35:59.648-07:00Introduction to Pure C Arduino Library - Timers & Delays<div style="text-align: justify;">
As long as blinking a led is a fairly simple task. Arduino Library is very handy and can really improve the speed of development of a new projects, making your idea real & tangible. Something similar in C would be useful. At this moment one may ask - why to create a new library, when there are already plenty of those available and ready to use ? Well, thinking like that, we may ask ourselves straight away why to even bother and play with an 8-bit machine when there is so powerful and cheap stuff available out there at the moment everywhere nearly ? The answers for both are short and straight forward:</div>
<div>
<div>
<ol>
<li style="text-align: justify;">Because we can and it's fun</li>
<li style="text-align: justify;">Because we want to learn something</li>
<li style="text-align: justify;">Because we want to create some real, useful stuff</li>
</ol>
</div>
<div>
<div style="text-align: justify;">
Another reason to create a library is to have some basic tool set which will be absolutely essential in most of any further developments. First thing which will need in this tool set is a proper (by proper I mean - timer/interrupt based) delay function. I have nothing against a "busy" delay from AVR libc but there is a small problem with that - the delay time cannot be passed as a parameter in the runtime since the delay is calculated during compilation, based upon the defined clock value (F_CPU). Now that's a real problem. We could write a similar function as well, which would spin in a loop for a defined number of time but this is more tricky than it seems - probably the optimizer would simply remove our code since it would detect that it has no functional meaning, the second thing is that it would be really hard to maintain any kind of usable accuracy. Since we have a proper hardware to do that (timers) we will use it.</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
At the time being I already created a simple library implementing most of the essential functionality, so this post will continue more or less as a supplement to the documentation on how to really use it. The library is hosted on GitHub:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<a href="https://github.com/dagon666/avr_Libpca">https://github.com/dagon666/avr_Libpca</a></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
I suggest cloning it to <b>pca </b>directory, since current repository name is my GitHub remote convention naming scheme, which isn't really convenient for every day use:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
The documentation for the library, is a doxygen generated html page, available here:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<a href="http://dagon666.github.io/avr_Libpca">http://dagon666.github.io/avr_Libpca</a></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
But going back to the topic of timers. Let's discuss how the delay could be implemented. If we program the timer to overflow every 1 ms then automatically we have a 1 ms delay accuracy functionality implemented. It's really simple, here are the steps needed in a little bit more details:</div>
</div>
<div>
<ol>
<li style="text-align: justify;">Program a timer in <b>CTC </b>mode, to overflow every 1 ms.</li>
<li style="text-align: justify;">Enable timer <span style="font-family: Courier New, Courier, monospace;">COMPA/COMPB</span> interrupt</li>
<li style="text-align: justify;">Set global variable, let's call it "<span style="font-family: Courier New, Courier, monospace;">duration</span>" to the number of milliseconds required</li>
<li style="text-align: justify;">With every timer overflow, decrement the "<span style="font-family: Courier New, Courier, monospace;">duration</span>" variable in the interrupt handler</li>
<li style="text-align: justify;">Block until "<span style="font-family: Courier New, Courier, monospace;">duration</span>" > 0</li>
<li style="text-align: justify;">Disable timer interrupt, since the required amount of time has passed by</li>
</ol>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
First of all we need to program a timer in <b>CTC</b> mode, to be able to specify the exact time needed for it to overflow. Please have a look at the datasheet for more details about how timer behaves in that mode. Let's walk through the code bellow:
<script src="https://gist.github.com/dagon666/6720470.js"></script>
<br />
<br /></div>
</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div>
<div style="text-align: justify;">
Starting from the main function. I setup <span style="font-family: Courier New, Courier, monospace;">PORTB</span> as output and initiate it's value to 0x00; Further on I toggle all lines of <span style="font-family: Courier New, Courier, monospace;">PORTB</span> with a 0.5 Hz frequency. Let's focus on the delay implementation itself. </div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
I strongly suggest to go through this code with datasheet opened - it will help to understand the setting and the register values a lot. First thing is to enable global interrupts and power to <span style="font-family: Courier New, Courier, monospace;">Timer0</span> - I'll use this timer for delay purposes. I use a macro from AVR libc to power on the timer - all it really does is writes zero to bit <span style="font-family: Courier New, Courier, monospace;">PRTIM0</span> in <span style="font-family: Courier New, Courier, monospace;">PRR</span> register which controls the power reduction settings of the MCU, so we can easilly replace that with an explicit bit operation if we want:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>PRR &= ~_BV(PRTIM0);</b></span></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>_BV</b></span> is another nifty macro from avr-libc. It performs a bit shift, so in that example it's equivalent to:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<b><span style="font-family: Courier New, Courier, monospace;">PRR &= ~(0x01 << PRTIM0);</span></b></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
Next I setup the <span style="font-family: Courier New, Courier, monospace;">Timer0</span> registers. First in <span style="font-family: Courier New, Courier, monospace;">TCR0A</span> I configure <span style="font-family: Courier New, Courier, monospace;">Timer0</span> in <b>CTC</b> mode (<b><span style="font-family: Courier New, Courier, monospace;">WGM01</span></b> bit set). I do not care about <span style="font-family: Courier New, Courier, monospace;">COM0A1/COM0A0</span> and <span style="font-family: Courier New, Courier, monospace;">COM0B1/COM0B0</span> settings since I do not plan to output anything on the MCUs <span style="font-family: Courier New, Courier, monospace;">OC0A/OC0B</span> pin. Next thing is to configure the prescaler value in <span style="font-family: Courier New, Courier, monospace;">TCR0B</span> to 64 (<b><span style="font-family: Courier New, Courier, monospace;">CS01</span></b> and <span style="font-family: Courier New, Courier, monospace;"><b>CS00</b></span> bits are set). At that stage the timer is running. I then configure the value of <span style="font-family: Courier New, Courier, monospace;">OC0A</span> to 0x7c (124), accordingly to the formula in the datasheet, the frequency in <b>CTC</b> mode for <span style="font-family: Courier New, Courier, monospace;">Timer0</span> with these settings will be:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">f = 16 Mhz / [ 2 * 64 * (1 + 124)] = 1 kHz</span></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
and the period:</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;">T = 1/f = 1 ms</span></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
Exactly what we need in order to have a 1 ms accurate delay. The timer now is running and overflows with a required frequency. In the next line I configure the duration variable to the requested amount of milliseconds. All that has to be done at that point is to simply enable the <span style="font-family: Courier New, Courier, monospace;">OCIE0A</span> (output compare interrupt which happends always when the counter reaches value configured in <span style="font-family: Courier New, Courier, monospace;">OC0A</span>) interrupt and block in a while loop until the "duration" variable becomes 0.</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
In the interrupt handler, the <span style="font-family: Courier New, Courier, monospace;">duration</span> variable is decremented (if it has a positive value) each time the interrupt occurs. Once "<span style="font-family: Courier New, Courier, monospace;">duration</span>" is equal to zero, I simply mask the <span style="font-family: Courier New, Courier, monospace;">OCIE0A</span> interrupt and disable to clock to Timer0 by configuring prescaler to 0. The timer now has been stopped and no further interrupts will be generated.</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
Because interrupt decrements the "<span style="font-family: Courier New, Courier, monospace;">duration</span>" variable every 1 ms. After 1000 ms it will become zero, and the <span style="font-family: Courier New, Courier, monospace;">tdelay_ms</span> function will end it's execution. Simple as that :).</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
The implementation in <span style="font-family: Courier New, Courier, monospace;">libpca</span> is exactly the same as the example above, it's a little bit more complex only to provide more flexibility and not to duplicate the code inside of the library, but in general the principle stays the same. How to use timer delays with libpca then ? It's even simpler than our reference code above. Let's start by cloning the library and creating directory for our "test project":</div>
</div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>git clone git@github.com:dagon666/avr_Libpca pca</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>mkdir delay_tests</b></span></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>cd delay_tests</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Once inside of our project directory. Let's create two files <span style="font-family: Courier New, Courier, monospace;">main.c</span> for our code and <span style="font-family: Courier New, Courier, monospace;">Makefile</span> for compilation:</div>
<script src="https://gist.github.com/dagon666/6720698.js"></script>
<br />
<div style="text-align: justify;">
The code is really simple. The first difference is that there are two functions tdelay_init() and the tdelay_ms() function itself. The reason is that we need to configure the timer only once, after that all that needs to be done is to configure the "interrupt variable" and re-enable interrupts. This save some time when tdelay_ms() is called in a very busy loop. The second difference is that you must specify the timer explicitly for every function by using the timer enumeration (<span style="font-family: Courier New, Courier, monospace;">E_TIMER0 - E_TIMER2</span>) The library tries to be as much flexible as it is possible. We can use any Timer we want, not only Timer0. One thing needs to be mentioned. In order for the timer delay implementation to work a timer interrupt implementation must be enabled for adequate timer in the library configuration (<span style="font-family: Courier New, Courier, monospace;">include/config.h</span>), in case of the example above this should be:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: Courier New, Courier, monospace;"><b>#define TDELAY_IMPLEMENT_T0_INT 1</b></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
A complete example can be downloaded here.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/delay_tests.tgz">https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/delay_tests.tgz</a></div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
<div style="text-align: justify;">
I hope that this short introduction has been helpful. Going further there is not much that has to be changed to our existing reference code in order to implement the Arduino Library tone() function - I'll try to cover that next time.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
</div>
<div>
<div style="text-align: justify;">
<br /></div>
</div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-45017313298762913882013-09-25T11:57:00.003-07:002013-09-29T14:14:21.004-07:00Libraries, what they really are<br />
<div style="text-align: justify;">
This post is more of an introduction to what I plan to cover further on in the future.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let's start with the basics, for those who are not very familiar with C compilation details. How to create a library, what kind of libraries can we create, what are the advantages/disadvantages ? First of all, there are two types of libraries, static (*.a files) and dynamic libraries (*.so files). The first ones are just a bunch of object files glued together to form a single file (object archive). The second ones are loaded during runtime by operating systems (like Linux (*.so files) /Windows (*.dll files)) whenever applications need them. Both have their pros & cons.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The advantage of dynamic libraries, short summary:</div>
<ul>
<li style="text-align: justify;">The library code is NOT included in every application using the library, the resulting executables are smaller</li>
<li style="text-align: justify;">The library is loaded to memory by operating system (dynamic library loader) once an application requests it, and removed when no longer needed.</li>
<li style="text-align: justify;">The library is shared across many applications - only one copy exists in the memory</li>
<li style="text-align: justify;">When making changes to the library there is no need to recompile once again every application using it (as long as the interface stays compatible)</li>
</ul>
<br />
<div style="text-align: justify;">
Disadvantages:</div>
<ul>
<li style="text-align: justify;">A true multi - process capable operating system is needed</li>
</ul>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
In contrast to the dynamic libraries static libraries are simply compiled into the executable itself for every application using the library. The only advantage we really gain, is that once the library is compiled, we do not have to compile it anymore (if it doesn't change), we just compile the code of our app and link against the library.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The advantages of static libraries, short summary:</div>
<ul>
<li style="text-align: justify;">User results with a single opaque object archive file (.a) which he needs to link his application against</li>
<li style="text-align: justify;">The library is an easily decoupled logical entity, containing some universal code</li>
<li style="text-align: justify;">No sophisticated runtime loading mechanisms are required since the library code is included in the application itself</li>
</ul>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Disadvantages:</div>
<ul>
<li style="text-align: justify;">Every application must link library code into itself (larger executables)</li>
<li style="text-align: justify;">Every application using the library must be recompiled if we incorporate a new change to the library</li>
</ul>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Although dynamic libraries seems to be far more superior, we can only benefit from creating static libraries for embedded systems like Arduino though. Now why is that ? The answer is simple: No operating system ! On our little 8 bit machine there are no resources to run an operating system capable of managing dynamic libraries and real multiprocess environment, thus the only option available are static libraries.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Just as an exercise let's create a dummy library. We'll need two files <span style="font-family: Courier New, Courier, monospace;">dummy.c</span> and <span style="font-family: Courier New, Courier, monospace;">dummy.h</span></div>
<div style="text-align: justify;">
<script src="https://gist.github.com/dagon666/6704104.js"></script>
and the code:</div>
<div>
<div style="text-align: justify;">
<script src="https://gist.github.com/dagon666/6704135.js"></script>
We can't go any simpler. To create a library out of this code, all we need to do is compile it as an object:</div>
<br />
<b><span style="font-family: Courier New, Courier, monospace;">avr-gcc -mmcu=atmega328p -I. -c dummy.c</span></b><br />
<br />
In fact this single object file is already a static library. The (.a) file only aggregates them into a single file nothing else.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>avr-ar rcsv libdummy.a dummy.o</b></span><br />
<br />
... and there we go, our first lib. It can be used in a program the following way:</div>
<div>
<br /></div>
<script src="https://gist.github.com/dagon666/6704202.js"></script>
<div>
<b><span style="font-family: Courier New, Courier, monospace;">avr-gcc -mmcu=atmega328p main.c -ldummy -L. -I.</span></b><br />
<br />
Additionally, we can have a look what symbols are inside:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">avr-nm libdummy.a</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">dummy.o:</span><br />
<span style="font-family: Courier New, Courier, monospace;">0000003e a __SP_H__</span><br />
<span style="font-family: Courier New, Courier, monospace;">0000003d a __SP_L__</span><br />
<span style="font-family: Courier New, Courier, monospace;">0000003f a __SREG__</span><br />
<span style="font-family: Courier New, Courier, monospace;">00000000 a __tmp_reg__</span><br />
<span style="font-family: Courier New, Courier, monospace;">00000001 a __zero_reg__</span><br />
<span style="font-family: Courier New, Courier, monospace;">00000000 T portb_high</span><br />
<br />
Our function starts from address <span style="font-family: Courier New, Courier, monospace;">0x00</span>, we can have a look at the assembler output:<br />
<br />
In archive <span style="font-family: Courier New, Courier, monospace;">libdummy.a</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">dummy.o: file format elf32-avr</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Disassembly of section .text:</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">00000000 <portb_high>:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 0:<span class="Apple-tab-span" style="white-space: pre;"> </span>cf 93 <span class="Apple-tab-span" style="white-space: pre;"> </span>push<span class="Apple-tab-span" style="white-space: pre;"> </span>r28</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 2:<span class="Apple-tab-span" style="white-space: pre;"> </span>df 93 <span class="Apple-tab-span" style="white-space: pre;"> </span>push<span class="Apple-tab-span" style="white-space: pre;"> </span>r29</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 4:<span class="Apple-tab-span" style="white-space: pre;"> </span>cd b7 <span class="Apple-tab-span" style="white-space: pre;"> </span>in<span class="Apple-tab-span" style="white-space: pre;"> </span>r28, 0x3d<span class="Apple-tab-span" style="white-space: pre;"> </span>; 61</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 6:<span class="Apple-tab-span" style="white-space: pre;"> </span>de b7 <span class="Apple-tab-span" style="white-space: pre;"> </span>in<span class="Apple-tab-span" style="white-space: pre;"> </span>r29, 0x3e<span class="Apple-tab-span" style="white-space: pre;"> </span>; 62</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 8:<span class="Apple-tab-span" style="white-space: pre;"> </span>85 e2 <span class="Apple-tab-span" style="white-space: pre;"> </span>ldi<span class="Apple-tab-span" style="white-space: pre;"> </span>r24, 0x25<span class="Apple-tab-span" style="white-space: pre;"> </span>; 37</span><br />
<span style="font-family: Courier New, Courier, monospace;"> a:<span class="Apple-tab-span" style="white-space: pre;"> </span>90 e0 <span class="Apple-tab-span" style="white-space: pre;"> </span>ldi<span class="Apple-tab-span" style="white-space: pre;"> </span>r25, 0x00<span class="Apple-tab-span" style="white-space: pre;"> </span>; 0</span><br />
<span style="font-family: Courier New, Courier, monospace;"> c:<span class="Apple-tab-span" style="white-space: pre;"> </span>2f ef <span class="Apple-tab-span" style="white-space: pre;"> </span>ldi<span class="Apple-tab-span" style="white-space: pre;"> </span>r18, 0xFF<span class="Apple-tab-span" style="white-space: pre;"> </span>; 255</span><br />
<span style="font-family: Courier New, Courier, monospace;"> e:<span class="Apple-tab-span" style="white-space: pre;"> </span>fc 01 <span class="Apple-tab-span" style="white-space: pre;"> </span>movw<span class="Apple-tab-span" style="white-space: pre;"> </span>r30, r24</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 10:<span class="Apple-tab-span" style="white-space: pre;"> </span>20 83 <span class="Apple-tab-span" style="white-space: pre;"> </span>st<span class="Apple-tab-span" style="white-space: pre;"> </span>Z, r18</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 12:<span class="Apple-tab-span" style="white-space: pre;"> </span>df 91 <span class="Apple-tab-span" style="white-space: pre;"> </span>pop<span class="Apple-tab-span" style="white-space: pre;"> </span>r29</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 14:<span class="Apple-tab-span" style="white-space: pre;"> </span>cf 91 <span class="Apple-tab-span" style="white-space: pre;"> </span>pop<span class="Apple-tab-span" style="white-space: pre;"> </span>r28</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 16:<span class="Apple-tab-span" style="white-space: pre;"> </span>08 95 <span class="Apple-tab-span" style="white-space: pre;"> </span>ret</span><br />
<br />
<br />
<div style="text-align: justify;">
What can be seen here ? First, registers <span style="font-family: Courier New, Courier, monospace;">r28,r29</span> (register Y) are preserved on the stack (address 0 and 2). Then, <span style="font-family: Courier New, Courier, monospace;">r28,r29</span> is configured to the current stack pointer top. That's a standard gcc behavior. Next two instructions load registers r24,r25 with the memory address of <span style="font-family: Courier New, Courier, monospace;">PORTB (0x25)</span>. The instruction at address <span style="font-family: Courier New, Courier, monospace;">0x0c</span> loads our argument <span style="font-family: Courier New, Courier, monospace;">0xff</span> to register <span style="font-family: Courier New, Courier, monospace;">r18</span>. Next two instructions copy the register pair <span style="font-family: Courier New, Courier, monospace;">r24,r25</span> to <span style="font-family: Courier New, Courier, monospace;">r30,r31</span> (register Z) in order to store the value in <span style="font-family: Courier New, Courier, monospace;">r18</span> (<span style="font-family: Courier New, Courier, monospace;">0xff</span>) in the memory (<span style="font-family: Courier New, Courier, monospace;">0x0025 - PORTB</span>). Next the stack is restored and we exit the function. Quite a lot of stuff as for such a simple code :). This code is compiled of course without any optimizations enabled. If we compile it once again with <span style="font-family: Courier New, Courier, monospace;">-Os</span> (size optimization), the output looks a lot less clobbered:</div>
<br />
<span style="font-family: Courier New, Courier, monospace;">In archive libdummy.a:</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">dummy.o: file format elf32-avr</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">Disassembly of section .text:</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">00000000 <portb_high>:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 0:<span class="Apple-tab-span" style="white-space: pre;"> </span>8f ef <span class="Apple-tab-span" style="white-space: pre;"> </span>ldi<span class="Apple-tab-span" style="white-space: pre;"> </span>r24, 0xFF<span class="Apple-tab-span" style="white-space: pre;"> </span>; 255</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 2:<span class="Apple-tab-span" style="white-space: pre;"> </span>85 b9 <span class="Apple-tab-span" style="white-space: pre;"> </span>out<span class="Apple-tab-span" style="white-space: pre;"> </span>0x05, r24<span class="Apple-tab-span" style="white-space: pre;"> </span>; 5</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 4:<span class="Apple-tab-span" style="white-space: pre;"> </span>08 95 <span class="Apple-tab-span" style="white-space: pre;"> </span>ret</span><br />
<br />
The code is pretty obvious and doesn't require further explanations from my point of view. At this time I'm sure that most of the library technical specific aspects have been covered and we are ready to create some more useful stuff. In the next post, I'll try to explain the details regarding the Atmega's Timers and introduce you to a real library with more useful code.</div>
<div>
<br /></div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com0tag:blogger.com,1999:blog-4146080941178349095.post-1293251209327845612013-09-22T04:31:00.002-07:002013-09-25T11:30:00.170-07:00Arduino in pure C<div style="text-align: justify;">
Arduino is a great, simple development platform and it's simple enough that even less advanced users can start and be creative straight out of the box. I have nothing against the C++ Arduino Libraries but relying only on those separates you a little bit from the machine itself. Arduino is simple enough to use it with Pure C. Doing so, you will not only learn a lot more, but will have an ultimate control over your software and will better understand what really is going on. I dedicate this blog to everyone who is starting with Arduino as well as to those of you who already have a lot of experience with it but were never really brave enough to abandon the Arduino Libraries and IDE itself.<br />
<br />
In order to start we need a couple of tools.<br />
<ul>
<li>toolchain & cross compiler: avr-gcc, avr-binutils</li>
<li>C library: avr-libc</li>
<li>Programmer: avrdude</li>
</ul>
Some other useful stuff which can be installed:<br />
<ul>
<li>debugger: avr-gdb</li>
<li>simulator: simavr/simulavr</li>
</ul>
On most of the modern system those packages can be installed automatically (through a package manager). If that's not the case, you will have to download them compile and install manually. On ARCH linux you can install arduino package using yaourt, which will automatically install avr-gcc + avrdude, unfortunately those are not placed in the PATH directories so one needs to specify the paths explicitly. I'm not going to focus on those matters as in my understanding they're a little out of scope.<br />
<br />
To start the work first of all, we need to prepare a Makefile which will ease up the development and compilation process. The avrdude configuration paths, serial port or the target mcu should be adjusted accordingly to the configuration of your board and system. TARGET denotes the name of the ELF file which will be generated by the compiler and SOURCES variable should contain a list of all source files which must be compiled. For the purpose of this simple example there is only one blink.c which we'll create later on. The basic Makefile which I will use and extend further on looks the following way:<br />
<script src="https://gist.github.com/dagon666/6654222.js"></script>
<br />
<br />
<br />
Using C with AVR MCU requires some knowledge of the avr-libc library. So this site:<br />
<br />
<a href="http://www.nongnu.org/avr-libc/">http://www.nongnu.org/avr-libc/</a><br />
<br />
will be your best friend for now on. Not mentioning the detailed datasheet of the MCU itself. For Atmega's installed on Arduino UNO this one is located here:<br />
<br />
<a href="http://atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf">http://atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf</a><br />
<br />
The Arduino Schematics also comes very handy:<br />
<br />
(Rev 3): <a href="http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf">http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf</a><br />
<br />
For the moment we need to know three things.<br />
<ol>
<li>In order to configure a pin as output we need to configure it in the DDR(B,C,D) register.</li>
<li>In order to raise the pin high or low we need to set an appropriate bin in the PORT(B,C,D) register.</li>
<li>The avr-libc implements the simplest, so called, busy delay (which in general is a bunch of loops) which can be used for our purposes.</li>
</ol>
<br />
Let's put this together:<br />
<script src="https://gist.github.com/dagon666/6654262.js"></script>
<br />
<div>
<br /></div>
A short walk through this example. Line 6, writing 0x01 will configure pin 0 of port B as output, on the next line I'm setting port B to zeros. On Line 10 I'm XOR'ing current value of PORTB with 0x01, this will cause a value of the first bit to toggle since<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">0 xor 0 = 0;</span><br />
<span style="font-family: Courier New, Courier, monospace;">0 xor 1 = 1;</span><br />
<span style="font-family: Courier New, Courier, monospace;">1 xor 1 = 0;</span><br />
<span style="font-family: Courier New, Courier, monospace;">1 xor 0 = 1;</span><br />
<br />
On the next line I'm calling a avr-libc delay function, so our LED won't blink with full clock speed. If we have a look at the schematics, then we can see that PORTB0 is connected to pin 8 on the arduino. This is where the LED should be attached.<br />
<br />
All that needs to be done is as simple as:<br />
<span style="font-family: Courier New, Courier, monospace;">make</span><br />
<span style="font-family: Courier New, Courier, monospace;">make install</span><br />
<br />
... and our blinking led C "project" should run now on Arduino. Complete code can be found here:<br />
<br />
<a href="https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/blink.tar.gz">https://googledrive.com/host/0ByE_WFvvg-guTzE4TmFwMDhaZTA/blink.tar.gz</a><br />
<br /></div>
tomaszhttp://www.blogger.com/profile/06567710331366612674noreply@blogger.com1