{"id":296,"date":"2013-02-06T11:00:03","date_gmt":"2013-02-06T19:00:03","guid":{"rendered":"http:\/\/micromouseusa.com\/?p=296"},"modified":"2013-05-06T16:43:31","modified_gmt":"2013-05-06T23:43:31","slug":"a-smarter-way-to-write-micros","status":"publish","type":"post","link":"http:\/\/micromouseusa.com\/?p=296","title":{"rendered":"a smarter way to write micros()"},"content":{"rendered":"<p>For those who use arduino before must know the function micros() returns system time in microseconds. AVR based arduinos use TIMER0 in MCU(such as ATMEGA328) to track system time. For cortex arm M0\/M3\/M4 processor, the most common way is to use systick to count system time. Typically people need system time in milli second level, so all they do is to set<\/p>\n<p><span style=\"color: #ffff00;\">volatile u32 Millis;<\/span><\/p>\n<p><span style=\"color: #ffff00;\">if (SysTick_Config (SystemCoreClock \/ 1000)) \/\/1ms per interrupt<\/span><br \/>\n<span style=\"color: #ffff00;\"> while (1);<\/span><\/p>\n<p><span style=\"color: #ffff00;\">and accumulate Millis every milli second in systick handler<\/span><\/p>\n<p><span style=\"color: #ffff00;\">void SysTick_Handler(void)<\/span><br \/>\n<span style=\"color: #ffff00;\"> Millis++;<\/span><\/p>\n<p>if you need system time in micro second, one way to do is let systick generates interrupt every 1us, accumulate the count for system time in micro second. the code will like this:<\/p>\n<p><span style=\"color: #ffff00;\">volatile u32 Millis;<\/span><\/p>\n<p><span style=\"color: #ffff00;\">volatile u32 Micros;<\/span><\/p>\n<p><span style=\"color: #ffff00;\">if (SysTick_Config (SystemCoreClock \/ 1000000)) \/\/1us per interrupt<\/span><br \/>\n<span style=\"color: #ffff00;\"> while (1);<\/span><\/p>\n<p><span style=\"color: #ffff00;\">and accumulate Millis every milli second in systick handler<\/span><\/p>\n<p><span style=\"color: #ffff00;\">void SysTick_Handler(void)<\/span><\/p>\n<p><span style=\"color: #ffff00;\">\u00a0\u00a0\u00a0 {Micros++; Millis %= Micros}<\/span><\/p>\n<p>However, this is not a good way to achieve your goal since you need to do Micros++ and Millis%=Micros every 72 cycles if your STM32 runs at 72Mhz, it takes too much system source even though the computation won&#8217;t take that much time every 72 cycles.<\/p>\n<p>After all, I found a way smarter way to count system time in micro second without sacrifice too much system performance.<\/p>\n<p>It&#8217;s really easy to achieve this, before I show my code, let&#8217;s do a refreshment of how systick works.<\/p>\n<p>Systick is a 24bit counting down timer in arm processor, you load a value for counter to count down at beginning, and the count amount decrease by 1 every one system cycle, when the count reaches 0, it will automatically reload and generate a systick interrupt. the counting down process doesn&#8217;t consume any system resources(tho it consumes power : D). In my new solution, I use systick to generate interrupt every 1 ms, accumulate the count for Millis only, and when I need system time in micro second, I get the value from register in systick called SYSTICK-&gt;VAL to get the current counter value to convert to the system I want in micro second. The advantage it doesn&#8217;t take any system resource when we don&#8217;t need system time in micros. Here is the code<\/p>\n<p><span style=\"color: #ff6600;\">void Systick_Init(void)<\/span><br \/>\n<span style=\"color: #ff6600;\"> {<\/span><br \/>\n<span style=\"color: #ff6600;\"> if (SysTick_Config (SystemCoreClock \/ 1000)) \/\/1ms per interrupt<\/span><br \/>\n<span style=\"color: #ff6600;\"> while (1);<\/span><\/p>\n<p><span style=\"color: #ff6600;\">\/\/set systick interrupt priority<\/span><br \/>\n<span style=\"color: #ff6600;\"> NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);\u00a0\u00a0 \u00a0\/\/4 bits for preemp priority 0 bit for sub priority<\/span><br \/>\n<span style=\"color: #ff6600;\"> NVIC_SetPriority(SysTick_IRQn, 0);\/\/i want to make sure systick has highest priority amount all other interrupts<\/span><\/p>\n<p><span style=\"color: #ff6600;\">Millis = 0;\/\/reset Millis<\/span><br \/>\n<span style=\"color: #ff6600;\"> }<\/span><\/p>\n<p><span style=\"color: #ff6600;\">u32 micros(void)<\/span><br \/>\n<span style=\"color: #ff6600;\"> {<\/span><\/p>\n<p><span style=\"color: #ff6600;\">\u00a0\u00a0\u00a0 Micros = Millis*1000 + 1000 &#8211; SysTick-&gt;VAL\/72;<\/span><\/p>\n<p><span style=\"color: #ff6600;\">\u00a0\u00a0\u00a0 \/\/ = Millis*1000+(SystemCoreClock\/1000-SysTick-&gt;VAL)\/72;<\/span><br \/>\n<span style=\"color: #ff6600;\"> return Micros;<\/span><\/p>\n<p><span style=\"color: #ff6600;\">}<\/span><\/p>\n<p><span style=\"color: #ff6600;\">u32 millis(void)<\/span><br \/>\n<span style=\"color: #ff6600;\"> {<\/span><br \/>\n<span style=\"color: #ff6600;\"> return Millis;<\/span><br \/>\n<span style=\"color: #ff6600;\"> }<\/span><\/p>\n<p><span style=\"color: #ff6600;\">void delay_ms(u32 nTime)<\/span><br \/>\n<span style=\"color: #ff6600;\"> {<\/span><br \/>\n<span style=\"color: #ff6600;\"> u32 curTime = Millis;<\/span><br \/>\n<span style=\"color: #ff6600;\"> while((nTime-(Millis-curTime)) &gt; 0);<\/span><br \/>\n<span style=\"color: #ff6600;\"> }<\/span><\/p>\n<p><span style=\"color: #ff6600;\">void delay_us(u32 nTime)<\/span><br \/>\n<span style=\"color: #ff6600;\"> {<\/span><br \/>\n<span style=\"color: #ff6600;\"> u32 curTime = Micros;<\/span><br \/>\n<span style=\"color: #ff6600;\"> while((nTime-(Micros-curTime)) &gt; 0);<\/span><br \/>\n<span style=\"color: #ff6600;\"> }<\/span><\/p>\n<p>and don&#8217;t forget to accumulate Millis in systick_handler<\/p>\n<p><span style=\"color: #ff6600;\">void SysTick_Handler(void)<\/span><br \/>\n<span style=\"color: #ff6600;\"> Millis++;<\/span><\/p>\n<p>in the function micros()<\/p>\n<p>we have this code:<\/p>\n<p><span style=\"color: #ffff99;\">Micros = Millis*1000 + 1000 &#8211; SysTick-&gt;VAL\/72<\/span><br \/>\n<span style=\"color: #ffff99;\"> return Micros;<\/span><\/p>\n<p>the equation was originally Millis*1000+(SystemCoreClock\/1000-SysTick-&gt;VAL)\/72;<\/p>\n<p>however, I found it takes a lot cycles, and it only take 25 cycles after I simplified the equation above to \u00a0\u00a0 Micros = Millis*1000 + 1000 &#8211; SysTick-&gt;VAL\/72 by tracking down the cycles in simulator in KEIL<\/p>\n<p>25 cycles is only 1\/3 of one micro second, which is accurate enough to tell the system time in micro second. If you don&#8217;t call micros() frequently, It will save a lot of your code execution time for some other functions. I ended up made my floodfill saved 100us from 610 us to 510us at one certain cell by simulation all japan 2011 maze with same amount of computation, that was a pretty big surprise for me. It also saved 4us for my printf function. a lot progress, wasn&#8217;t it?<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For those who use arduino before must know the function micros() returns system time in microseconds. AVR based arduinos use TIMER0 in MCU(such as ATMEGA328) to track system time. For cortex arm M0\/M3\/M4 processor, the most common way is to &hellip; <a href=\"http:\/\/micromouseusa.com\/?p=296\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[7],"tags":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/micromouseusa.com\/index.php?rest_route=\/wp\/v2\/posts\/296"}],"collection":[{"href":"http:\/\/micromouseusa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/micromouseusa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/micromouseusa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/micromouseusa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=296"}],"version-history":[{"count":20,"href":"http:\/\/micromouseusa.com\/index.php?rest_route=\/wp\/v2\/posts\/296\/revisions"}],"predecessor-version":[{"id":1231,"href":"http:\/\/micromouseusa.com\/index.php?rest_route=\/wp\/v2\/posts\/296\/revisions\/1231"}],"wp:attachment":[{"href":"http:\/\/micromouseusa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/micromouseusa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=296"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/micromouseusa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}