Sunday, February 24, 2013

EvoPrimer Tutorial: ToolBars

 
This blog post is the first in series (hopefully, there will be more) of tutorials on the EvoPrimer dev kit from Raisonance. These tutorials will mainly concentrate on usage of the circle OS. This tutorial assumes that you already know how to create a simple Circle OS project. If you are not aware of the procedure to do so, you can follow this tutorial to learn about it.

For this tutorial, we will see how we can create and use a tool bar under Circle OS. Toolbars are the widgets that appear on the top of the LCD.

For this tutorial, we will build a simple game of gears, papers and scissors (I could not find a rock icon in Tango image library :p). The game logic itself is simple, the CPU makes a random selection of an object, either a rock(gears), paper or scissor and compares against the user selection, selected via the tool bar.


First we will see how the game logic is implemented and then move on to the implementation details of the game on the Circle OS.

The game:
The three game objects (gear, paper and scissor) are represented using numeric values which are defined using following '#define's:


 #define GEAR 0  
 #define PAPER 1  
 #define SIC 2  

Next up, we have defines which represent the result of a match.

 #define PLAYER_WINS 3  
 #define CPU_WINS 4  
 #define DRAW 5  

These two are used to setup the rules table. This is a two dimensional array which when accessed with column as CPU selection and row as user selection, returns the result of the match. All other parts of the application is built on this core logic. The game is “played” by the the function play() which takes as input the user choice and internally generates a random number to make a CPU selection and determines the result of the match. We'll now see how one can create tool bars and use them.

The tool bars:
You can have up to 4 tool bar items displayed at a time. The main toolbar is represented by the 'tTheToolBar' which is of type 'tToolbar' which we need to populate with our custom tool bar icons and their associated call back functions. First, we need to have icons. I got the icons from the Tango library and used “BMPTOLCD” tool to get the RGB value from the image files and store it in “C” header files.

 static const uint16_t aPaperIcn[] = {  
 #include "paper.h"  
 };  
 static const uint16_t aGearIcn[] = {  
 #include "gear.h"  
 };  
 static const uint16_t aSiccorIcn[] = {  
 #include "siccor.h"  
 };  
 static const uint16_t aExitIcn[] = {  
 #include "exit.h"  
 };  

If you were to add the above lines and copy the header files into current working directory you would encounter following error message
 undefined symbol `!!!!!!!!! FLASH IS FULL !!!!!!!!!' referenced in expression   

This is due to the fact that each circle OS application by default is allocated 8K of program memory and by including all the header files of icons (which also consumes program memory), we have exceeded the memory allocated to us. Solution is to modify the linker script, “Circle_App_OP4.ld” (or “Circle_App.ld” in case of primer 1 or 2) to allow us to use more program memory. The linker script is located in the same directory as the project files are located. Open the file “Circle_App_OP4.ld” in RIDE ( or your favorite editor) and scroll down to line number 198 and change “16K” to “64K” now that the linker knows the program memory available (flash), we also need to set the higher address for the flash. According to the linker script our program memory starts from “0x800C000” and the higher address would be 0x800C000 + 64K – 1. Modify line 206 as well with the similar changes that you made to line 198 that is, replace 16K with 64K. Save the modifications and now the application should compile.

Now that we have icons for the tools bar, we need to create the toolbar items that can be used by the circle OS.

 const tToolbarItem tItem1 = { aGearIcn, ToolBar_Handle_Gear};  
 const tToolbarItem tItem2 = { aPaperIcn, ToolBar_Handle_Paper};  
 const tToolbarItem tItem3 = { aSiccorIcn, ToolBar_Handle_Siccor};  
 const tToolbarItem tItem4 = { aExitIcn, ToolBar_Handle_Exit};  

The above structure initializations has two parts, the first part is the starting address of the image data (which has to be 60x60 pixels for proper drawing on the LCD). The second part is the callback function that will be executed when the user clicks on the corresponding tool bar item.

 enum MENU_code  
 ToolBar_Handle_Gear (void)  
 {  
 Play(GEAR);  
 return MENU_CONTINUE_COMMAND;  
 }  
 enum MENU_code  
 ToolBar_Handle_Siccor (void)  
 {  
 Play(SIC);  
 return MENU_CONTINUE_COMMAND;  
 }  
 enum MENU_code  
 ToolBar_Handle_Paper (void)  
 {  
 Play(PAPER);  
 return MENU_CONTINUE_COMMAND;  
 }  
 enum MENU_code  
 ToolBar_Handle_Exit (void)  
 {  
 MENU_RestoreAppliDivider();  
 return MENU_Quit();  
 }  

All the toolbar handlers (except for exit) use the Play() function to play the game. Finally, we register our toolbar items with the circle OS using the following steps in the Application_Ini().

 tTheToolBar.NbItems = 4;  
 tTheToolBar.FirstDispItem = 0;  
 tTheToolBar.Items[0] = tItem1;  
 tTheToolBar.Items[1] = tItem2;  
 tTheToolBar.Items[2] = tItem3;  
 tTheToolBar.Items[3] = tItem4;  
 TOOLBAR_Set (&tTheToolBar);  

Above, we populate the main toolbar ('tTheToolBar') with the information of our tool bar items. First statement sets the number of tool bar items, which is 4 in our case. The next statement sets the first tool bar item to be displayed which we have set to zero since we want 'gears' toolbar item to be displayed first. This parameter can be useful if tool bar items are greater than 4. In that case you can cycle through your multiple tool bar items to be displayed. The tool bar for our application is set using the function “TOOLBAR_Set()”. When you start your application, you should see the toolbar in the top and should be able to play the game.

You can download the project and related files from here.
You need to have an account at stm32circle.com to download the files.

I've kept out description of other circle OS features used (such as LCD_Draw()). These can be part of future tutorials. You can post any questions you might have in the comments section. I'll try my best to answer. Please do leave your feed back as well. Would help me to better these tutorials.

P.S.: Toolbars events are actually triggered through the LCD touch screen, hence you need to calibrate the touch screen (if you are restarting the EvoPrimer and have not calibrated the touch screen). Bottom line is, Without calibration, the tool bars won't work. 

4 comments:

  1. This is good ! I like the way you have edited the linker script.Earlier I used to think that this feature (extended memory) is available only in the Premium Version of Ride and wasted lot of time in reducing the Application size, but I think I can use this feature now.I will test it and let you know the result.

    ReplyDelete
    Replies
    1. Glad that this post helped you.
      The limitation you are talking of is on debugging your code on the primer with RIDE. I think the limit is 64 or 128 K. I am not sure how much that limit is.

      Delete
  2. Bonsoir, j'ai besoin de votre aide, j'aimerai faire un tableau de deux cases verticalement et 5 cases horizontalement dans l'ecran du module evoprimer je suis nouvelle dans ce domaine et je suis coincée .Donc comment je peux programmer ça sachant sue j'utilise le RIDE7 pour configurer l'evoprimer. Merci d'avance

    ReplyDelete
    Replies
    1. I've used google translate to understand what you've written and my understanding of your problem is on that basis.
      What I understand is that you want to draw a table using squares (I presume 2x2). You can easily accomplish this using LCD_FillRect() function. To get you started, I've written a small code for you. You can find it here http://pastebin.com/603braGN. Play with TABLE_COLS, TABLE_ROWS to get a feel of it. Hope this helps.

      Delete