tag:blogger.com,1999:blog-32594466500394903422024-03-17T20:03:54.084-07:00ForceTronicsThe ForceTronics blog provides tutorials on creating fun and unique electronic projects. The goal of each project will be to create a foundation or jumping off point for amateur, hobbyist, and professional engineers to build on and innovate. Please use the comments section for questions and go to forcetronics.com for information on forcetronics consulting services.ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.comBlogger127125tag:blogger.com,1999:blog-3259446650039490342.post-3646892232457027142023-06-23T14:14:00.000-07:002023-06-23T14:14:08.593-07:00Tutorial on Routing Electrical Signal with Mechanical Relays<p> <span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In this two part series we take a look at mechanical relays: different types, terminology, theory of operation, and design considerations. We finish part one with a demo of an armature relay showing its inside, how to actuate it, and capture its flyback voltage waveform with an Oscilloscope. </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In part 2 we look at a simple circuit that allows us to control armature or reed relays with a simple digital pin from a microcontroller. We also look at a circuit design that allows us to avoid hot switching when using mechanical relays.</span></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/4SLLdkZ-Nec" width="320" youtube-src-id="4SLLdkZ-Nec"></iframe></div><br /><p><br /></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/aJlWzPX8Y8U" width="320" youtube-src-id="aJlWzPX8Y8U"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; text-align: start; white-space: pre-wrap;">Check us out on Patreon for exclusive content related to this series: </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; text-align: start; white-space: pre-wrap;">https://www.patreon.com/forcetronics</span></div><br /><p><br /></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-65766562782403627762023-04-26T19:31:00.005-07:002023-04-26T19:31:58.736-07:00Designing an Adjustable LED Drive Circuit<div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/zmVAo-aqm4E" width="320" youtube-src-id="zmVAo-aqm4E"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/j-8O6WXN328" width="320" youtube-src-id="j-8O6WXN328"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In this video series we implement an adjustable LED Drive circuit using the AL8862FF-7. </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"> In part 1 we review the target LED applications for our drive circuit and how the switch mode buck architecture of the AL8862FF-7 LED drive IC works. We then look at the schematic design for our circuit.</span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"> In part 2 we look at a demo of our LED Drive Circuit in action. We also take a look at the PCB layout of the LED Drive Circuit. At the end we look at measurement data from our circuit including the max and adjusted current values as well as look at measurements to calculate the efficiency of the design. The extended Patreon version of the video include more measurement data on the design and reviews the ESP32 Arduino code used in the demo. </span></div><div><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">
Link to ForceTronics Patreon Page: </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">https://www.patreon.com/forcetronics</span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">
AL8862FF-7 datasheet: </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">https://www.mouser.com/datasheet/2/115/AL8862-1274720.pdf</span></div><div><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><br /></span></div><div><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiPnyTedlGwiMCbX_GW5vfH2cF27dzyrEWzd-kb_LTsT8xbhghoGbrXdfXqKgxnlJnLwOQCjegi1xxko-WAuXf8jVpYMrrkHY1Gf-pujTwXfqwpSQJb8Y-LPS709ZXSFAPdpvd90uWC6yU09xPEx4bqW8HSVoKdPUHLs6pVbgZTLF_AeJfLbGKY9KQp8Q" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="680" data-original-width="1219" height="357" src="https://blogger.googleusercontent.com/img/a/AVvXsEiPnyTedlGwiMCbX_GW5vfH2cF27dzyrEWzd-kb_LTsT8xbhghoGbrXdfXqKgxnlJnLwOQCjegi1xxko-WAuXf8jVpYMrrkHY1Gf-pujTwXfqwpSQJb8Y-LPS709ZXSFAPdpvd90uWC6yU09xPEx4bqW8HSVoKdPUHLs6pVbgZTLF_AeJfLbGKY9KQp8Q=w640-h357" width="640" /></a></div><br /><br /></span></div>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-63861757952506115942023-02-23T19:49:00.002-08:002023-02-23T19:54:04.596-08:00Building a Dynamic ESP32 Wireless Network using the ESP-Now Protocol<p><span style="background-color: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt;">In this three part series we will design
a dynamic wireless network using ESP32 modules and leveraging EXPRESSIF's
ESP-NOW communication protocol.</span></p>
<p class="MsoNormal"><span style="background: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt; line-height: 107%;">In part 1 we provide an overview of the
ESP-NOW communication protocol and talk about how our dynamic wireless network
will work. <o:p></o:p></span></p><p class="MsoNormal"></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/BmBF29DmIiA" width="320" youtube-src-id="BmBF29DmIiA"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p class="MsoNormal"><span style="background: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt; line-height: 107%;">In part 2 we look at a simple
implementation of ESP-Now that will serve as a foundation for the dynamic
network we will design and cover in part 3.<o:p></o:p></span></p><p class="MsoNormal"></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/RFmEF0mIk74" width="320" youtube-src-id="RFmEF0mIk74"></iframe></div><br /><span style="background: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt; line-height: 107%;"><br /></span><p></p><div class="separator" style="clear: both;">
<p class="MsoNormal"><span style="background: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt; line-height: 107%;">Patreon page link: </span><span style="white-space: pre-wrap;">https://www.patreon.com/forcetronics</span><span style="white-space: pre-wrap;"> <o:p></o:p></span></p>
<p class="MsoNormal"><span style="background: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt; line-height: 107%;">ESP-NOW documentation: </span><span style="white-space: pre-wrap;">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html</span><o:p></o:p></p><p class="MsoNormal"><span style="white-space: pre-wrap;"><br /></span></p><p class="MsoNormal"><span style="white-space: pre-wrap;"> **************Part 3 coming soon*******************************</span></p></div><p class="MsoNormal"><br /><span style="background: white; color: #0d0d0d; font-family: Roboto; font-size: 11.5pt; line-height: 107%;"><br /></span></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-39036017268588746472023-01-06T17:51:00.003-08:002023-01-29T11:02:55.264-08:00Designing a Li-Ion and USB Power Circuit with Built-in Charging<p>T<span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;">his video series will take you step by step through how to design a circuit that can be powered from a USB input (5V) or from a Lithium Ion battery cell and output a regulated 5V. The design includes a battery charging circuit and a circuit that automatically isolates the battery from the power bus when USB power is applied. </span></p><p>Please support ForceTronics on Patreon: <a href="http://patreon.com/forcetronics">patreon.com/forcetronics</a></p><p><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;">In part one we review the overall plan for the design, go over Li-ion battery cell basics, and give a crash course on boost switching voltage regulators.
</span></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/ZCEw7gVe8eU" width="320" youtube-src-id="ZCEw7gVe8eU"></iframe></div><br />
Battery university link: <span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;">https://batteryuniversity.com/</span><p></p><p><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;"><br /></span></p><p><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;">In part two we go into detail on our boost switching regulator design using Texas Instruments TPS61202 5-V fixed output voltage boost converter.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/i3sw2wDRw4k" width="320" youtube-src-id="i3sw2wDRw4k"></iframe></div><br /><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;"><br /></span><p></p><p><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;">Link to TI’s TPS61202 product page: </span><span face="Roboto, Noto, sans-serif" style="background-color: white; color: #0d0d0d; font-size: 15px; white-space: pre-wrap;">https://www.ti.com/product/TPS61202?qgpn=tps61202</span></p><p>In part three we look at the battery charging circuit and the power source isolation circuit</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/cDRjSY4ImSo" width="320" youtube-src-id="cDRjSY4ImSo"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Link to MAX1898 battery charging IC datasheet: https://www.mouser.com/datasheet/2/256/MAX1898-1515496.pdf</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">In part 4 we look at the PCB layout for our circuits and we see a demo of our circuits in action</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/w5UP5i0h8is" width="320" youtube-src-id="w5UP5i0h8is"></iframe></div><br /><div class="separator" style="clear: both; text-align: left;"><br /></div><div><br /></div>Circuit Block Diagram<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieXIwPCx-ePiFEog1xvh_El9YZqizYsG8eAq7W0lK2RlS1rz9O_N197dk5CjiKH79lsjJxkZDtq41M4UJZ9-VIEmEryheeHxoCwO0yIUn_3mcZeDsUoR3DO9G-jlWjlilxQhvOq9fvUsq_uOozzPvKYgGhBI6sD3Zub5t7dYWsA0fMAjwmZ9Plkr0nUQ/s1035/diagram.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="490" data-original-width="1035" height="302" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieXIwPCx-ePiFEog1xvh_El9YZqizYsG8eAq7W0lK2RlS1rz9O_N197dk5CjiKH79lsjJxkZDtq41M4UJZ9-VIEmEryheeHxoCwO0yIUn_3mcZeDsUoR3DO9G-jlWjlilxQhvOq9fvUsq_uOozzPvKYgGhBI6sD3Zub5t7dYWsA0fMAjwmZ9Plkr0nUQ/w640-h302/diagram.PNG" width="640" /></a></div><br /><div><br /><p><br /></p></div></div>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-72654686298143879412022-12-04T15:19:00.001-08:002022-12-04T15:19:24.750-08:00How to Design a Programming Circuit for the ESP32<p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In the video we look at how to design a circuit for programming an ESP32 module. We also explain the Strapping Pins on the ESP32 and how they work.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/XbPMfoKi8kk" width="320" youtube-src-id="XbPMfoKi8kk"></iframe></div><br /><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><br /></span><p></p><p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">Oscilloscope Capture of EN pin and GPIO0 setting ESP32 in Download Boot Mode</span></p><p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjD7T0YyKFHGbfY20Mvt4oTqVAdY-nWk12VIU2cGRNlwu7XImjiimnAvk6GBp_XUr9l3_Iwdf7eCReuy-vl8BsCozeWXq2XpsKW2LjiaV0AkR8QTRulY2E1avlmOITU_Tl3sCNg4KiZFTtQM9cwqdVRefWv--ZuRjAYpj5yg3nuT1KNKPOlB7M4dlmxBA" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="560" data-original-width="745" height="482" src="https://blogger.googleusercontent.com/img/a/AVvXsEjD7T0YyKFHGbfY20Mvt4oTqVAdY-nWk12VIU2cGRNlwu7XImjiimnAvk6GBp_XUr9l3_Iwdf7eCReuy-vl8BsCozeWXq2XpsKW2LjiaV0AkR8QTRulY2E1avlmOITU_Tl3sCNg4KiZFTtQM9cwqdVRefWv--ZuRjAYpj5yg3nuT1KNKPOlB7M4dlmxBA=w640-h482" title="Oscilloscope Capture of EN and GPIO Signals" width="640" /></a></div><br /><br /><p></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-68113571929504737692022-11-27T13:57:00.000-08:002022-11-27T13:57:20.239-08:00How to Use a USB Type-C Connector in Your Next Microcontroller Based Project<p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In this video we give an overview of the USB type-C connector standard along with other related USB standards. We then look at an example design that implements a USB type-C connector and converts the USB 2.0 communication to serial or UART communication. You can then use the serial data to communicate, debug, or program your microcontroller for programming environments such as Arduino.</span></p><p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/c0yRkn_vO3Y" width="320" youtube-src-id="c0yRkn_vO3Y"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">TI USB Type C Application Note: </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><a href="https://www.ti.com/lit/wp/slyy109b/slyy109b.pdf?ts=1669008410178&ref_url=https%253A%252F%252Fwww.google.com%252F">https://www.ti.com/lit/wp/slyy109b/slyy109b.pdf?ts=1669008410178&ref_url=https%253A%252F%252Fwww.google.com%252F</a></span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">
ST Micro USB Type C Application Note: </span><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><a href="https://www.st.com/resource/en/technical_article/dm00496853-overview-of-usb-type-c-and-power-delivery-technologies-stmicroelectronics.pdf">https://www.st.com/resource/en/technical_article/dm00496853-overview-of-usb-type-c-and-power-delivery-technologies-stmicroelectronics.pdf</a></span></div><p>USB Type C Connector example implementation</p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhkmgwXfcK0jY5KdvQTNhDANSYdDLGEGrMEokMDBNGkGpuBVsdw4rbCldUcZSDbhETAwraoopWljFFdOrgF5CnR3Z9-oLHnydJTxLYBEAw9SORwwHVE5kispvDdtSyxPSTpHSt-cH0zCiusQDySztnvIJlOV7k5SLbODsfm1rI4vOHdrDoBkCPnxOwOXw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="647" data-original-width="1148" height="360" src="https://blogger.googleusercontent.com/img/a/AVvXsEhkmgwXfcK0jY5KdvQTNhDANSYdDLGEGrMEokMDBNGkGpuBVsdw4rbCldUcZSDbhETAwraoopWljFFdOrgF5CnR3Z9-oLHnydJTxLYBEAw9SORwwHVE5kispvDdtSyxPSTpHSt-cH0zCiusQDySztnvIJlOV7k5SLbODsfm1rI4vOHdrDoBkCPnxOwOXw=w640-h360" width="640" /></a></div><br /><br /></span><p></p><p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">USB 2.0 communication converted to UART / Serial</span></p><p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiMBQDGQs9MDN-JewU3c2xDloaETYdNX5t2f4sDYrLnzZpTjeU1Iw4JJ1GpGJ2kJnO9OQlr4Br2elhJKVSJvVhQ5G6iw_qXSx6kbvuCK85Uk-WwVfkXnRzXZCbIN-wwpcOPiBwCKXBx1f5Xhav62uP0zYNppWt-vT5gKedbpQewnkuPWHZ4OwkZTIMH9w" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="621" data-original-width="1161" height="342" src="https://blogger.googleusercontent.com/img/a/AVvXsEiMBQDGQs9MDN-JewU3c2xDloaETYdNX5t2f4sDYrLnzZpTjeU1Iw4JJ1GpGJ2kJnO9OQlr4Br2elhJKVSJvVhQ5G6iw_qXSx6kbvuCK85Uk-WwVfkXnRzXZCbIN-wwpcOPiBwCKXBx1f5Xhav62uP0zYNppWt-vT5gKedbpQewnkuPWHZ4OwkZTIMH9w=w640-h342" width="640" /></a></div><br /><br /><p></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-44829461617043470002022-09-14T14:37:00.000-07:002022-09-14T14:37:16.283-07:00How to Control Water Flow with Arduino IoT Cloud and a Solenoid Parts 1 and 2<p><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In this two part series we look at how to control a Solenoid using an ESP32 board and the Arduino IoT Cloud. In part one we focus on what a solenoid is and the hardware needed to drive a solenoid open or closed. In part 2 we focus on setting up the Arduino IoT Cloud control. </span></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/SjSJKjIcOA0" width="320" youtube-src-id="SjSJKjIcOA0"></iframe>\</div><p><br /></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/v6e3KRIlFBM" width="320" youtube-src-id="v6e3KRIlFBM"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Link to tutorial on setting up device on Arduino IoT Cloud: <a href="https://docs.arduino.cc/arduino-cloud/getting-started/esp-32-cloud" style="text-decoration-line: none;"><span style="color: #0097a7; font-family: Arial; font-size: 15pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://docs.arduino.cc/arduino-cloud/getting-started/esp-32-cloud</span></a></div><br /><div><br /></div><div><span style="color: #2b00fe;">//**************Arduino Code from Tutorial*********************</span></div><div><div><span style="color: #2b00fe;">#include "thingProperties.h"</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;">#define SOLENOID_PIN 21</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;">void setup() {</span></div><div><span style="color: #2b00fe;"> pinMode(SOLENOID_PIN,OUTPUT);</span></div><div><span style="color: #2b00fe;"> digitalWrite(SOLENOID_PIN,LOW);</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;"> // Defined in thingProperties.h</span></div><div><span style="color: #2b00fe;"> initProperties();</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;"> // Connect to Arduino IoT Cloud</span></div><div><span style="color: #2b00fe;"> ArduinoCloud.begin(ArduinoIoTPreferredConnection);</span></div><div><span style="color: #2b00fe;"> </span></div><div><span style="color: #2b00fe;"> /*</span></div><div><span style="color: #2b00fe;"> The following function allows you to obtain more information</span></div><div><span style="color: #2b00fe;"> related to the state of network and IoT Cloud connection and errors</span></div><div><span style="color: #2b00fe;"> the higher number the more granular information you’ll get.</span></div><div><span style="color: #2b00fe;"> The default is 0 (only errors).</span></div><div><span style="color: #2b00fe;"> Maximum is 4</span></div><div><span style="color: #2b00fe;"> */</span></div><div><span style="color: #2b00fe;"> setDebugMessageLevel(2);</span></div><div><span style="color: #2b00fe;"> ArduinoCloud.printDebugInfo();</span></div><div><span style="color: #2b00fe;">}</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;">void loop() {</span></div><div><span style="color: #2b00fe;"> ArduinoCloud.update();</span></div><div><span style="color: #2b00fe;"> </span></div><div><span style="color: #2b00fe;"> if(water_Scheduler.isActive() || solenoidState) {</span></div><div><span style="color: #2b00fe;"> digitalWrite(SOLENOID_PIN, HIGH);</span></div><div><span style="color: #2b00fe;"> }</span></div><div><span style="color: #2b00fe;"> else {</span></div><div><span style="color: #2b00fe;"> digitalWrite(SOLENOID_PIN, LOW);</span></div><div><span style="color: #2b00fe;"> } </span></div><div><span style="color: #2b00fe;">}</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;">/*</span></div><div><span style="color: #2b00fe;"> Since SolenoidState is READ_WRITE variable, onSolenoidStateChange() is</span></div><div><span style="color: #2b00fe;"> executed every time a new value is received from IoT Cloud.</span></div><div><span style="color: #2b00fe;">*/</span></div><div><span style="color: #2b00fe;">void onSolenoidStateChange() {</span></div><div><span style="color: #2b00fe;"> // Add your code here to act upon SolenoidState change</span></div><div><span style="color: #2b00fe;"> /*</span></div><div><span style="color: #2b00fe;"> if (solenoidState) {</span></div><div><span style="color: #2b00fe;"> digitalWrite(SOLENOID_PIN, HIGH);</span></div><div><span style="color: #2b00fe;"> }</span></div><div><span style="color: #2b00fe;"> else {</span></div><div><span style="color: #2b00fe;"> digitalWrite(SOLENOID_PIN, LOW);</span></div><div><span style="color: #2b00fe;"> } </span></div><div><span style="color: #2b00fe;"> */</span></div><div><span style="color: #2b00fe;">}</span></div><div><span style="color: #2b00fe;"><br /></span></div><div><span style="color: #2b00fe;">/*</span></div><div><span style="color: #2b00fe;"> Since WaterScheduler is READ_WRITE variable, onWaterSchedulerChange() is</span></div><div><span style="color: #2b00fe;"> executed every time a new value is received from IoT Cloud.</span></div><div><span style="color: #2b00fe;">*/</span></div><div><span style="color: #2b00fe;">void onWaterSchedulerChange() {</span></div><div><span style="color: #2b00fe;"> // Add your code here to act upon WaterScheduler change</span></div><div><span style="color: #2b00fe;">}</span></div></div><div><br /></div>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com1tag:blogger.com,1999:blog-3259446650039490342.post-60815453703843496182021-11-13T14:42:00.000-08:002021-11-13T14:42:24.636-08:00How to Build a Switch Debounce Circuit for a Rotary Encoder<p style="text-align: center;"> <iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/iwyARHUbvNI" width="320" youtube-src-id="iwyARHUbvNI"></iframe></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In this tutorial we look at how to combat switch bounce when using a rotary encoder with a debounce circuit made up of fairly basic components (see below). We use the KY-040 encoder as the test subject in the video. Below is the parts list from the video.</span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">
Parts list: BAS16-HE3-18 (Diode), SN74LVC1G17QDCKRQ1 (Schmitt Trigger), standard 0805 resistors (300ohms and 15kohms), and 4.7uF 0805 ceramic capacitor</span></div><div class="separator" style="clear: both; text-align: left;"><span id="docs-internal-guid-1fcd95e7-7fff-5fd5-8f50-5465e827acb2"><img height="282" src="https://lh4.googleusercontent.com/4cXKQ6_eR8dEh_cT-55hFoXxYdJ6Q0n8MAYk5K8vED3pYLMwXvR3wW3S7iNeY8ytkzzCPH7AtrqZcD3mdsK870V3gfwRy6_oVtyla_HGScl_VXRLsD7Td5x0vhmYn2j99MXR0B50LJu6=w640-h282" width="640" /></span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">Code from example ESP32 and KY-040 application in the video</span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #0d0d0d; font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">//**************************************************************************************************************</span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; font-size: 15px; white-space: pre-wrap;"><span style="color: #2b00fe; font-family: Roboto, Noto, sans-serif;">//This sketch demonstrates how to use the KY-040 encoder
//link to KY-040 https://www.epitran.it/ebayDrive/datasheet/25.pdf
//encoder pins
#include <Adafruit_NeoPixel.h>
#define ECLK 26 //encoder CLK pin
#define EDT 25 //encoder DT pin
#define ESW 35 //encoder SW pin
#define LED_PIN 13 //pin for LED comm
#define LED_CNT 1 //LED cnt
#define BRIGHTNESS 125 //LED brightness setting
//First argument is number of LEDs, second is arduino pin
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(LED_CNT,LED_PIN, NEO_GRB + NEO_KHZ800);
const uint32_t off = pixels.Color(0, 0, 0); //RGB value for off
const uint32_t white = pixels.Color(127, 127, 127); //RGB color for white
const uint32_t blue = pixels.Color(30,144,255); //RGB color for blue
const uint32_t red = pixels.Color(255, 0, 0); //RGB color for red
volatile bool buttonFlag = false; //flag that tracks if button was pressed
volatile uint8_t encoderFlag = 0; //flog for tracking encoder turns
bool ledState = false; //tracks whether to turn LED off or on for button presses
//interrupt service routine for an encoder turn CC or CCW
void IRAM_ATTR ISR() { encoderFlag = true; }
//interrupt service routine for an encoder button press
void IRAM_ATTR ISR2() {
buttonFlag = true;
}
void setup() {
pinMode(ECLK,INPUT); //setup encoder pins
pinMode(EDT,INPUT);
pinMode(ESW,INPUT);
attachInterrupt(ECLK, ISR, FALLING); //setup encoder interrupts
attachInterrupt(ESW, ISR2, FALLING);
pixels.begin(); //start RGB LED object
pixels.setBrightness(BRIGHTNESS); //set LED brightness
setLED(off); //set LED off
}
void loop() {
if(encoderFlag) { //encoder knob was turned
if(digitalRead(EDT)) { //encoder turned clockwise
setLED(blue);
}
else { //encoder was turned counter clockwise
setLED(red);
}
encoderFlag = false; //reset flag
}
if(buttonFlag) { //button was pressed
buttonFlag = false; //reset flag
if(ledState) {
setLED(off);
ledState = false;
}
else {
setLED(white);
ledState = true;
}
}
}
//sets LED to a specified RGB color
//input is the RGB value
void setLED(uint32_t color) {
for(int i=0;i<1;i++){
pixels.setPixelColor(i,color); //set LED color
pixels.show(); //send updated state to LED
}
}</span></span></div> </div><br /> ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-33020916996278881032020-12-22T18:59:00.000-08:002020-12-22T18:59:09.136-08:00How to Setup and Change the System Clock on the SAMD21 Microcontroller Family <p><span style="background-color: #f9f9f9; color: #030303; font-family: Roboto, Arial, sans-serif; font-size: 14px; white-space: pre-wrap;">In this video we look at how to setup and change the system clock on the SAMD21 family of microcontrollers from Microchip / Atmel. This example code is written in C++ and uses direct register access. </span></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/_oiv19ggDVM" width="320" youtube-src-id="_oiv19ggDVM"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><span id="docs-internal-guid-f30bdf26-7fff-1cb2-6f95-922152964167"><span style="font-family: Arial; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: large;">Where to access the two versions of the code</span></span></span></div><div class="separator" style="clear: both; text-align: center;"><span><span style="font-family: Arial; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: large;"><br /></span></span></span></div><div class="separator" style="clear: both; text-align: center;"><span id="docs-internal-guid-85ac3394-7fff-7f64-f26a-714412e0b587"><ul style="margin-bottom: 0; margin-top: 0;"><li dir="ltr" style="font-family: Arial; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Free version can be found on GitHub: </span><a href="https://github.com/ForceTronics/SamD21_Clock_Setup" style="text-decoration-line: none;"><span style="color: #0097a7; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://github.com/ForceTronics/SamD21_Clock_Setup</span></a></p></li><li dir="ltr" style="font-family: Arial; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">For pay version includes the following additional features:</span></p></li><ul style="margin-bottom: 0; margin-top: 0;"><li dir="ltr" style="font-family: Arial; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: circle; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="background-color: white; color: #1d1d1d; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Demonstrates how to use the calibration values stored in NVM to tune the 48MHz clock for higher accuracy</span></p></li><li dir="ltr" style="color: #1d1d1d; font-family: Arial; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: circle; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="background-color: white; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Allows you to change the system clock to 48MHz, 8MHz, 1MHz, and 32768Hz</span></p></li><li dir="ltr" style="color: #1d1d1d; font-family: Arial; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: circle; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="background-color: white; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Shows how to output the system clock from pin PA27</span></p></li></ul><li dir="ltr" style="color: #1d1d1d; font-family: Arial; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 12pt; margin-top: 0pt; text-align: left;"><span style="background-color: white; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Link to code on ForceTronics.com: </span><a href="http://www.forcetronics.com/example-code-for-purchase/samd21-clock-setup-and-control-c-code-example" style="text-decoration-line: none;"><span style="background-color: white; color: #0097a7; font-size: 18pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">http://www.forcetronics.com/example-code-for-purchase/samd21-clock-setup-and-control-c-code-example</span></a></p></li></ul></span></div><br /><p><br /></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com5tag:blogger.com,1999:blog-3259446650039490342.post-10252286172386873482020-11-29T17:14:00.003-08:002020-11-29T17:14:27.510-08:00How to Design 24VAC to DC Power Supply for HVAC Applications Part 2<p><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In the video we look at how to design a 24VAC power supply for industrial and HVAC applications. The supply will be flexible enough to handle DC voltage inputs. The power supply will employ a DC to DC buck converter, half wave rectifier, input protection against over voltage, and output noise reduction circuit features. In part 2 we look at the PCB design, the finished product, and capture some test data to see how it is working.</span></p><p><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/dBb105UsHBc" width="320" youtube-src-id="dBb105UsHBc"></iframe></div><br /><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;"><br /></span><p></p><p style="text-align: center;"><span id="docs-internal-guid-5591a40c-7fff-ad2f-17a0-ddbe7dc88354"><img height="254" src="https://lh5.googleusercontent.com/VO04bpOzfoduGDnxwx1alk025VDR_DhHWiYbHcpDdNkl-ZAHgRV3maxLMcQdc4Jf8KCXiM04m7bGxVt_JLcZG1qD-grEM0U03OdF5xpj5cr0wEOmSHTydc10DAvPRIiTVJtdNSqjoZQ=w640-h254" width="640" /></span></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com2tag:blogger.com,1999:blog-3259446650039490342.post-54919579292783556072020-11-16T15:51:00.001-08:002020-11-16T15:51:25.402-08:00How to Design a 24VAC to DC Power Supply for HVAC Applications Part 1<p> <span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In the video we look at how to design a 24VAC power supply for industrial and HVAC applications. The supply will be flexible enough to handle DC voltage inputs. The power supply will employ a DC to DC buck converter, half wave rectifier, input protection against over voltage, and output noise reduction circuit features</span></p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/V779Q4bjwJw" width="320" youtube-src-id="V779Q4bjwJw"></iframe></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">Link to the ferrite bead article mentioned in the video: </span><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">https://www.analog.com/en/analog-dialogue/articles/ferrite-beads-demystified.html#</span><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">
Link to TI Webbench Power Designer tool: </span><span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">https://webench.ti.com/power-designer/switching-regulator</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><span id="docs-internal-guid-6bc56028-7fff-6060-7ff8-3c029205378b"><img height="254" src="https://lh4.googleusercontent.com/gjL9wi5xkoLCQudB6LMDovVo1jk1saEI_dadugjr4xO1IdzhVhh7eaSUgzNN9QViUbqAd_nClwURhD_HLWejejSW1eSz92nvwifBgvDtIv2txtgyHkWhsXv4dm8zNDTTYn4kNTBFhN8=w640-h254" width="640" /></span></div><br /><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwg8twK5I4f4sAz-s525ihqa8DhbQpF8AFsZo79laItKzZVgHBMHHYkmtzTD2RBrCmRmkXh4d823I409g0nmj2b2hL-XLuHaD2NZq9G_al2r80bkkuU6zwtRJdMXmGocOuw8BPbGDAUhhx/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="552" data-original-width="941" height="376" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwg8twK5I4f4sAz-s525ihqa8DhbQpF8AFsZo79laItKzZVgHBMHHYkmtzTD2RBrCmRmkXh4d823I409g0nmj2b2hL-XLuHaD2NZq9G_al2r80bkkuU6zwtRJdMXmGocOuw8BPbGDAUhhx/w640-h376/image.png" width="640" /></a></div><br /><br /><p></p>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-2609038731706786642019-12-09T08:55:00.000-08:002019-12-09T08:55:49.550-08:00Designing an Automatic Battery Cutoff Circuit to Prevent Over Discharge of Rechargeable Batteries Part 2<span style="color: rgba(0, 0, 0, 0.87); font-family: Roboto, Noto, sans-serif; font-size: 15px; white-space: pre-wrap;">In this video we will design an automatic battery cutoff circuit to prevent damaging over discharge of rechargeable batteries. In part 2 we test the design and discuss MOSFET and Voltage Detector specs.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/cLD4OWrYO4w/0.jpg" src="https://www.youtube.com/embed/cLD4OWrYO4w?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<span id="docs-internal-guid-c3a2e735-7fff-60af-7d38-44f95a648db7"></span><br />
<br /><br />BOM of battery cutoff circuit: <div>
<ul>
<li>S-1011A70-M6T1U4 Voltage Detector from ABLIC</li>
<li>DMP4015SSS-13 P Chan MOSFET from Diodes Inc</li>
<li>BSS138 N Chan MOSFET from multiple manufacturers</li>
<li>RSX051VYM30FHTR Schottky Diode from ROHM Semi</li>
<li>2x 3.3 nF Ceramic Capacitor</li>
<li>~100 kOhm Resistor</li>
<li>1 to 10 MOhm Resistor (used 4.7M in example circuit)</li>
</ul>
<div>
<br /></div>
</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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOL1RX81nn4xgFcnKGbf9uUAZXlBUxjMNkq8-Vcg9bl1KGrqLf1bVVbX2BMJ3fgB_TTQS9Jg2r82jGXJsmdQIChAWsB-rfRM3w2wsPWDqMY2TxA5G01qPvFCNrz56tdueBhqdXMgVPoYmi/s1600/Capture.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1353" data-original-width="1600" height="540" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOL1RX81nn4xgFcnKGbf9uUAZXlBUxjMNkq8-Vcg9bl1KGrqLf1bVVbX2BMJ3fgB_TTQS9Jg2r82jGXJsmdQIChAWsB-rfRM3w2wsPWDqMY2TxA5G01qPvFCNrz56tdueBhqdXMgVPoYmi/s640/Capture.PNG" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PCB Layout of Battery Cutoff Circuit</td></tr>
</tbody></table>
<div>
<br /></div>
ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-43343489898647154592019-11-29T07:22:00.000-08:002019-12-09T08:58:12.939-08:00Designing an Automatic Battery Cutoff Circuit to Prevent Over Discharge of Rechargeable Batteries Part 1<span style="background-color: #f9f9f9; color: #0d0d0d; font-family: "roboto" , "arial" , sans-serif; font-size: 14px; white-space: pre-wrap;">In this video we will design an automatic battery cutoff circuit to prevent damaging over discharge of rechargeable batteries. To design our battery cutoff circuit we will use a Voltage Detector or Reset IC.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/s9IoFANIxkE/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/s9IoFANIxkE?feature=player_embedded" width="320"></iframe></div>
<br />
BOM from video:<br />
<br />
<ul>
<li>S-1011A70-M6T1U4 Voltage Detector from ABLIC </li>
<li>DMP4015SSS-13 P Chan MOSFET from Diodes Inc </li>
<li>BSS138 N Chan MOSFET from multiple manufacturers </li>
<li>RSX051VYM30FHTR Schottky Diode from ROHM Semi </li>
<li>2x 3.3 nF Ceramic Capacitor </li>
<li>~100 kOhm Resistor </li>
<li>1 to 10 MOhm Resistor</li>
</ul>
<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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSBxVPPf0khFyUnQ3D_BsGI1iRIRycgYncphyCn_8hOt9_AkBjFoCj5mBEDOOOzLIJSTl2qc1m9TxqpvVtchqOLAvb42iZoklAdllszbu5Bak0CYsaCQD7qc_jzJifUYRO2ZDnq8eLOAnL/s1600/Batt+Cutoff+Circuit.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="586" data-original-width="998" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSBxVPPf0khFyUnQ3D_BsGI1iRIRycgYncphyCn_8hOt9_AkBjFoCj5mBEDOOOzLIJSTl2qc1m9TxqpvVtchqOLAvb42iZoklAdllszbu5Bak0CYsaCQD7qc_jzJifUYRO2ZDnq8eLOAnL/s640/Batt+Cutoff+Circuit.PNG" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Battery Cutoff Circuit Schematic</td></tr>
</tbody></table>
<div>
<span style="color: #595959; font-family: "arial";"><span style="white-space: pre-wrap;"><br /></span></span></div>
ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-81922749771924499722019-05-31T11:38:00.001-07:002019-05-31T11:38:33.037-07:00Ways to Improve ADC Measurement Accuracy and Resolution Part 2<span style="background-color: white; color: #0a0a0a; font-family: Roboto, Arial, sans-serif; font-size: 14px; white-space: pre-wrap;">In part two of this 4 or 5 part series, we look at how the Successive Approximation or SAR ADC architecture works and understand its limitations. Note SAR based ADC architecture is what you typically find in microcontrollers. </span><br />
<span style="background-color: white; color: #0a0a0a; font-family: Roboto, Arial, sans-serif; font-size: 14px; white-space: pre-wrap;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/rDDiPzJpI18/0.jpg" src="https://www.youtube.com/embed/rDDiPzJpI18?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<span style="background-color: white; color: #0a0a0a; font-family: Roboto, Arial, sans-serif; font-size: 14px; white-space: pre-wrap;"><br /></span>
<span style="background-color: white; color: #0a0a0a; font-family: Roboto, Arial, sans-serif; font-size: 14px; white-space: pre-wrap;">To access the white paper that was referenced to derive the equation related to RC time constants and sampling time: </span><span style="color: #2200cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"><a href="https://www.silabs.com/documents/public/application-notes/AN119.pdf" style="text-decoration-line: none;">https://www.silabs.com/documents/public/application-notes/AN119.pdf</a></span><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="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC0pfrcWq-aIus9eSYD3ltZFjMbdVX57F6hQSGiA6IbdbeJ9vGd6-co_1ZnFCtdvlPsYrdey1HKW7cLA9pSoIzQAAdd8QcJ2gUSTwFq8AolnPUQDR8TRpnao1Ld2G2DPFXrQc0hwXTzg-X/s1600/Setting+time+equation.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="811" data-original-width="936" height="552" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC0pfrcWq-aIus9eSYD3ltZFjMbdVX57F6hQSGiA6IbdbeJ9vGd6-co_1ZnFCtdvlPsYrdey1HKW7cLA9pSoIzQAAdd8QcJ2gUSTwFq8AolnPUQDR8TRpnao1Ld2G2DPFXrQc0hwXTzg-X/s640/Setting+time+equation.PNG" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Cutout from Silicon Labs App Note on calculating settling time for SAR ADC</td></tr>
</tbody></table>
<br />ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-48131184780969336222019-03-30T14:15:00.001-07:002019-03-30T14:15:53.212-07:00Ways to Improve ADC Measurement Accuracy and Resolution Part 1In this video series we look at ways or tips to improve ADC measurement accuracy and resolution. In part 1 define what accuracy and resolution is and different types of error that can affect ADC measurements. We also look at the importance of using an accurate ADC reference voltage and why you want to scale the range of the signal you are measuring to the ADC's range.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/e20j4Vw5BbI/0.jpg" src="https://www.youtube.com/embed/e20j4Vw5BbI?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
//***************Arduino code used in video*******************************<br />
<span style="color: blue;">/*This code demonstrates how to change the ADC voltage reference on an Arduino </span><br />
<span style="color: blue;"> * This was shown in an ADC tutorial on the ForceTronics YouTube Channel.</span><br />
<span style="color: blue;">* This code is free and open for anybody to use at their own risk. </span><br />
<span style="color: blue;">*/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup() {</span><br />
<span style="color: blue;"> Serial.begin(115200); //setup serial connection</span><br />
<span style="color: blue;"> while(!Serial);</span><br />
<span style="color: blue;"> analogReference(AR_EXTERNAL); //sets the ADC reference voltage to external (input is aRef pin)</span><br />
<span style="color: blue;"> //analogReference(AR_DEFAULT); //set the ADC reference to default which is AVCC (uses power supply voltage or VCC as reference)</span><br />
<span style="color: blue;"> //analogReference(AR_INTERNAL2V23); //uses 2.23V internal reference in SAMD21 uC</span><br />
<span style="color: blue;"> analogReadResolution(12); //Set ADC to 12bit resolution, default is 10</span><br />
<span style="color: blue;"> burn8Readings(); //make 8 readings but don't use them to ensure good reading after reference change</span><br />
<span style="color: blue;"> delay(100);</span><br />
<span style="color: blue;"> for(int i=0;i<500;i++) { //loop through a bunch of ADC readings and print them to serial plotter</span><br />
<span style="color: blue;"> Serial.println(analogRead(A0)); //Make ADC measurement at A0</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop() {</span><br />
<span style="color: blue;"> //don't need the loop</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//This function makes 8 ADC measurements but does nothing with them</span><br />
<span style="color: blue;">//Since after a reference change the ADC can return bad readings at first. This function is used to get rid of the first </span><br />
<span style="color: blue;">//8 readings to ensure an accurate one is displayed</span><br />
<span style="color: blue;">void burn8Readings() {</span><br />
<span style="color: blue;"> for(int i=0; i<8; i++) {</span><br />
<span style="color: blue;"> analogRead(A0);</span><br />
<span style="color: blue;"> delay(1);</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com4tag:blogger.com,1999:blog-3259446650039490342.post-20684341782250166242019-03-06T20:57:00.000-08:002019-03-06T20:57:34.628-08:00Tutorial on Digital to Analog Converters (DAC) and Example Using the MCP4728 Part 2Two part tutorial on digital to analog converters (DAC). In part 2 we take a look at the capabilities of the MCP4728 which is a four channel DAC controlled via I2C. See the links below to access the code and get the PCB design from the video at PCBWay.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/YcGVH8NBbF4/0.jpg" src="https://www.youtube.com/embed/YcGVH8NBbF4?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
Link for PCB board at PCBWay: https://www.pcbway.com/project/shareproject/W08904ASW106_DAC_Example_Gerber.html<br />
<br />
//**********Arduino Code with MCP4728 examples from video***************<br />
<span style="color: blue;">/*</span><br />
<span style="color: blue;"> * This code was written to demonstrate functions on the MCP4728 4 channel DAC for a video on the ForceTronics YouTube channel</span><br />
<span style="color: blue;"> * This sketch leverages a library from GitHub made by Hideakitai, link to library: https://github.com/hideakitai/MCP4728</span><br />
<span style="color: blue;"> * This code is public domain and free to anyone to use and modify with no restrictions at your own risk</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#include <Wire.h></span><br />
<span style="color: blue;">#include "MCP4728.h"</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">MCP4728 dac; //create object to library</span><br />
<span style="color: blue;">//variables for wavform</span><br />
<span style="color: blue;">int const sampleCount = 24; //samples to read to have a buffer</span><br />
<span style="color: blue;">int signalSamples[sampleCount]; //create array to hold signal or waveform</span><br />
<span style="color: blue;">float pi2 = 6.283; //value of pi times 2</span><br />
<span style="color: blue;">const long clkFrequency = 400000; //I2C clock frequency</span><br />
<span style="color: blue;">const uint8_t t1 = 3; //pin to setup test 1 fast sinewave</span><br />
<span style="color: blue;">const uint8_t t2 = 4; //pin to setup test 2 sync'd sinewaves</span><br />
<span style="color: blue;">const uint8_t LDAC = 5; //Output pin on MCU to control LDAC(not) pin on DAC</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup() {</span><br />
<span style="color: blue;"> //Create sinewave</span><br />
<span style="color: blue;"> float in;</span><br />
<span style="color: blue;"> float hBit = 2047.5;</span><br />
<span style="color: blue;"> for (int i=0;i<sampleCount;i++)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> in = pi2*(1/(float)sampleCount)*(float)i;</span><br />
<span style="color: blue;"> signalSamples[i] = (int)(sin(in)*hBit + hBit);</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> pinMode(t1,INPUT_PULLUP); //configure test check pins</span><br />
<span style="color: blue;"> pinMode(t2,INPUT_PULLUP); //configure test check pins</span><br />
<span style="color: blue;"> pinMode(LDAC,OUTPUT); //configure test check pins</span><br />
<span style="color: blue;"> digitalWrite(LDAC,HIGH); //turn DAC outputs off</span><br />
<span style="color: blue;"> Wire.begin(); //start up I2C library</span><br />
<span style="color: blue;"> Wire.setClock(clkFrequency); //set clock frequency for I2C comm</span><br />
<span style="color: blue;"> dac.attatch(Wire, 13); //second argument is Arduino pin connected to LDAC(not), we are controlling LDAC manually so just entered pin we are not using</span><br />
<span style="color: blue;"> dac.readRegisters(); //Used to read current settings from MCP4728</span><br />
<span style="color: blue;"> dac.selectVref(MCP4728::VREF::VDD, MCP4728::VREF::VDD, MCP4728::VREF::VDD, MCP4728::VREF::VDD); //setup voltage ref for each DAC channel</span><br />
<span style="color: blue;"> dac.selectPowerDown(MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL, MCP4728::PWR_DOWN::NORMAL); //set power down mode, used for saving power</span><br />
<span style="color: blue;"> dac.selectGain(MCP4728::GAIN::X1, MCP4728::GAIN::X1, MCP4728::GAIN::X1, MCP4728::GAIN::X1); //set gain on output amp</span><br />
<span style="color: blue;"> //dac.enable(true); //enables the DAC outputs by controlling LDAC pin, but we are controlling LDAC manually in this example</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> //perform test one</span><br />
<span style="color: blue;"> if(!digitalRead(t1)) {</span><br />
<span style="color: blue;"> digitalWrite(LDAC,LOW);</span><br />
<span style="color: blue;"> //output sinewave as fast as we can</span><br />
<span style="color: blue;"> for(;;) { //run test for infinitity </span><br />
<span style="color: blue;"> for(int j=0;j<sampleCount;j++) {</span><br />
<span style="color: blue;"> dac.analogWrite(MCP4728::DAC_CH::A,signalSamples[j]);</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> else { //perform test 2 </span><br />
<span style="color: blue;"> for(;;) { //run test for infinitity </span><br />
<span style="color: blue;"> for(int j=0;j<sampleCount;j++) {</span><br />
<span style="color: blue;"> int temp = j;</span><br />
<span style="color: blue;"> digitalWrite(LDAC,HIGH); //turn outputs off</span><br />
<span style="color: blue;"> // delay(1);</span><br />
<span style="color: blue;"> dac.analogWrite(MCP4728::DAC_CH::A,signalSamples[temp]);</span><br />
<span style="color: blue;"> temp += 8; //shift sigal 90 degrees</span><br />
<span style="color: blue;"> if(temp > 23) temp -= sampleCount;</span><br />
<span style="color: blue;"> dac.analogWrite(MCP4728::DAC_CH::B,signalSamples[temp]);</span><br />
<span style="color: blue;"> temp += 8; //shift sigal 90 degrees</span><br />
<span style="color: blue;"> if(temp > 23) temp -= sampleCount;</span><br />
<span style="color: blue;"> dac.analogWrite(MCP4728::DAC_CH::C,signalSamples[temp]);</span><br />
<span style="color: blue;"> temp += 8; //shift sigal 90 degrees</span><br />
<span style="color: blue;"> if(temp > 23) temp -= sampleCount;</span><br />
<span style="color: blue;"> dac.analogWrite(MCP4728::DAC_CH::D,signalSamples[temp]);</span><br />
<span style="color: blue;"> digitalWrite(LDAC,LOW); //turn outputs on all four outputs at same time</span><br />
<span style="color: blue;"> // delay(1);</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop() {</span><br />
<span style="color: blue;">}</span><br />
<div>
<br /></div>
<br />ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com2tag:blogger.com,1999:blog-3259446650039490342.post-75435505442865208952019-02-16T20:44:00.000-08:002019-02-16T20:44:06.339-08:00Tutorial on Digital to Analog Converters (DAC) and Example Using the MCP4728 Part 1In this video we go over what a digital to analog converter (DAC) is and how it works. We then focus on the MCP4728 4 Channel DAC with some simple examples. In part two we do a deeper dive into the MCP4728.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/RWsNZIrdNHg/0.jpg" src="https://www.youtube.com/embed/RWsNZIrdNHg?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
Link to Analog Devices detailed tutorial on converters: <span style="font-family: Calibri; font-size: 12pt; white-space: pre-wrap;"><a href="https://www.analog.com/media/en/training-seminars/design-handbooks/Basic-Linear-Design/Chapter6.pdf">https://www.analog.com/media/en/training-seminars/design-handbooks/Basic-Linear-Design/Chapter6.pdf</a></span><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;"><img height="421px;" src="https://lh6.googleusercontent.com/mV6xSOHC9PezrYGm-V7EYl7Qb-D9RXfFku_U-T9spOarZi5UieTn-xXcwL7qX5b-fji17r9DLnlwDzKhwy7u9jk4Cib5uCvnQFG-AUSWTqUkyNB_bLjTQiQpke71q9r1wEzTTUNGDqo" style="margin-left: auto; margin-right: auto;" width="630px;" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Kelvin Divider or String DAC Architecture</td></tr>
</tbody></table>
<span id="docs-internal-guid-d0936e99-7fff-b722-a399-0317d9f20047"></span>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0tag:blogger.com,1999:blog-3259446650039490342.post-992799606932850992018-11-23T16:14:00.000-08:002018-11-23T16:14:00.748-08:00Unboxing Particle's Mesh Network IoT Series (Boron and Xenon)In this video we unbox Particle's new IoT Mesh Network series (Argon, Boron, Xenon). We take a look both the hardware and the software that allows you to easily create a cloud connected mesh network. Link to product page: https://www.particle.io/mesh<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/nJ_tU7VIHxw/0.jpg" src="https://www.youtube.com/embed/nJ_tU7VIHxw?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
//******************Code from Video*****************************************<br />
<span style="color: blue;">// -----------------------------------</span><br />
<span style="color: blue;">// Controlling LEDs over the Internet</span><br />
<span style="color: blue;">// -----------------------------------</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// First, let's create our "shorthand" for the pins</span><br />
<span style="color: blue;">// Same as in the Blink an LED example:</span><br />
<span style="color: blue;">// led1 is D0, led2 is D7</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">int led1 = D0;</span><br />
<span style="color: blue;">int led2 = D7;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// Last time, we only needed to declare pins in the setup function.</span><br />
<span style="color: blue;">// This time, we are also going to register our Particle function</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup()</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Here's the pin configuration, same as last time</span><br />
<span style="color: blue;"> pinMode(led1, OUTPUT);</span><br />
<span style="color: blue;"> pinMode(led2, OUTPUT);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // We are also going to declare a Particle.function so that we can turn the LED on and off from the cloud.</span><br />
<span style="color: blue;"> Particle.function("led",ledToggle);</span><br />
<span style="color: blue;"> // This is saying that when we ask the cloud for the function "led", it will employ the function ledToggle() from this app.</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // For good measure, let's also make sure both LEDs are off when we start:</span><br />
<span style="color: blue;"> digitalWrite(led1, LOW);</span><br />
<span style="color: blue;"> digitalWrite(led2, LOW);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><br /></span>
<span style="color: blue;">// Last time, we wanted to continously blink the LED on and off</span><br />
<span style="color: blue;">// Since we're waiting for input through the cloud this time,</span><br />
<span style="color: blue;">// we don't actually need to put anything in the loop</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop()</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> // Nothing to do here</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// We're going to have a super cool function now that gets called when a matching API request is sent</span><br />
<span style="color: blue;">// This is the ledToggle function we registered to the "led" Particle.function earlier.</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><br /></span>
<span style="color: blue;">int ledToggle(String command) {</span><br />
<span style="color: blue;"> /* Particle.functions always take a string as an argument and return an integer.</span><br />
<span style="color: blue;"> Since we can pass a string, it means that we can give the program commands on how the function should be used.</span><br />
<span style="color: blue;"> In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.</span><br />
<span style="color: blue;"> Then, the function returns a value to us to let us know what happened.</span><br />
<span style="color: blue;"> In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,</span><br />
<span style="color: blue;"> and -1 if we received a totally bogus command that didn't do anything to the LEDs.</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> if (command=="on") {</span><br />
<span style="color: blue;"> digitalWrite(led1,HIGH);</span><br />
<span style="color: blue;"> digitalWrite(led2,HIGH);</span><br />
<span style="color: blue;"> Particle.publish("LED State", "ON");</span><br />
<span style="color: blue;"> return 1;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> else if (command=="off") {</span><br />
<span style="color: blue;"> digitalWrite(led1,LOW);</span><br />
<span style="color: blue;"> digitalWrite(led2,LOW);</span><br />
<span style="color: blue;"> Particle.publish("LED State", "OFF");</span><br />
<span style="color: blue;"> return 0;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> else {</span><br />
<span style="color: blue;"> return -1;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span><br />
<div>
<br /></div>
ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com1tag:blogger.com,1999:blog-3259446650039490342.post-55103297886864466222018-11-09T09:35:00.000-08:002018-11-09T09:35:06.168-08:00Designing a Thermocouple Temperature Measurement Circuit Part 2In this series we look at how to design a Thermocouple temperature measurement circuit. In part 2 we look at a real world example of a Thermocouple J Type circuit design and discuss some of the common sources of error and how to avoid them.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/5aFSLzeLQ6c/0.jpg" src="https://www.youtube.com/embed/5aFSLzeLQ6c?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq8GrkNWeC6v0NilgxTVCxJpScIEOBOqw_LoX9nLUrISEJQ-9xlE23NdEQzW5Cqb_Rk3QbtfIYzg5DAEBhwnBOvYZOE35-J6DP_v4H6PNrI8N1gpf3evFH9PA6TY4VuJbS8sK4AFxz-lDn/s1600/Capture.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="684" data-original-width="1148" height="381" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq8GrkNWeC6v0NilgxTVCxJpScIEOBOqw_LoX9nLUrISEJQ-9xlE23NdEQzW5Cqb_Rk3QbtfIYzg5DAEBhwnBOvYZOE35-J6DP_v4H6PNrI8N1gpf3evFH9PA6TY4VuJbS8sK4AFxz-lDn/s640/Capture.PNG" width="640" /></a></div>
<br />
<br />ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com1tag:blogger.com,1999:blog-3259446650039490342.post-56223266374160768202018-10-10T21:03:00.000-07:002018-10-10T21:03:58.241-07:00Designing a Thermocouple Temperature Measurement Circuit Part 1In this series we look at how to design a Thermocouple temperature measurement circuit. In part 1 we look at Thermocouple theory, pros and cons versus other temperature measurement techniques, and an overview of a measurement hardware circuit as well as calculations done in software.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/S4mbV36QZW4/0.jpg" src="https://www.youtube.com/embed/S4mbV36QZW4?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0fqDTgOrn79WYRCrBOYV2RCqRKX2iPhnqxwVHtTH-2EI6lUo4Tfhwx-zyyi7h0wRuWnspjG1vhhDmYYoPGnmiSSLaboXeJnMgGU_QbbTyNyFyGDNK6t7Jyvbe4jwNvC2SoxPTmykmmmjL/s1600/Capture.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="844" data-original-width="1460" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0fqDTgOrn79WYRCrBOYV2RCqRKX2iPhnqxwVHtTH-2EI6lUo4Tfhwx-zyyi7h0wRuWnspjG1vhhDmYYoPGnmiSSLaboXeJnMgGU_QbbTyNyFyGDNK6t7Jyvbe4jwNvC2SoxPTmykmmmjL/s640/Capture.PNG" width="640" /></a></div>
<br />ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com2tag:blogger.com,1999:blog-3259446650039490342.post-34204900250987527492018-09-26T20:59:00.002-07:002018-09-26T20:59:44.765-07:00Easy Way to Create a Wireless Sensor NetworkIn this video we look at an easy way with not very much code to setup a wireless network using the nRF24L01 Transceiver and Arduino.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/KoJ27BQdYxE/0.jpg" src="https://www.youtube.com/embed/KoJ27BQdYxE?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
//***************************Master or Receiver code*****************<br />
<span style="color: blue;">/*This code was used for a video tutorial on the ForceTronics YouTube Channel</span><br />
<span style="color: blue;"> * This code is free and open for anybody to use and modify at your own risk</span><br />
<span style="color: blue;">*/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+</span><br />
<span style="color: blue;">#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/</span><br />
<span style="color: blue;">#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">const uint8_t pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)</span><br />
<span style="color: blue;">const uint8_t pinCSN = 10; //This pin is used for SPI comm chip select</span><br />
<span style="color: blue;">RF24 wirelessSPI(pinCE, pinCSN); // Declare object from nRF24 library (Create your wireless SPI) </span><br />
<span style="color: blue;">const uint64_t rAddress = 0xB00B1E50C3LL; //Create pipe address for the network and notice I spelled boobies because I am mature, the "LL" is for LongLong type</span><br />
<span style="color: blue;">const uint8_t rFChan = 89; //Set channel frequency default (chan 84 is 2.484GHz to 2.489GHz)</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//Create a structure to hold fake sensor data and channel data</span><br />
<span style="color: blue;">struct PayLoad {</span><br />
<span style="color: blue;"> uint8_t chan;</span><br />
<span style="color: blue;"> uint8_t sensor;</span><br />
<span style="color: blue;">};</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">PayLoad payload; //create struct object</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup() {</span><br />
<span style="color: blue;"> wirelessSPI.begin(); //Start the nRF24 module</span><br />
<span style="color: blue;"> wirelessSPI.setChannel(rFChan); //set communication frequency channel</span><br />
<span style="color: blue;"> wirelessSPI.openReadingPipe(1,rAddress); //This is receiver or master so we need to be ready to read data from transmitters</span><br />
<span style="color: blue;"> wirelessSPI.startListening(); // Start listening for messages</span><br />
<span style="color: blue;"> Serial.begin(115200); //serial port to display received data</span><br />
<span style="color: blue;"> Serial.println("Network master is online...");</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop() {</span><br />
<span style="color: blue;"> if(wirelessSPI.available()){ //Check if recieved data</span><br />
<span style="color: blue;"> wirelessSPI.read(&payload, sizeof(payload)); //read packet of data and store it in struct object</span><br />
<span style="color: blue;"> Serial.print("Received data packet from node: ");</span><br />
<span style="color: blue;"> Serial.println(payload.chan); //print node number or channel</span><br />
<span style="color: blue;"> Serial.print("Node sensor value is: ");</span><br />
<span style="color: blue;"> Serial.println(payload.sensor); //print node's sensor value</span><br />
<span style="color: blue;"> Serial.println(); </span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
//***************************Node or Transmitter code*****************<br />
<span style="color: blue;">/*This code was used for a video tutorial on the ForceTronics YouTube Channel</span><br />
<span style="color: blue;"> * This code is free and open for anybody to use and modify at your own risk</span><br />
<span style="color: blue;">*/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#include <SPI.h> //Call SPI library so you can communicate with the nRF24L01+</span><br />
<span style="color: blue;">#include <nRF24L01.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/</span><br />
<span style="color: blue;">#include <RF24.h> //nRF2401 libarary found at https://github.com/tmrh20/RF24/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">const uint8_t pinCE = 9; //This pin is used to set the nRF24 to standby (0) or active mode (1)</span><br />
<span style="color: blue;">const uint8_t pinCSN = 10; //This pin is used to tell the nRF24 whether the SPI communication is a command</span><br />
<span style="color: blue;">RF24 wirelessSPI(pinCE, pinCSN); // Declare object from nRF24 library (Create your wireless SPI) </span><br />
<span style="color: blue;">const uint64_t wAddress = 0xB00B1E50C3LL; //Create pipe address to send data, the "LL" is for LongLong type</span><br />
<span style="color: blue;">const uint8_t rFChan = 89; //Set channel default (chan 84 is 2.484GHz to 2.489GHz)</span><br />
<span style="color: blue;">const uint8_t rDelay = 7; //this is based on 250us increments, 0 is 250us so 7 is 2 ms</span><br />
<span style="color: blue;">const uint8_t rNum = 5; //number of retries that will be attempted </span><br />
<span style="color: blue;">const uint8_t chan1 = 2; //D2 pin for node channel check</span><br />
<span style="color: blue;">const uint8_t chan2 = 3; //D3 pin for node channel check</span><br />
<span style="color: blue;">const uint8_t chan3 = 4; //D4 pin for node channel check</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//stuct of payload to send fake sensor data and node channel</span><br />
<span style="color: blue;">struct PayLoad {</span><br />
<span style="color: blue;"> uint8_t chan;</span><br />
<span style="color: blue;"> uint8_t sensor;</span><br />
<span style="color: blue;">};</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">PayLoad payload; //create struct object</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup() {</span><br />
<span style="color: blue;"> pinMode(chan1,INPUT_PULLUP); //set channel select digital pins to input pullup</span><br />
<span style="color: blue;"> pinMode(chan2,INPUT_PULLUP);</span><br />
<span style="color: blue;"> pinMode(chan3,INPUT_PULLUP);</span><br />
<span style="color: blue;"> wirelessSPI.begin(); //Start the nRF24 module</span><br />
<span style="color: blue;"> wirelessSPI.setChannel(rFChan); </span><br />
<span style="color: blue;"> wirelessSPI.setRetries(rDelay,rNum); //if a transmit fails to reach receiver (no ack packet) then this sets retry attempts and delay between retries </span><br />
<span style="color: blue;"> wirelessSPI.openWritingPipe(wAddress); //open writing or transmit pipe</span><br />
<span style="color: blue;"> wirelessSPI.stopListening(); //go into transmit mode</span><br />
<span style="color: blue;"> randomSeed(analogRead(0)); //set random seed for fake sensor data</span><br />
<span style="color: blue;"> setChannel(); //checks current channel setting for transceiver</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop() {</span><br />
<span style="color: blue;"> delay(3000); //send data every 3 seconds</span><br />
<span style="color: blue;"> payload.sensor = random(0,255); //get made up sensor value</span><br />
<span style="color: blue;"> if (!wirelessSPI.write(&payload, sizeof(payload))){ //send data and remember it will retry if it fails</span><br />
<span style="color: blue;"> delay(random(5,20)); //as another back up, delay for a random amount of time and try again</span><br />
<span style="color: blue;"> if (!wirelessSPI.write(&payload, sizeof(payload))){</span><br />
<span style="color: blue;"> //set error flag if it fails again</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//check for low digital pin to set node address</span><br />
<span style="color: blue;">void setChannel() {</span><br />
<span style="color: blue;"> if(!digitalRead(chan1)) payload.chan = 1;</span><br />
<span style="color: blue;"> else if(!digitalRead(chan2)) payload.chan = 2;</span><br />
<span style="color: blue;"> else if(!digitalRead(chan3)) payload.chan = 3;</span><br />
<span style="color: blue;"> else payload.chan = 0;</span><br />
<span style="color: blue;">}</span><br />
<div>
<br /></div>
ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com2tag:blogger.com,1999:blog-3259446650039490342.post-23406204925124815982018-08-19T20:51:00.000-07:002018-08-19T20:51:26.648-07:00Building a UART to USB Memory Stick / Drive BridgeIn this video look at how to create a bridge that takes data from the UART port and writes it to a file on a USB thumb drive (BOMS device). For this project we will use the FT900 microcontroller from FTDI / Bridgetek.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/X6gCNMg0GJU/0.jpg" src="https://www.youtube.com/embed/X6gCNMg0GJU?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<span style="color: blue;">/* Code from the video***********************************************************</span><br />
<span style="color: blue;"> * This is code was used for a Tutorial on the ForceTronics YouTube Channel on writing UART data to a file on a USB thumb drive</span><br />
<span style="color: blue;"> * Most of this code was leveraged from the FTDI / Bridgetek example program called "USBH Example File System" it was written for the FT900</span><br />
<span style="color: blue;"> * family of microcontrollers from FTDI / Bridgetek. This code is free and open for any to use or modify at their own risk</span><br />
<span style="color: blue;"> * */</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//all these includes come from the example "USBH Example File System" made by FTDI</span><br />
<span style="color: blue;">#include <stdint.h></span><br />
<span style="color: blue;">#include <string.h></span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#include <ft900.h></span><br />
<span style="color: blue;">#include <ft900_usb.h></span><br />
<span style="color: blue;">#include <ft900_usbh_boms.h></span><br />
<span style="color: blue;">#include <ft900_startup_dfu.h></span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// UART support for printf output</span><br />
<span style="color: blue;">#include "tinyprintf.h"</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// Support for FATFS </span><br />
<span style="color: blue;">#include "ff.h"</span><br />
<span style="color: blue;">#include "diskio.h"</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/* CONSTANTS ***********************************************************************/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#define EXAMPLE_FILE "FTronics.TXT"</span><br />
<span style="color: blue;">// Change this value in order to change the size of the buffer being used</span><br />
<span style="color: blue;">#define RINGBUFFER_SIZE (4096)</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/* GLOBAL VARIABLES ****************************************************************/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// File system handle for fatfs.</span><br />
<span style="color: blue;">FATFS fs;</span><br />
<span style="color: blue;">// Context structure and handle for BOMS device.</span><br />
<span style="color: blue;">USBH_BOMS_context bomsCtx;</span><br />
<span style="color: blue;">USBH_interface_handle hOpenDisk = 0;</span><br />
<span style="color: blue;">USBH_device_handle hRootDev;</span><br />
<span style="color: blue;">unsigned long fPosition = 0; //This variable is used to track the position in the file where the last data was written</span><br />
<span style="color: blue;">volatile unsigned int mTimer = 0; //This variable was used to test how long it took to write data to the file</span><br />
<span style="color: blue;">typedef struct //struct for buffer that stores UART data before it is written to file</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> uint8_t data[RINGBUFFER_SIZE];</span><br />
<span style="color: blue;"> uint16_t wr_idx;</span><br />
<span style="color: blue;"> uint16_t rd_idx;</span><br />
<span style="color: blue;">} RingBuffer_t;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// Receiver buffer</span><br />
<span style="color: blue;">static RingBuffer_t uart0BufferIn = { {0}, 0, 0 };</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/* LOCAL FUNCTIONS / INLINES *******************************************************/</span><br />
<span style="color: blue;">DSTATUS disk_initialize(BYTE pdrv);</span><br />
<span style="color: blue;">DSTATUS disk_status(BYTE pdrv);</span><br />
<span style="color: blue;">DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);</span><br />
<span style="color: blue;">DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);</span><br />
<span style="color: blue;">DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);</span><br />
<span style="color: blue;">DWORD get_fattime(void);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/** @name tfp_putc</span><br />
<span style="color: blue;"> * @details Machine dependent putc function for tfp_printf (tinyprintf) library.</span><br />
<span style="color: blue;"> * @param p Parameters (machine dependent)</span><br />
<span style="color: blue;"> * @param c The character to write</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;">void tfp_putc(void* p, char c)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> uart_write((ft900_uart_regs_t*)p, (uint8_t)c);</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void ISR_timer(void) //this interrupt fires every ten milliseconds to handle USB functions</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> if (timer_is_interrupted(timer_select_a))</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>// Call USB timer handler to action transaction and hub timers.</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>USBH_timer();</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>mTimer++;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/* FatFS Functions ******************/</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/** Initialise a drive</span><br />
<span style="color: blue;"> * @param pdrv Physical Drive number</span><br />
<span style="color: blue;"> * @return Disk Status */</span><br />
<span style="color: blue;">DSTATUS disk_initialize(BYTE pdrv)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>DSTATUS stat = 0;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>int8_t status;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> status = USBH_BOMS_init(hOpenDisk, 0, &bomsCtx);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> if (status != USBH_BOMS_OK)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>tfp_printf("BOMS device could not be initialised: %d\r\n", status);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>stat = STA_NOINIT;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>hOpenDisk = 0;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>return stat;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/** Disk Status</span><br />
<span style="color: blue;"> * @param pdrv Physical Drive number</span><br />
<span style="color: blue;"> * @return Disk Status */</span><br />
<span style="color: blue;">DSTATUS disk_status(BYTE pdrv)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>DSTATUS stat = 0;</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>if (0 == hOpenDisk)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>stat |= STA_NOINIT;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//TODO: perform a GetSense SCSI command to make sure it's there</span><br />
<span style="color: blue;"> if (USBH_BOMS_status(&bomsCtx) != USBH_BOMS_OK)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> stat |= STA_NODISK;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>return stat;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/** Read sector(s) from disk</span><br />
<span style="color: blue;"> * @param pdrv Physical Drive number</span><br />
<span style="color: blue;"> * @param buff Data buffer to store into</span><br />
<span style="color: blue;"> * @param sector The logical sector address</span><br />
<span style="color: blue;"> * @param count The number of sectors to read</span><br />
<span style="color: blue;"> * @return Disk Status */</span><br />
<span style="color: blue;">DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>DRESULT res = RES_OK;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>if (USBH_BOMS_read(&bomsCtx, sector, USBH_BOMS_BLOCK_SIZE * count, buff) != USBH_BOMS_OK)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>res = RES_ERROR;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>return res;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#if _USE_WRITE</span><br />
<span style="color: blue;">/** Write sector(s) to the disk</span><br />
<span style="color: blue;"> * @param pdrv Physical Drive number</span><br />
<span style="color: blue;"> * @param buff Data buffer to write to the disk</span><br />
<span style="color: blue;"> * @param sector The logical sector address</span><br />
<span style="color: blue;"> * @param count The number of sectors to write</span><br />
<span style="color: blue;"> * @return Disk Status */</span><br />
<span style="color: blue;">DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>DRESULT res = RES_OK;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>if (USBH_BOMS_write(&bomsCtx, sector, USBH_BOMS_BLOCK_SIZE * count, (uint8_t *)buff) != USBH_BOMS_OK)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>res = RES_ERROR;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>return res;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;">#endif</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#if _USE_IOCTL</span><br />
<span style="color: blue;">/** Disk IO Control</span><br />
<span style="color: blue;"> * @param pdrv Physical Drive Number</span><br />
<span style="color: blue;"> * @param cmd Control Code</span><br />
<span style="color: blue;"> * @param buff Buffer to send/receive control data </span><br />
<span style="color: blue;"> * @return Disk Status */</span><br />
<span style="color: blue;">DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>DRESULT res = RES_OK;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Not Supported */</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>return res;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;">#endif</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#if _FS_READONLY == 0</span><br />
<span style="color: blue;">/** Get the current time</span><br />
<span style="color: blue;"> * @return The time in the following format:</span><br />
<span style="color: blue;"> * bit[31:25] = Year from 1980 (0..127),</span><br />
<span style="color: blue;"> * bit[24:21] = Month (1..12),</span><br />
<span style="color: blue;"> * bit[20:16] = Day of the Month (1..31),</span><br />
<span style="color: blue;"> * bit[15:11] = Hour (0..23),</span><br />
<span style="color: blue;"> * bit[10:5] = Minute (0..59),</span><br />
<span style="color: blue;"> * bit[4..0] = Second / 2 (0..29) */</span><br />
<span style="color: blue;">DWORD get_fattime(void)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> return 0; /* Invalid timestamp */</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;">#endif</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/**</span><br />
<span style="color: blue;"> See how much data is available in the UART0 ring buffer</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> @return The number of bytes available</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;">uint16_t uart0Available(void)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> int16_t diff = uart0BufferIn.wr_idx - uart0BufferIn.rd_idx;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> if (diff < 0)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> diff += RINGBUFFER_SIZE;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> return (uint16_t)diff;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/**</span><br />
<span style="color: blue;"> Receive a number of bytes from UART0</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> @return The number of bytes read from UART0</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;">uint16_t uart0Rx(uint8_t *data, uint16_t len)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> uint16_t avail = 0;</span><br />
<span style="color: blue;"> uint16_t copied = 0;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> avail = uart0Available();</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Copy in as much data as we can ...</span><br />
<span style="color: blue;"> This can be either the maximum size of the buffer being given</span><br />
<span style="color: blue;"> or the maximum number of bytes available in the Serial Port</span><br />
<span style="color: blue;"> buffer */</span><br />
<span style="color: blue;"> while(len-- && avail--)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> *data = uart0BufferIn.data[uart0BufferIn.rd_idx];</span><br />
<span style="color: blue;"> data++;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Increment the pointer and wrap around */</span><br />
<span style="color: blue;"> uart0BufferIn.rd_idx++;</span><br />
<span style="color: blue;"> if (uart0BufferIn.rd_idx == RINGBUFFER_SIZE) uart0BufferIn.rd_idx = 0;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> copied++;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Report back how many bytes have been copied into the buffer...*/</span><br />
<span style="color: blue;"> return copied;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><br /></span>
<span style="color: blue;"><br /></span>
<span style="color: blue;">/**</span><br />
<span style="color: blue;"> The Interrupt which handles asynchronous transmission and reception</span><br />
<span style="color: blue;"> of data into the ring buffer</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;">void uart0ISR()</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> static uint8_t c;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Receive interrupt... */</span><br />
<span style="color: blue;"> if (uart_is_interrupted(UART0, uart_interrupt_rx))</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> /* Read a byte into the Ring Buffer... */</span><br />
<span style="color: blue;"> uart_read(UART0, &c);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> uart0BufferIn.data[uart0BufferIn.wr_idx] = c;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Increment the pointer and wrap around */</span><br />
<span style="color: blue;"> uart0BufferIn.wr_idx++;</span><br />
<span style="color: blue;"> if (uart0BufferIn.wr_idx == RINGBUFFER_SIZE) uart0BufferIn.wr_idx = 0;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> /* Check to see if we have hit the back of the buffer... */</span><br />
<span style="color: blue;"> if (uart0BufferIn.wr_idx == uart0BufferIn.rd_idx)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> /* Increment the pointer and wrap around */</span><br />
<span style="color: blue;"> uart0BufferIn.rd_idx++;</span><br />
<span style="color: blue;"> if (uart0BufferIn.rd_idx == RINGBUFFER_SIZE) uart0BufferIn.rd_idx = 0;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//this function mounts file system that the file is written to</span><br />
<span style="color: blue;">int8_t mountFileSystem(USBH_interface_handle hBOMS)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> // Initialise FatFS</span><br />
<span style="color: blue;"> hOpenDisk = hBOMS; //this gets USB "interface" handle</span><br />
<span style="color: blue;"> //Would like to make this a one time action</span><br />
<span style="color: blue;"> if (f_mount(&fs, "", 0) != FR_OK) //mounts file system, needed to open file I am assuming</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>tfp_printf("Unable to mount File System\r\n");</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>return -1;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> tfp_printf("\r\n\r\n"); delayms(1000);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> return 0;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//This function creates the file that we are storing on the USB drive</span><br />
<span style="color: blue;">//If the file already exists it will be deleted and a new one is created</span><br />
<span style="color: blue;">int8_t createFile(USBH_interface_handle hBOMS) {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> // Initialise FatFS</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> hOpenDisk = hBOMS; //this gets USB "interface" handle</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> FRESULT res; //file data type, that is an enumeration with states of the file interactions</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> FIL f; //another file data type enum with file conditions</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> // Check to see if the example file is there.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> //This code checks to see if file already exists</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> res = f_stat(EXAMPLE_FILE, NULL);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> if (FR_OK == res)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> tfp_printf("File " EXAMPLE_FILE " already exists. Deleting\r\n");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> if (FR_OK != f_unlink(EXAMPLE_FILE))</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>tfp_printf("Problem deleting " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>return 0;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span> res = f_open(&f, EXAMPLE_FILE, FA_CREATE_NEW);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span> if (FR_OK != res)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>tfp_printf("Problem creating file " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>return 0;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span> tfp_printf( "Closing " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> if (FR_OK != f_close(&f)) //This is where the file is closed after writing</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>tfp_printf("Error closing " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span> tfp_printf("\r\n\r\n"); delayms(1000);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> return 1;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//funciton used to write data to the file. the data pointer is for the data you want to write</span><br />
<span style="color: blue;">//this bCount variable is for how much data</span><br />
<span style="color: blue;">int8_t writeDataToFile(USBH_interface_handle hBOMS, uint8_t* data, uint16_t bCount)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> FRESULT res; //file data type, that is an enumeration with states of the file interactions</span><br />
<span style="color: blue;"> FIL f; //another file data type enum with file conditions</span><br />
<span style="color: blue;"> UINT towrite, written;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Initialise FatFS</span><br />
<span style="color: blue;"> hOpenDisk = hBOMS; //this gets USB "interface" handle which I am guessing is information on the USB device we are working with</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Write some data to the USB memory stick, this is where we open file to write to</span><br />
<span style="color: blue;"> // tfp_printf( "Opening " EXAMPLE_FILE " for writing\r\n");</span><br />
<span style="color: blue;"> res = f_open(&f, EXAMPLE_FILE, FA_WRITE | FA_OPEN_EXISTING);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> if (FR_OK != res)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>tfp_printf("Problem opening file " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> f_lseek (&f, fPosition); //change writing position of the file???</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> towrite = bCount;</span><br />
<span style="color: blue;"> written = 0;</span><br />
<span style="color: blue;"> //this is where we write the data to the file. It seems if you mess up setting up USB stuff this is where we fail</span><br />
<span style="color: blue;"> while(towrite)</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> f_write(&f, data, towrite, &written);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> towrite -= written;</span><br />
<span style="color: blue;"> data += written;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> tfp_printf("Wrote %d bytes\r\n", written);</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> fPosition = fPosition + written;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> tfp_printf( "Closing " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"> if (FR_OK != f_close(&f)) //This is where the file is closed after writing</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>tfp_printf("Error closing " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> return 0;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//This funciton will read data from file. It is not used in this example and was left in for debugging purposes</span><br />
<span style="color: blue;">int8_t readFromFile(USBH_interface_handle hBOMS)</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> FIL f; //another file data type enum with file conditions</span><br />
<span style="color: blue;"> UINT read;</span><br />
<span style="color: blue;"> uint8_t* buffer[512]; //buffer for reading file on USB BOMS</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Initialise FatFS</span><br />
<span style="color: blue;"> hOpenDisk = hBOMS; //this gets USB "interface" handle which I am guessing is information on the USB device we are working with</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> //this is where the / a file is open and read</span><br />
<span style="color: blue;"> tfp_printf( "Opening " EXAMPLE_FILE " for reading\r\n\r\n");</span><br />
<span style="color: blue;"> if (FR_OK != f_open(&f, EXAMPLE_FILE, FA_READ))</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>tfp_printf("Error opening " EXAMPLE_FILE " for reading\r\n");</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> do</span><br />
<span style="color: blue;"> {</span><br />
<span style="color: blue;"> f_read(&f, buffer, 128, &read);</span><br />
<span style="color: blue;"> uart_writen(UART0, (uint8_t *)buffer, read);</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> while(read == 128);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><br /></span>
<span style="color: blue;"> tfp_printf( "\r\n" "Closing " EXAMPLE_FILE "\r\n");</span><br />
<span style="color: blue;"> f_close(&f);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><br /></span>
<span style="color: blue;"> tfp_printf("\r\n\r\n");</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> return 0;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//this function does all the setup work for the connected USB drive</span><br />
<span style="color: blue;">USBH_interface_handle doAllUSBStuff(){</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>uint8_t status;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>USBH_STATE connect;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>USBH_interface_handle hInterface;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>uint8_t usbClass;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>uint8_t usbSubclass;</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>uint8_t usbProtocol;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>//First USB action, initialize. There is no function for this so is it part of the USBH library</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//This is part of FT900 USB library, notes from doc:Performs a software reset and initialises the USB hardware</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>USBH_initialise(NULL);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>//Second step: Determine if a hub port has a downstream connection.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//Select a hub and a port to query. For the root hub the handle will be NULL and the port zero</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//checks if there are multiple ports, and sets if there is a connection</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>USBH_get_connect_state(USBH_ROOT_HUB_HANDLE, USBH_ROOT_HUB_PORT, &connect);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>if (connect == USBH_STATE_NOTCONNECTED)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>tfp_printf("\r\nPlease plug in a USB Device\r\n");</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>// You only enter this loop if there is no USB device detected. basically loops until you plug one in</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>do //looks like this is only called if the first port call fails</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//Third step: To be continuously called by the user application. Checks for asynchronous transfer completions</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//and root hub events. When a root hub connection is detected then the enumeration routine is called automatically.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//There is no requirement to call USBH_enumerate if USBH_process is called periodically.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>status = USBH_process();</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>USBH_get_connect_state(USBH_ROOT_HUB_HANDLE, USBH_ROOT_HUB_PORT, &connect);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>} while (connect == USBH_STATE_NOTCONNECTED);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>}</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>tfp_printf("\r\nUSB Device Detected\r\n");</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>do{ //this loop continues until USB BOMS device is enumerated</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>status = USBH_process(); //third step, see description above</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//USBH_process combined with get connected state does the enumeration</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>USBH_get_connect_state(USBH_ROOT_HUB_HANDLE, USBH_ROOT_HUB_PORT, &connect);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>} while (connect != USBH_STATE_ENUMERATED);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>tfp_printf("USB Device Enumerated\r\n");</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>// Get the first device (device on root hub)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//Step four: Get device list. Get the first child device of a device. The function will return a handle to a device if there are one</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>//or more child devices. For devices on the root hub the handle is set to USBH_ROOT_HUB_HANDLE.If there are no interfaces then a NULL is returned.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>status = USBH_get_device_list(USBH_ROOT_HUB_HANDLE, &hRootDev);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>if (status != USBH_OK)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>// Report the error code.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>tfp_printf("%d\r\n", status);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>}</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>else //this is where hub_scan_for_boms function was orginally called in USB test function</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> //this is a repeated function call (step 4), why do that? probably just to get status data in this function rather than</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> //passing it from previous function</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> status = USBH_get_interface_list(hRootDev, &hInterface);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span> //step 5: Get interface class, subclass and protocol. Get the class information of an interface.</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> //This function basically gets the USB characteristics of the attached device</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> if (USBH_interface_get_class_info(hInterface, &usbClass, &usbSubclass, &usbProtocol) == USBH_OK)</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>if ((usbClass == USB_CLASS_MASS_STORAGE) && //this if statement is checking all the parameters of the previous function</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> (usbSubclass == USB_SUBCLASS_MASS_STORAGE_SCSI) &&</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> (usbProtocol == USB_PROTOCOL_MASS_STORAGE_BOMS))</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span> tfp_printf("BOMS device found at level %d\r\n", 1);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span> //at this point we have established the connected USB device and we are moving to the file interactions</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span> //fs_testing(hInterface,"this better print to a mofo text file");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>mountFileSystem(hInterface);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>}</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>else {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>tfp_printf("Problem creating and writing to file");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>}</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> else {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> <span style="white-space: pre;"> </span>tfp_printf("Problem getting USB information");</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>return hInterface;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup()</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"> /* Check for a USB device connection and initiate a DFU firmware download or</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span> upload operation. This will timeout and return control here if no host PC</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span> program contacts the device's DFU interace. USB device mode is disabled</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span> before returning.</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>*/</span><br />
<span style="color: blue;"> <span style="white-space: pre;"> </span>STARTUP_DFU();</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> <span style="white-space: pre;"> </span>/* Enable the UART Device... */</span><br />
<span style="color: blue;"> sys_enable(sys_device_uart0);</span><br />
<span style="color: blue;"> /* Make GPIO48 function as UART0_TXD and GPIO49 function as UART0_RXD... */</span><br />
<span style="color: blue;"> gpio_function(48, pad_uart0_txd); /* UART0 TXD */</span><br />
<span style="color: blue;"> gpio_function(49, pad_uart0_rxd); /* UART0 RXD */</span><br />
<span style="color: blue;"> uart_open(UART0, /* Device */</span><br />
<span style="color: blue;"> 1, /* Prescaler = 1 */</span><br />
<span style="color: blue;"> UART_DIVIDER_115200_BAUD, /* Divider = 1302 */</span><br />
<span style="color: blue;"> uart_data_bits_8, /* No. Data Bits */</span><br />
<span style="color: blue;"> uart_parity_none, /* Parity */</span><br />
<span style="color: blue;"> uart_stop_bits_1); /* No. Stop Bits */</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Enable tfp_printf() functionality...</span><br />
<span style="color: blue;"> init_printf(UART0, tfp_putc);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> sys_enable(sys_device_timer_wdt);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> interrupt_attach(interrupt_timers, (int8_t)interrupt_timers, ISR_timer);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Timer A = 1ms</span><br />
<span style="color: blue;"> timer_prescaler(1000);</span><br />
<span style="color: blue;"> timer_init(timer_select_a, 1000, timer_direction_down, timer_prescaler_select_on, timer_mode_continuous);</span><br />
<span style="color: blue;"> timer_enable_interrupt(timer_select_a);</span><br />
<span style="color: blue;"> timer_start(timer_select_a);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> uart_disable_interrupt(UART0, uart_interrupt_tx);</span><br />
<span style="color: blue;"> // Enable the UART to fire interrupts when receiving data...</span><br />
<span style="color: blue;"> uart_enable_interrupt(UART0, uart_interrupt_rx);</span><br />
<span style="color: blue;"> // Attach the interrupt so it can be called...</span><br />
<span style="color: blue;"> interrupt_attach(interrupt_uart0, (uint8_t) interrupt_uart0, uart0ISR);</span><br />
<span style="color: blue;"> // Enable interrupts to be fired...</span><br />
<span style="color: blue;"> uart_enable_interrupts_globally(UART0);</span><br />
<span style="color: blue;"> interrupt_enable_globally();</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> hOpenDisk = doAllUSBStuff();</span><br />
<span style="color: blue;"> createFile(hOpenDisk);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">int main(int argc, char *argv[])</span><br />
<span style="color: blue;">{</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>setup(); //run code to setup USB and UART communication</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>fPosition = 0; //reset the file position</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span>while(1) { //loop forever</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>mTimer = 0; //reset 10 msec timer variable</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>if (uart0Available()) {</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>uint8_t buffer[RINGBUFFER_SIZE] = {0};</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>uint16_t read_bytes = uart0Rx(buffer, RINGBUFFER_SIZE);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>writeDataToFile(hOpenDisk, buffer, read_bytes);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>tfp_printf("timer value is %d\r\n", mTimer*10);</span><br />
<span style="color: blue;"><span style="white-space: pre;"> </span>}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"><span style="white-space: pre;"> </span> }</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> interrupt_detach(interrupt_timers);</span><br />
<span style="color: blue;"> interrupt_disable_globally();</span><br />
<span style="color: blue;"> sys_disable(sys_device_timer_wdt);</span><br />
<span style="color: blue;">}</span><br />
<div>
<br /></div>
<br />
<br />ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com1tag:blogger.com,1999:blog-3259446650039490342.post-41717126204805825342018-07-15T16:16:00.000-07:002018-07-15T16:16:09.028-07:00Speeding up the ADC on Arduino SAMD21 Boards (Zero, Mkr, etc) Part 2In this video we look at how to get higher ADC speeds out of Arduino boards that are based off of the SAMD21 microcontroller. In part 2 we discuss memory limitations and we leverage an Adafruit library to do an FFT on the ADC data.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Yb5vpLIFWOM/0.jpg" src="https://www.youtube.com/embed/Yb5vpLIFWOM?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
Link to details on PCBWay Maker Contest: ttps://www.pcbway.com/project/PCB_DESIGN_CONTEST.aspx<br />
<br />
//*******************Arduino Code from Video*********************************<br />
<span style="color: blue;">/*This code is from a tutorial on the ForceTronics YouTube Channel that talks about speeding up the sample rate on Arduino boards </span><br />
<span style="color: blue;"> * that use the SAMD21 microcontroller like the Arduino Zero or MKR series. This code is free and clear for other to use and modify </span><br />
<span style="color: blue;"> * at their own risk. </span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;">#include "Adafruit_ZeroFFT.h" //adafruit library for FFT</span><br />
<span style="color: blue;">#include <SPI.h></span><br />
<span style="color: blue;">#include <SD.h></span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">const long sRate = 300000; //sample rate of ADC</span><br />
<span style="color: blue;">const int16_t dSize = 1024; //used to set number of samples</span><br />
<span style="color: blue;">const byte chipSelect = 38; //used for SPI chip select pin</span><br />
<span style="color: blue;">const byte gClk = 3; //used to define which generic clock we will use for ADC</span><br />
<span style="color: blue;">const byte intPri = 0; //used to set interrupt priority for ADC</span><br />
<span style="color: blue;">const int cDiv = 1; //divide factor for generic clock</span><br />
<span style="color: blue;">const float period = 3.3334; //period of 300k sample rate</span><br />
<span style="color: blue;">String wFile = "ADC_DATA"; //used as file name to store wind and GPS data</span><br />
<span style="color: blue;">volatile int16_t aDCVal[dSize]; //array to hold ADC samples</span><br />
<span style="color: blue;">volatile int count = 0; //tracks how many samples we have collected</span><br />
<span style="color: blue;">bool done = false; //tracks when done writing data to SD card</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup() {</span><br />
<span style="color: blue;"> portSetup(); //setup the ports or pin to make ADC measurement</span><br />
<span style="color: blue;"> genericClockSetup(gClk,cDiv); //setup generic clock and routed it to ADC</span><br />
<span style="color: blue;"> aDCSetup(); //this function set up registers for ADC, input argument sets ADC reference</span><br />
<span style="color: blue;"> setUpInterrupt(intPri); //sets up interrupt for ADC and argument assigns priority</span><br />
<span style="color: blue;"> aDCSWTrigger(); //trigger ADC to start free run mode</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop() {</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"> if(count==(dSize-1) and !done) { //if done reading and they have not been written to SD card yet</span><br />
<span style="color: blue;"> removeDCOffset(aDCVal, dSize, 8); //this function removes DC offset if you are measuring an AC signal</span><br />
<span style="color: blue;"> int16_t fTTVal[dSize]; //array to hold FFT samples</span><br />
<span style="color: blue;"> for(int j=0; j<dSize; j++) fTTVal[j] = aDCVal[j]; //copy one array to another array</span><br />
<span style="color: blue;"> ZeroFFT(fTTVal,dSize); //calculate FFT and store into array</span><br />
<span style="color: blue;"> SD.begin(chipSelect); //start SD card library</span><br />
<span style="color: blue;"> File myFile = SD.open((wFile + ".csv"), FILE_WRITE); //open file to write data to CSV file</span><br />
<span style="color: blue;"> if (myFile) {</span><br />
<span style="color: blue;"> float sTime = 0;</span><br />
<span style="color: blue;"> for (int y = 0; y < dSize; y++) { //write each reading to CSV </span><br />
<span style="color: blue;"> myFile.print(String(FFT_BIN(y, sRate, dSize))+",");</span><br />
<span style="color: blue;"> myFile.print(String((fTTVal[y]))+",");</span><br />
<span style="color: blue;"> myFile.print(sTime,5); //write each reading to SD card as string</span><br />
<span style="color: blue;"> myFile.print(",");</span><br />
<span style="color: blue;"> myFile.println(String(aDCVal[y])+","); //write each reading to SD card as string</span><br />
<span style="color: blue;"> sTime = sTime + period; //update signal period info</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> myFile.close(); //close file</span><br />
<span style="color: blue;"> done = true; //we are done </span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//function for configuring ports or pins, note that this will not use the same pin numbering scheme as Arduino</span><br />
<span style="color: blue;">void portSetup() {</span><br />
<span style="color: blue;"> // Input pin for ADC Arduino A0/PA02</span><br />
<span style="color: blue;"> REG_PORT_DIRCLR1 = PORT_PA02;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Enable multiplexing on PA02_AIN0 PA03/ADC_VREFA</span><br />
<span style="color: blue;"> PORT->Group[0].PINCFG[2].bit.PMUXEN = 1;</span><br />
<span style="color: blue;"> PORT->Group[0].PINCFG[3].bit.PMUXEN = 1;</span><br />
<span style="color: blue;"> PORT->Group[0].PMUX[1].reg = PORT_PMUX_PMUXE_B | PORT_PMUX_PMUXO_B;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//this function sets up the generic clock that will be used for the ADC unit</span><br />
<span style="color: blue;">//by default it uses the 48M system clock, input arguments set divide factor for generic clock and choose which generic clock</span><br />
<span style="color: blue;">//Note unless you understand how the clock system works use clock 3. clocks 5 and up can brick the microcontroller based on how Arduino configures things</span><br />
<span style="color: blue;">void genericClockSetup(int clk, int dFactor) {</span><br />
<span style="color: blue;"> // Enable the APBC clock for the ADC</span><br />
<span style="color: blue;"> REG_PM_APBCMASK |= PM_APBCMASK_ADC;</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"> //This allows you to setup a div factor for the selected clock certain clocks allow certain division factors: Generic clock generators 3 - 8 8 division factor bits - DIV[7:0]</span><br />
<span style="color: blue;"> GCLK->GENDIV.reg |= GCLK_GENDIV_ID(clk)| GCLK_GENDIV_DIV(dFactor);</span><br />
<span style="color: blue;"> while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); </span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> //configure the generator of the generic clock with 48MHz clock</span><br />
<span style="color: blue;"> GCLK->GENCTRL.reg |= GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(clk); // GCLK_GENCTRL_DIVSEL don't need this, it makes divide based on power of two</span><br />
<span style="color: blue;"> while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"> //enable clock, set gen clock number, and ID to where the clock goes (30 is ADC)</span><br />
<span style="color: blue;"> GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(clk) | GCLK_CLKCTRL_ID(30);</span><br />
<span style="color: blue;"> while (GCLK->STATUS.bit.SYNCBUSY);</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">/*</span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV4_Val 0x0u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV8_Val 0x1u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV16_Val 0x2u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV32_Val 0x3u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV64_Val 0x4u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV128_Val 0x5u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV256_Val 0x6u </span><br />
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV512_Val 0x7u </span><br />
<span style="color: blue;">--> 8 bit ADC measurement takes 5 clock cycles, 10 bit ADC measurement takes 6 clock cycles</span><br />
<span style="color: blue;">--> Using 48MHz system clock with division factor of 1</span><br />
<span style="color: blue;">--> Using ADC division factor of 32</span><br />
<span style="color: blue;">--> Sample rate = 48M / (5 x 32) = 300 KSPS</span><br />
<span style="color: blue;">This function sets up the ADC, including setting resolution and ADC sample rate</span><br />
<span style="color: blue;">*/</span><br />
<span style="color: blue;">void aDCSetup() {</span><br />
<span style="color: blue;"> // Select reference</span><br />
<span style="color: blue;"> REG_ADC_REFCTRL = ADC_REFCTRL_REFSEL_INTVCC1; //set vref for ADC to VCC</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Average control 1 sample, no right-shift</span><br />
<span style="color: blue;"> REG_ADC_AVGCTRL |= ADC_AVGCTRL_SAMPLENUM_1;</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // Sampling time, no extra sampling half clock-cycles</span><br />
<span style="color: blue;"> REG_ADC_SAMPCTRL = ADC_SAMPCTRL_SAMPLEN(0);</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"> // Input control and input scan</span><br />
<span style="color: blue;"> REG_ADC_INPUTCTRL |= ADC_INPUTCTRL_GAIN_1X | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_MUXPOS_PIN0;</span><br />
<span style="color: blue;"> // Wait for synchronization</span><br />
<span style="color: blue;"> while (REG_ADC_STATUS & ADC_STATUS_SYNCBUSY);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> ADC->CTRLB.reg |= ADC_CTRLB_RESSEL_8BIT | ADC_CTRLB_PRESCALER_DIV32 | ADC_CTRLB_FREERUN; //This is where you set the divide factor, note that the divide call has no effect until you change Arduino wire.c</span><br />
<span style="color: blue;"> //Wait for synchronization</span><br />
<span style="color: blue;"> while (REG_ADC_STATUS & ADC_STATUS_SYNCBUSY);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> ADC->WINCTRL.reg = ADC_WINCTRL_WINMODE_DISABLE; // Disable window monitor mode</span><br />
<span style="color: blue;"> while(ADC->STATUS.bit.SYNCBUSY);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> ADC->EVCTRL.reg |= ADC_EVCTRL_STARTEI; //start ADC when event occurs</span><br />
<span style="color: blue;"> while (ADC->STATUS.bit.SYNCBUSY);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> ADC->CTRLA.reg |= ADC_CTRLA_ENABLE; //set ADC to run in standby</span><br />
<span style="color: blue;"> while (ADC->STATUS.bit.SYNCBUSY);</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//This function sets up an ADC interrupt that is triggered </span><br />
<span style="color: blue;">//when an ADC value is out of range of the window</span><br />
<span style="color: blue;">//input argument is priority of interrupt (0 is highest priority)</span><br />
<span style="color: blue;">void setUpInterrupt(byte priority) {</span><br />
<span style="color: blue;"> </span><br />
<span style="color: blue;"> ADC->INTENSET.reg |= ADC_INTENSET_RESRDY; // enable ADC ready interrupt</span><br />
<span style="color: blue;"> while (ADC->STATUS.bit.SYNCBUSY);</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> NVIC_EnableIRQ(ADC_IRQn); // enable ADC interrupts</span><br />
<span style="color: blue;"> NVIC_SetPriority(ADC_IRQn, priority); //set priority of the interrupt</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//software trigger to start ADC in free run</span><br />
<span style="color: blue;">//in future could use this to set various ADC triggers</span><br />
<span style="color: blue;">void aDCSWTrigger() {</span><br />
<span style="color: blue;"> ADC->SWTRIG.reg |= ADC_SWTRIG_START;</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//This ISR is called each time ADC makes a reading</span><br />
<span style="color: blue;">void ADC_Handler() {</span><br />
<span style="color: blue;"> if(count<1023) {</span><br />
<span style="color: blue;"> aDCVal[count] = REG_ADC_RESULT;</span><br />
<span style="color: blue;"> count++;</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;"> ADC->INTFLAG.reg = ADC_INTENSET_RESRDY; //Need to reset interrupt</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//This function takes out DC offset of AC signal, it assumes that the offset brings signal to zero volts</span><br />
<span style="color: blue;">//input arguments: array with measured points and bits of measurement</span><br />
<span style="color: blue;">void removeDCOffset(volatile int16_t aDC[], int aSize, int bits) {</span><br />
<span style="color: blue;"> int aSteps = pow(2,bits)/2; //get number of levels in ADC measurement and cut it in half</span><br />
<span style="color: blue;"> for(int i=0; i<aSize; i++) {</span><br />
<span style="color: blue;"> aDC[i] = aDC[i] - aSteps; //take out offset</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com5tag:blogger.com,1999:blog-3259446650039490342.post-31988562908954696352018-06-30T21:14:00.000-07:002018-06-30T21:14:15.139-07:00Speeding up the ADC on Arduino SAMD21 Boards (Zero, Mkr, etc) P1In this video we look at how to get higher ADC speeds out of Arduino boards that are based off of the SAMD21 microcontroller.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/glulIeL2lxA/0.jpg" src="https://www.youtube.com/embed/glulIeL2lxA?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
Windows file paths from video:<br />
<ul>
<li>files that define register data structures: C:\Users\yourname\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.18\bootloaders\sofia\Bootloader_D21_Sofia_V2.1\src\ASF\sam0\utils\cmsis\samd21\include\component</li>
<li>wire.c file path: C:\Users\yourname\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.18\cores\arduino</li>
</ul>
<div>
<br /></div>
<div>
//*******************Arduino example code from video*************************</div>
<div>
<div>
<span style="color: blue;">/*This code is from a tutorial on the ForceTronics YouTube Channel that talks about speeding up the sample rate on Arduino boards </span></div>
<div>
<span style="color: blue;"> * that use the SAMD21 microcontroller like the Arduino Zero or MKR series. This code is free and clear for other to use and modify </span></div>
<div>
<span style="color: blue;"> * at their own risk. </span></div>
<div>
<span style="color: blue;"> */</span></div>
<div>
<span style="color: blue;">#include <SPI.h></span></div>
<div>
<span style="color: blue;">#include <SD.h></span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">const int16_t dSize = 1024; //used to set number of samples</span></div>
<div>
<span style="color: blue;">const byte chipSelect = 38; //used for SPI chip select pin</span></div>
<div>
<span style="color: blue;">const byte gClk = 3; //used to define which generic clock we will use for ADC</span></div>
<div>
<span style="color: blue;">const byte intPri = 0; //used to set interrupt priority for ADC</span></div>
<div>
<span style="color: blue;">const int cDiv = 1; //divide factor for generic clock</span></div>
<div>
<span style="color: blue;">const float period = 3.3334; //period of 300k sample rate</span></div>
<div>
<span style="color: blue;">String wFile = "ADC_DATA"; //used as file name to store wind and GPS data</span></div>
<div>
<span style="color: blue;">volatile int aDCVal[dSize]; //array to hold ADC samples</span></div>
<div>
<span style="color: blue;">volatile int count = 0; //tracks how many samples we have collected</span></div>
<div>
<span style="color: blue;">bool done = false; //tracks when done writing data to SD card</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">void setup() {</span></div>
<div>
<span style="color: blue;"> portSetup(); //setup the ports or pin to make ADC measurement</span></div>
<div>
<span style="color: blue;"> genericClockSetup(gClk,cDiv); //setup generic clock and routed it to ADC</span></div>
<div>
<span style="color: blue;"> aDCSetup(); //this function set up registers for ADC, input argument sets ADC reference</span></div>
<div>
<span style="color: blue;"> setUpInterrupt(intPri); //sets up interrupt for ADC and argument assigns priority</span></div>
<div>
<span style="color: blue;"> aDCSWTrigger(); //trigger ADC to start free run mode</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">void loop() {</span></div>
<div>
<span style="color: blue;"> </span></div>
<div>
<span style="color: blue;"> if(count==(dSize-1) and !done) { //if done reading and they have not been written to SD card yet</span></div>
<div>
<span style="color: blue;"> removeDCOffset(aDCVal, dSize, 8); //this function removes DC offset if you are measuring an AC signal</span></div>
<div>
<span style="color: blue;"> SD.begin(chipSelect); //start SD card library</span></div>
<div>
<span style="color: blue;"> File myFile = SD.open((wFile + ".csv"), FILE_WRITE); //open file to write data to CSV file</span></div>
<div>
<span style="color: blue;"> if (myFile) {</span></div>
<div>
<span style="color: blue;"> float sTime = 0;</span></div>
<div>
<span style="color: blue;"> for (int y = 0; y < dSize; y++) {</span></div>
<div>
<span style="color: blue;"> myFile.print(sTime,5); //write each reading to SD card as string</span></div>
<div>
<span style="color: blue;"> myFile.print(",");</span></div>
<div>
<span style="color: blue;"> myFile.println(String(aDCVal[y])+","); //write each reading to SD card as string</span></div>
<div>
<span style="color: blue;"> sTime = sTime + period; //update signal period info</span></div>
<div>
<span style="color: blue;"> }</span></div>
<div>
<span style="color: blue;"> }</span></div>
<div>
<span style="color: blue;"> myFile.close(); //close file</span></div>
<div>
<span style="color: blue;"> done = true; //we are done </span></div>
<div>
<span style="color: blue;"> }</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">//function for configuring ports or pins, note that this will not use the same pin numbering scheme as Arduino</span></div>
<div>
<span style="color: blue;">void portSetup() {</span></div>
<div>
<span style="color: blue;"> // Input pin for ADC Arduino A0/PA02</span></div>
<div>
<span style="color: blue;"> REG_PORT_DIRCLR1 = PORT_PA02;</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> // Enable multiplexing on PA02_AIN0 PA03/ADC_VREFA</span></div>
<div>
<span style="color: blue;"> PORT->Group[0].PINCFG[2].bit.PMUXEN = 1;</span></div>
<div>
<span style="color: blue;"> PORT->Group[0].PINCFG[3].bit.PMUXEN = 1;</span></div>
<div>
<span style="color: blue;"> PORT->Group[0].PMUX[1].reg = PORT_PMUX_PMUXE_B | PORT_PMUX_PMUXO_B;</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">//this function sets up the generic clock that will be used for the ADC unit</span></div>
<div>
<span style="color: blue;">//by default it uses the 48M system clock, input arguments set divide factor for generic clock and choose which generic clock</span></div>
<div>
<span style="color: blue;">//Note unless you understand how the clock system works use clock 3. clocks 5 and up can brick the microcontroller based on how Arduino configures things</span></div>
<div>
<span style="color: blue;">void genericClockSetup(int clk, int dFactor) {</span></div>
<div>
<span style="color: blue;"> // Enable the APBC clock for the ADC</span></div>
<div>
<span style="color: blue;"> REG_PM_APBCMASK |= PM_APBCMASK_ADC;</span></div>
<div>
<span style="color: blue;"> </span></div>
<div>
<span style="color: blue;"> //This allows you to setup a div factor for the selected clock certain clocks allow certain division factors: Generic clock generators 3 - 8 8 division factor bits - DIV[7:0]</span></div>
<div>
<span style="color: blue;"> GCLK->GENDIV.reg |= GCLK_GENDIV_ID(clk)| GCLK_GENDIV_DIV(dFactor);</span></div>
<div>
<span style="color: blue;"> while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); </span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> //configure the generator of the generic clock with 48MHz clock</span></div>
<div>
<span style="color: blue;"> GCLK->GENCTRL.reg |= GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(clk); // GCLK_GENCTRL_DIVSEL don't need this, it makes divide based on power of two</span></div>
<div>
<span style="color: blue;"> while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);</span></div>
<div>
<span style="color: blue;"> </span></div>
<div>
<span style="color: blue;"> //enable clock, set gen clock number, and ID to where the clock goes (30 is ADC)</span></div>
<div>
<span style="color: blue;"> GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(clk) | GCLK_CLKCTRL_ID(30);</span></div>
<div>
<span style="color: blue;"> while (GCLK->STATUS.bit.SYNCBUSY);</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">/*</span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV4_Val 0x0u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV8_Val 0x1u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV16_Val 0x2u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV32_Val 0x3u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV64_Val 0x4u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV128_Val 0x5u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV256_Val 0x6u </span></div>
<div>
<span style="color: blue;">ADC_CTRLB_PRESCALER_DIV512_Val 0x7u </span></div>
<div>
<span style="color: blue;">--> 8 bit ADC measurement takes 5 clock cycles, 10 bit ADC measurement takes 6 clock cycles</span></div>
<div>
<span style="color: blue;">--> Using 48MHz system clock with division factor of 1</span></div>
<div>
<span style="color: blue;">--> Using ADC division factor of 32</span></div>
<div>
<span style="color: blue;">--> Sample rate = 48M / (5 x 32) = 300 KSPS</span></div>
<div>
<span style="color: blue;">This function sets up the ADC, including setting resolution and ADC sample rate</span></div>
<div>
<span style="color: blue;">*/</span></div>
<div>
<span style="color: blue;">void aDCSetup() {</span></div>
<div>
<span style="color: blue;"> // Select reference</span></div>
<div>
<span style="color: blue;"> REG_ADC_REFCTRL = ADC_REFCTRL_REFSEL_INTVCC1; //set vref for ADC to VCC</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> // Average control 1 sample, no right-shift</span></div>
<div>
<span style="color: blue;"> REG_ADC_AVGCTRL |= ADC_AVGCTRL_SAMPLENUM_1;</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> // Sampling time, no extra sampling half clock-cycles</span></div>
<div>
<span style="color: blue;"> REG_ADC_SAMPCTRL = ADC_SAMPCTRL_SAMPLEN(0);</span></div>
<div>
<span style="color: blue;"> </span></div>
<div>
<span style="color: blue;"> // Input control and input scan</span></div>
<div>
<span style="color: blue;"> REG_ADC_INPUTCTRL |= ADC_INPUTCTRL_GAIN_1X | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_MUXPOS_PIN0;</span></div>
<div>
<span style="color: blue;"> // Wait for synchronization</span></div>
<div>
<span style="color: blue;"> while (REG_ADC_STATUS & ADC_STATUS_SYNCBUSY);</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> ADC->CTRLB.reg |= ADC_CTRLB_RESSEL_8BIT | ADC_CTRLB_PRESCALER_DIV32 | ADC_CTRLB_FREERUN; //This is where you set the divide factor, note that the divide call has no effect until you change Arduino wire.c</span></div>
<div>
<span style="color: blue;"> //Wait for synchronization</span></div>
<div>
<span style="color: blue;"> while (REG_ADC_STATUS & ADC_STATUS_SYNCBUSY);</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> ADC->WINCTRL.reg = ADC_WINCTRL_WINMODE_DISABLE; // Disable window monitor mode</span></div>
<div>
<span style="color: blue;"> while(ADC->STATUS.bit.SYNCBUSY);</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> ADC->EVCTRL.reg |= ADC_EVCTRL_STARTEI; //start ADC when event occurs</span></div>
<div>
<span style="color: blue;"> while (ADC->STATUS.bit.SYNCBUSY);</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> ADC->CTRLA.reg |= ADC_CTRLA_ENABLE; //set ADC to run in standby</span></div>
<div>
<span style="color: blue;"> while (ADC->STATUS.bit.SYNCBUSY);</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">//This function sets up an ADC interrupt that is triggered </span></div>
<div>
<span style="color: blue;">//when an ADC value is out of range of the window</span></div>
<div>
<span style="color: blue;">//input argument is priority of interrupt (0 is highest priority)</span></div>
<div>
<span style="color: blue;">void setUpInterrupt(byte priority) {</span></div>
<div>
<span style="color: blue;"> </span></div>
<div>
<span style="color: blue;"> ADC->INTENSET.reg |= ADC_INTENSET_RESRDY; // enable ADC ready interrupt</span></div>
<div>
<span style="color: blue;"> while (ADC->STATUS.bit.SYNCBUSY);</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;"> NVIC_EnableIRQ(ADC_IRQn); // enable ADC interrupts</span></div>
<div>
<span style="color: blue;"> NVIC_SetPriority(ADC_IRQn, priority); //set priority of the interrupt</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">//software trigger to start ADC in free run</span></div>
<div>
<span style="color: blue;">//in future could use this to set various ADC triggers</span></div>
<div>
<span style="color: blue;">void aDCSWTrigger() {</span></div>
<div>
<span style="color: blue;"> ADC->SWTRIG.reg |= ADC_SWTRIG_START;</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">//This ISR is called each time ADC makes a reading</span></div>
<div>
<span style="color: blue;">void ADC_Handler() {</span></div>
<div>
<span style="color: blue;"> if(count<1023) {</span></div>
<div>
<span style="color: blue;"> aDCVal[count] = REG_ADC_RESULT;</span></div>
<div>
<span style="color: blue;"> count++;</span></div>
<div>
<span style="color: blue;"> }</span></div>
<div>
<span style="color: blue;"> ADC->INTFLAG.reg = ADC_INTENSET_RESRDY; //Need to reset interrupt</span></div>
<div>
<span style="color: blue;">}</span></div>
<div>
<span style="color: blue;"><br /></span></div>
<div>
<span style="color: blue;">//This function takes out DC offset of AC signal, it assumes that the offset brings signal to zero volts</span></div>
<div>
<span style="color: blue;">//input arguments: array with measured points and bits of measurement</span></div>
<div>
<span style="color: blue;">void removeDCOffset(volatile int aDC[], int aSize, int bits) {</span></div>
<div>
<span style="color: blue;"> int aSteps = pow(2,bits)/2; //get number of levels in ADC measurement and cut it in half</span></div>
<div>
<span style="color: blue;"> for(int i=0; i<aSize; i++) {</span></div>
<div>
<span style="color: blue;"> aDC[i] = aDC[i] - aSteps; //take out offset</span></div>
<div>
<span style="color: blue;"> }</span></div>
<div>
<span style="color: blue;">}</span></div>
</div>
ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com2tag:blogger.com,1999:blog-3259446650039490342.post-22218617715293474972018-05-23T03:54:00.001-07:002018-05-23T03:54:56.003-07:00Building an RGB LED Display Part 1In video series we build a scalable RGB LED Display or matrix and control it with Arduino. In part 1 we take a close look at the magic of the WS2812B RGB IC and Arduino options for controlling a large display of them.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Lycj8fk78oc/0.jpg" src="https://www.youtube.com/embed/Lycj8fk78oc?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
//***************Arduino Code from Video*************************************<br />
<span style="color: blue;">/* This Arduino sketch was made for a tutorial entitled "Building a Fun and Scalable RGB LED Display Part 1" for the ForceTronics YouTube Channel</span><br />
<span style="color: blue;"> * This sketch was leveraged from an example with the Adafruit NeoPixel library.This sketch was used to compare performance of an Arduino UNO versus </span><br />
<span style="color: blue;"> * the Altrium Sno FPGA based Arduino for controlling the ADafruit NeoMatrix. This sketch randomly changes each pixel's brightness and color in a timed</span><br />
<span style="color: blue;"> * loop.</span><br />
<span style="color: blue;"> * This code is free for others to use and modify at their own risk</span><br />
<span style="color: blue;"> */</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">#include <Adafruit_NeoPixel.h> //uncomment this library when using an AVR based Arduino</span><br />
<span style="color: blue;">//#include <XLR8NeoPixel.h> //uncomment this library when using the SNO</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// Defines single pin to control NeoMatrix from Arduino</span><br />
<span style="color: blue;">#define PIN 6</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">//defines number of pixels in the NeoMatrix that was used</span><br />
<span style="color: blue;">#define NUMPIXELS 64</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use</span><br />
<span style="color: blue;">//We can also set the comm speed and settings related to the how the NeoMatrix is configured</span><br />
<span style="color: blue;">//For more information on how to use arguments for this function go to: https://learn.adafruit.com/adafruit-neopixel-uberguide/neomatrix-library</span><br />
<span style="color: blue;">Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //decomment this function if you are using an AVR based Arduino</span><br />
<span style="color: blue;">//XLR8NeoPixel pixels = XLR8NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //uncomment this function if you are using the SNO FPGA Arduino</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">int delayval = 10; // delay for 10 msec</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void setup() {</span><br />
<span style="color: blue;"> pixels.begin(); // This initializes the NeoPixel or XLR8NeoPixel library.</span><br />
<span style="color: blue;">}</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;">void loop() {</span><br />
<span style="color: blue;"><br /></span>
<span style="color: blue;"> // For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one.</span><br />
<span style="color: blue;"> //This loops through all the pixels (1 to 64) and then starts back at 1</span><br />
<span style="color: blue;"> for(int i=0;i<NUMPIXELS;i++){</span><br />
<span style="color: blue;"> //This function sets the brightness of a pixel. Brightness can be 0 to 255. Using random() to generate psuedo random value between 0 and 255</span><br />
<span style="color: blue;"> pixels.setBrightness(random(0,255));</span><br />
<span style="color: blue;"> //This function sets the color scheme of an RGB LED, so values are red 0 to 255, green 0 to 255, blue 0 to 255.</span><br />
<span style="color: blue;"> //'i' is the pixel number that is being set and the other arguments are the RGB values which are set using psuedo random values between 0 and 255</span><br />
<span style="color: blue;"> pixels.setPixelColor(i, pixels.Color(random(0,255),random(0,255),random(0,255))); // Moderately bright green color.</span><br />
<span style="color: blue;"> //This function updates the pixels</span><br />
<span style="color: blue;"> pixels.show(); // This sends the updated pixel color to the hardware.</span><br />
<span style="color: blue;"> delay(delayval); // Delay for a period of time (in milliseconds).</span><br />
<span style="color: blue;"> }</span><br />
<span style="color: blue;">}</span>ForceTronicshttp://www.blogger.com/profile/07566887237874449390noreply@blogger.com0