{"id":505,"date":"2015-02-23T15:35:21","date_gmt":"2015-02-23T23:35:21","guid":{"rendered":"http:\/\/www.beyond-circuits.com\/wordpress\/?page_id=505"},"modified":"2016-07-25T15:03:48","modified_gmt":"2016-07-25T23:03:48","slug":"tutorial15","status":"publish","type":"page","link":"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial15\/","title":{"rendered":"Tutorial 15: A Software Stopwatch"},"content":{"rendered":"<p>In this tutorial, we will develop an ARM application that uses the <strong>stopwatch_controller<\/strong> IP which\u00a0we designed in the last two tutorials.<\/p>\n<h1>Exporting the Project to SDK<\/h1>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig1.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-512 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig1-300x192.png\" alt=\"tut15fig1\" width=\"300\" height=\"192\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig1-300x192.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig1.png 323w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>From your <strong>stopwatch_controller<\/strong> project in Vivado, select <em>File\u2192Export\u2192Export\u00b7Hardware&#8230;<\/em> . A dialog box will appear. Make sure that\u00a0<em>Export to<\/em> is set to <em>&lt;Local to Project&gt;<\/em> and the <em>include bitstream<\/em> box is checked.<\/p>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig2.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-513 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig2-300x206.png\" alt=\"tut15fig2\" width=\"300\" height=\"206\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig2-300x206.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig2.png 329w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Then select <em>File\u2192Launch SDK<\/em> to launch the Vivado Software Design Kit (SDK). When the dialog box appears click <em><strong>OK<\/strong><\/em>.<\/p>\n<h1>Creating a Software Project<\/h1>\n<p>After the SDK completes loading, we will need to add the <em>stopwatch_controller<\/em> repository to the software project. This lets the project use software drivers built for the stopwatch controller IP. Select Xilinx\u00b7Tools\u2192Repositories to bring up the Repositories dialog box. Click the New button and select the <em>stopwatch_controller_1.0<\/em> IP from the <em>ip_repo<\/em> directory. Click <strong><em>OK<\/em><\/strong>, and then <strong><em>OK<\/em><\/strong> again.<\/p>\n<p>Next, we will create a new application. Select <em>File\u2192New\u2192Application\u00b7Project<\/em>. Enter <em>Stopwatch<\/em> for the project name and click <strong><em>Next<\/em><\/strong>. Select the <em>Empty Application<\/em> template and then click <strong><em>Finish<\/em><\/strong>. <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig3.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-515 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig3-300x101.png\" alt=\"tut15fig3\" width=\"300\" height=\"101\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig3-300x101.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig3.png 396w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>This will create <em>Stopwatch<\/em> and <em>Stopwatch_bsp<\/em> projects, and will also create a tab called <em>system.mss<\/em>. In the system.mss tab, click the <strong><em>Modify this BSP Settings<\/em><\/strong> button.<\/p>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig4.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-516 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig4-300x187.png\" alt=\"tut15fig4\" width=\"300\" height=\"187\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig4-300x187.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig4.png 453w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>This will bring up the <em>Board Support Package Settings<\/em> dialog box.\u00a0Select the <em>drivers<\/em> tab, then scroll down the\u00a0component list until you see the <em>stopwatch_controller<\/em> component. <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig5.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-517 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig5-300x52.png\" alt=\"tut15fig5\" width=\"300\" height=\"52\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig5-300x52.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig5-500x87.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig5.png 790w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Select the <em>stopwatch_controller.<\/em>\u00a0Then, in the Drivers column, select <em>stopwatch_controller<\/em> from the pull-down menu.<\/p>\n<h1>Writing the ARM code<\/h1>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig6.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-518 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig6-300x100.png\" alt=\"tut15fig6\" width=\"300\" height=\"100\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig6-300x100.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig6-500x167.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig6.png 606w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Open up the <em>Stopwatch<\/em> project in the <em>Project Explorer<\/em> and right-click on the <em>src<\/em> folder. Select <em>New\u2192File<\/em>. This will bring up the <em>New File<\/em> dialog box. Enter <em>stopwatch.c<\/em> for the file name and click <strong><em>Finish<\/em><\/strong>. You can now edit the file.<\/p>\n<p>First,\u00a0we need some header files: one for controlling the ZYNQ processor in general and the other to bring\u00a0in items specific to our stopwatch controller. Here are the includes:<\/p>\n<pre><code>#include \"stopwatch_controller.h\"\r\n#include \"xparameters.h\"\r\n<\/code><\/pre>\n<p>Next we want to make some definitions which give us some simple names for the addresses of the registers in our IP block. We will use the defines from the <em>stopwatch_controller.h<\/em> file but give them names with more meaning for us. Here is the code:<\/p>\n<pre><code>\/* \tDefine the base memory addresses of the stopwatch_controller IP core *\/\r\n#define SW_BASE XPAR_STOPWATCH_CONTROLLER_0_S00_AXI_BASEADDR\r\n#define SSD_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG0_OFFSET\r\n#define LED_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG1_OFFSET\r\n#define SWITCH_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG2_OFFSET\r\n#define BTN_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG3_OFFSET\r\n#define ENC_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG4_OFFSET\r\n#define ENC_SW_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG5_OFFSET\r\n#define ENC_BTN_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG6_OFFSET\r\n#define TIMER_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG7_OFFSET\r\n<\/code><\/pre>\n<p>We are creating what is known as a <em>bare metal<\/em> software program. What this means is that there is no operating system running on the ARM while\u00a0our program runs. It&#8217;s just our program, and nothing else. What\u00a0that means is that our program should really never exit. Our goal is to have it\u00a0run in a loop and never exit. Each time through the loop, the program should do whatever processing is required at that point in time. So we will declare our C main routine and a while loop that never exits. For now, we&#8217;ll read all six of our input registers at the beginning of the loop, do some processing, and then write both of our output registers at the end of the loop. Here is the basic outline with an empty loop:<\/p>\n<pre><code>int main(void){\r\n  u32 ssd_val = 0;\r\n  u32 led_val = 0;\r\n  u32 switch_val = 0;\r\n  u32 btn_val = 0;\r\n  u32 enc_val = 0;\r\n  u32 enc_sw_val = 0;\r\n  u32 enc_btn_val = 0;\r\n  u32 timer_val = 0;\r\n\r\n  while(1){\r\n    switch_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, SWITCH_ADDR);\r\n    btn_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, BTN_ADDR);\r\n    enc_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, ENC_ADDR);\r\n    enc_sw_val= STOPWATCH_CONTROLLER_mReadReg(SW_BASE, ENC_SW_ADDR);\r\n    enc_btn_val= STOPWATCH_CONTROLLER_mReadReg(SW_BASE, ENC_BTN_ADDR);\r\n    timer_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR);\r\n    \/* Actions go here *\/\r\n    STOPWATCH_CONTROLLER_mWriteReg(SW_BASE, LED_ADDR, led_val);\r\n    STOPWATCH_CONTROLLER_mWriteReg(SW_BASE, SSD_ADDR, ssd_val);\r\n  }\r\n  return 1;\r\n}\r\n<\/code><\/pre>\n<p>The <code>STOPWATCH_CONTROLLER_mReadReg<\/code> function takes the base address of our stopwatch block and a register address, and returns the current value of the register. The <code> STOPWATCH_CONTROLLER_mWriteReg<\/code> function takes the same arguments and a value to write to the register. All that is left for us is to define some action to perform.<\/p>\n<p>As a starter, let&#8217;s just take the encoder value and write it to the SSD and LED outputs. Here is the code for that:<\/p>\n<pre><code>\r\n\t\/* Actions go here *\/\r\n\tssd_val = enc_val;\r\n\tled_val = enc_val;\r\n<\/code><\/pre>\n<p>All this does is assign the encoder value to the SSD and LED outputs. Go ahead and save the file. The SDK will automatically compile the code and you will see some warning about unused variables. You can ignore those.<\/p>\n<h1>Running the Program<\/h1>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig7.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-520 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig7-300x89.png\" alt=\"tut15fig7\" width=\"300\" height=\"89\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig7-300x89.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig7-500x149.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/tut15fig7.png 675w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Right-click on the <em>Stopwatch<\/em> application and select <em>Run\u2192Launch\u00b7on\u00b7Hardware\u00b7(GDB)<\/em>. You should see the value of the encoder register in the FPGA appear on the seven segment display and also in binary on the LEDs. This simple application demonstrates the power of combining an FPGA with an embedded processor. We have been able to take care of some simple tasks like maintaining the rotary encoder and controlling the seven segment display in the FPGA, while at the same time handling the higher-level control in a C program. In the next section we will add more stopwatch functions.<\/p>\n<h1>Counting the Seconds<\/h1>\n<p>Let&#8217;s add some more functions to our program. First, I want to keep around the rotary encoder display function. Let&#8217;s use the switch on the encoder to select the mode for our program. If the switch is in one position we will view the encoder value, if it is in the other we will display the stopwatch function. We will change the action section to have us an <strong>if<\/strong> statement:<\/p>\n<pre><code>\t\tif (enc_sw_val) { \/* encoder display *\/\r\n\t\t\tssd_val = enc_val;\r\n\t\t\tled_val = enc_val;\r\n\t\t} else { \/* stopwatch functions *\/\t\t\r\n\t\t}\r\n<\/code><\/pre>\n<p>Now, how do we manage the stopwatch functions? The FPGA hardware is keeping a millisecond counter for us. That counter is 32 bits, so it will be able to count for almost 50 days. To\u00a0display the counter, all our program needs to do is read the value, then decide which part of the counter to display. Like with our hardware example in <a title=\"Tutorial 8 \u2013 Stopwatch\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial8\/\">tutorial 8<\/a>, we will use the switch inputs to select which part of the counter we are displaying.<\/p>\n<p>Our first task is to break our millisecond counter value down into hundredths of seconds, seconds, minutes, hours, and days. We keep a 32-bit unsigned value for each one, and calculate the value based on the timer value.<\/p>\n<pre><code>u32 hundredths = (timer_val\/10)%100;\r\nu32 seconds = (timer_val \/ 1000)%60;\r\nu32 minutes = (timer_val \/ (60*1000)) % 60;\r\nu32 hours = (timer_val \/ (60*60*1000)) % 24;\r\nu32 days = (timer_val \/ (24*60*60*1000));\r\n<\/code><\/pre>\n<p>Next, we keep another 32-bit unsigned value to hold\u00a0the time we want to display. We first set it to <em>hundredths<\/em>,\u00a0then each subsequent larger time value based on the switch settings.<\/p>\n<pre><code>u32 time = hundredths;\r\nif (switch_val&amp;1) time = seconds;\r\nif (switch_val&amp;2) time = minutes;\r\nif (switch_val&amp;4) time = hours;\r\nif (switch_val&amp;8) time = days;\r\n<\/code><\/pre>\n<p>Finally, we need to display the time value. We need to keep in mind that the seven segment display displays hexadecimal values, so we need to convert the time value into BCD before displaying it. For the LEDs it makes more sense to display them in binary:<\/p>\n<pre><code>led_val = time;\r\nssd_val = ((time\/10)&lt;&lt;4)|(time%10);\r\n<\/code><\/pre>\n<h1>Start, Stop, and Clear<\/h1>\n<p>How do we start, stop, and clear the display? You may have noticed that, when you recompile and rerun your program, the time doesn&#8217;t reset. This is because the FPGA hardware is not being reloaded. The <em>timer<\/em> register counts independently of the software looking at it. We could add the function in the FPGA to start, stop, and clear the counter, but this isn&#8217;t really necessary. We can achieve all those effects in software.<\/p>\n<p>But first, we need to get some terminology straight. When we look at our program we will refer to a number of sections. There is the <em>definitions<\/em> section before the <strong>main<\/strong> declaration which we use to make definitions. Then there is an <em>initialization<\/em> before the <strong>while<\/strong> loop where we initialize variables when the program first runs. Inside the <strong>while<\/strong> loop, we have an <em>input<\/em> section where we read all the relevant registers. Then we have a <em>body<\/em> section where we perform some computations. Finally we have an <em>output<\/em> section where we update the hardware register values. Let&#8217;s look at our code again and add\u00a0comments at the beginning of each section. I will refer to these sections later when we add our additional features.<\/p>\n<p>Here is how our code looks right now with the sections commented:<\/p>\n<pre><code>#include \"stopwatch_controller.h\"\r\n#include \"xparameters.h\"\r\n\r\n\/* Definitions Section *\/\r\n\r\n\/* Define the base memory addresses of the stopwatch_controller IP core *\/\r\n#define SW_BASE XPAR_STOPWATCH_CONTROLLER_0_S00_AXI_BASEADDR\r\n#define SSD_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG0_OFFSET\r\n#define LED_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG1_OFFSET\r\n#define SWITCH_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG2_OFFSET\r\n#define BTN_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG3_OFFSET\r\n#define ENC_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG4_OFFSET\r\n#define ENC_SW_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG5_OFFSET\r\n#define ENC_BTN_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG6_OFFSET\r\n#define TIMER_ADDR STOPWATCH_CONTROLLER_S00_AXI_SLV_REG7_OFFSET\r\n\r\nint main(void){\r\n\t\/* Initialization section *\/\r\n\tu32 ssd_val = 0;\r\n\tu32 led_val = 0;\r\n\tu32 switch_val = 0;\r\n\tu32 btn_val = 0;\r\n\tu32 enc_val = 0;\r\n\tu32 enc_sw_val = 0;\r\n\tu32 enc_btn_val = 0;\r\n\tu32 timer_val = 0;\r\n\twhile(1){\r\n\t\t\/* Input section *\/\r\n\t\tswitch_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, SWITCH_ADDR);\r\n\t\tbtn_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, BTN_ADDR);\r\n\t\tenc_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, ENC_ADDR);\r\n\t\tenc_sw_val= STOPWATCH_CONTROLLER_mReadReg(SW_BASE, ENC_SW_ADDR);\r\n\t\tenc_btn_val= STOPWATCH_CONTROLLER_mReadReg(SW_BASE, ENC_BTN_ADDR);\r\n\t\ttimer_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR);\r\n\r\n\t\t\/* Computation section *\/\r\n\t\tif (enc_sw_val) { \/* encoder display *\/\r\n\t\t\tssd_val = enc_val;\r\n\t\t\tled_val = enc_val;\r\n\t\t} else { \/* stopwatch functions *\/\r\n\t\t\tu32 hundredths = (timer_val\/10)%100;\r\n\t\t\tu32 seconds = (timer_val \/ 1000)%60;\r\n\t\t\tu32 minutes = (timer_val \/ (60*1000)) % 60;\r\n\t\t\tu32 hours = (timer_val \/ (60*60*1000)) % 24;\r\n\t\t\tu32 days = (timer_val \/ (24*60*60*1000));\r\n\t\t\tu32 time = hundredths;\r\n\t\t\tif (switch_val&amp;1) time = seconds;\r\n\t\t\tif (switch_val&amp;2) time = minutes;\r\n\t\t\tif (switch_val&amp;4) time = hours;\r\n\t\t\tif (switch_val&amp;8) time = days;\r\n\t\t\tled_val = time;\r\n\t\t\tssd_val = ((time\/10)&lt;&lt;4)|(time%10);\r\n\t\t}\r\n\r\n\t\t\/* Output section *\/\r\n\t\tSTOPWATCH_CONTROLLER_mWriteReg(SW_BASE, LED_ADDR, led_val);\r\n\t\tSTOPWATCH_CONTROLLER_mWriteReg(SW_BASE, SSD_ADDR, ssd_val);\r\n\t}\r\n\treturn 1;\r\n}\r\n<\/code><\/pre>\n<p>First, we know we will need to use the buttons to control the board behavior. Let&#8217;s add some <strong>define<\/strong> statements to the <em>definitions<\/em> section. These defines indicate a mask for each of the button bits in the FPGA register.<\/p>\n<pre><code>#define BTN_C 16\r\n#define BTN_D 8\r\n#define BTN_R 4\r\n#define BTN_U 2\r\n#define BTN_L 1\r\n<\/code><\/pre>\n<p>We want to compute when a button rises. We can do that by keeping track of the button value from the previous time through the look and checking if it is different the next time through the loop. So we will add a new variable called <em>btn_val_prev<\/em> to the <em>initialization<\/em> section. This should be initialized to the current value of the button register.<\/p>\n<pre><code>u32 btn_val_prev = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, BTN_ADDR);\r\n<\/code><\/pre>\n<p>Then in the <em>input<\/em> section, we will use a new variable called <em>btn_val_rise<\/em> to compare the new button value with the previous button value.<\/p>\n<pre><code>u32 btn_val_rise = ~btn_val_prev &amp; btn_val;\r\n<\/code><\/pre>\n<p>Finally, in the output section, we need to transfer the current button value into the previous button value in preparation for the next time through the loop.<\/p>\n<pre><code>btn_val_prev = btn_val;\r\n<\/code><\/pre>\n<h2>Clearing the counter<\/h2>\n<p>To clear the counter, we should just remember the timer value when the clear button is pressed, and then in the rest of the code, use the difference between the timer value and the value when it was last cleared as the actual timer value.<\/p>\n<p>First, add a variable called <em>timer_zero<\/em> to the initialization section. This will hold the timer value whenever we clear the timer. In addition, it will initialize to the current timer value so when the program runs the timer starts at zero.<\/p>\n<pre><code>u32 timer_zero = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR);\r\n<\/code><\/pre>\n<p>Then, in the input section, we modify the assignment to timer_val to subtract off the timer_zero value:<\/p>\n<pre><code>timer_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR) - timer_zero;\r\n<\/code><\/pre>\n<p>Then in the computation section, we add a statement to set the <em>timer_zero<\/em> variable to the current timer value if the user presses the left button.<\/p>\n<pre><code>if (btn_val_rise&amp;BTN_C) timer_zero = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR);\r\n<\/code><\/pre>\n<p>Compile and run the program again. You should see the counter start at zero and clear whenever you press the left button.<\/p>\n<h2>Stopping the counter<\/h2>\n<p>It is pretty easy to stop the counter: we just stop reading the timer value. Just add a variable called stopped and initialize it with zero. Place this in the initialization section.<\/p>\n<pre><code>u32 stopped = 0;\r\n<\/code><\/pre>\n<p>Then in the input section, condition the assignment of <em>timer_val<\/em> based on not being stopped. Like this:<\/p>\n<pre><code>if (!stopped) timer_val = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR) - timer_zero;\r\n<\/code><\/pre>\n<p>Finally, in the computation section, you need to add a test to set the stopped flag if the center button is pushed.<\/p>\n<pre><code>if (btn_val_rise&amp;BTN_C) stopped = 1;\r\n<\/code><\/pre>\n<p>Go ahead and compile and run this. You should see the counter stop when you press the middle button.<\/p>\n<h1>Starting again<\/h1>\n<p>Stopping the count is great, but how do we start it up again? Well of course, we need to set the <em>stopped<\/em> flag back to zero. Even so,\u00a0that&#8217;s not enough. If that were\u00a0all we did, when we\u00a0started, the count would jump forward as if we\u00a0hadn&#8217;t stopped at all. This is not what we want. The solution is to adjust the <em>timer_zero<\/em> value as well. We basically need to add the amount of time we were stopped. Here is the code which we add to the <em>computation<\/em> section to do that when we press the right button:<\/p>\n<pre><code>if (stopped &amp;&amp; btn_val_rise&amp;BTN_R) {\r\n    stopped = 0;\r\n    timer_zero = STOPWATCH_CONTROLLER_mReadReg(SW_BASE, TIMER_ADDR) - timer_val;\r\n}\r\n<\/code><\/pre>\n<h1>Other useful features<\/h1>\n<p>I also added code which sets the <em>timer_zero<\/em> value to zero by pressing the up button, and added a resume button which resumes the display without updating the <em>timer_zero<\/em> value. Try to add those features yourself.<\/p>\n<h1>Files<\/h1>\n<p>Here is a link to the <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/tutorials\/tutorial15\/stopwatch.c\">stopwatch.c<\/a> file that I used for this tutorial.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we will develop an ARM application that uses the stopwatch_controller IP which\u00a0we designed in the last two tutorials. Exporting the Project to SDK From your stopwatch_controller project in Vivado, select File\u2192Export\u2192Export\u00b7Hardware&#8230; . A dialog box will appear. &hellip; <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial15\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":226,"menu_order":15,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-505","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/505","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/comments?post=505"}],"version-history":[{"count":11,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/505\/revisions"}],"predecessor-version":[{"id":1026,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/505\/revisions\/1026"}],"up":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/226"}],"wp:attachment":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/media?parent=505"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}