{"id":10,"date":"2015-11-07T21:22:00","date_gmt":"2015-11-07T21:22:00","guid":{"rendered":""},"modified":"2023-08-18T12:34:41","modified_gmt":"2023-08-18T11:34:41","slug":"pwm-to-esc-converter-1","status":"publish","type":"post","link":"https:\/\/blog.hslracing.com\/electronics\/2015\/11\/pwm-to-esc-converter-1.html","title":{"rendered":"PWM to ESC Converter 1"},"content":{"rendered":"<p>I have been looking at ways of using the PWM output of <a href=\"https:\/\/github.com\/grbl\/grbl\/wiki\/Connecting-Grbl\">GRBL<\/a> to control a brushless RC motor via an ESC.<\/p>\n<p>Now there is a commercial option available from <a href=\"http:\/\/www.logicnc.com\/rcnc.html\">Logicnc<\/a>, but I object to paying $34.99 for something that can potentially be made for pennies.<\/p>\n<p>I came across a post by Kretov on the <a href=\"http:\/\/www.cnczone.com\/forums\/general-cnc-machine-related-electronics\/106381-mach3-gt-brushless-esc-interface-arduino.html\">CNCZone<\/a>\u00a0covering this very topic.<\/p>\n<p>He had posted a schematic and hex files, along with source code to implement this on a <a href=\"http:\/\/www.microchip.com\/wwwproducts\/Devices.aspx?product=PIC12F629\">PIC12F629<\/a>\u00a0(DIP 8) chip.<\/p>\n<div style=\"clear: both; text-align: center;\"><a href=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BScheme.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-55 size-medium\" src=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BScheme-300x205.png\" alt=\"\" width=\"300\" height=\"205\" srcset=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BScheme-300x205.png 300w, https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BScheme-768x524.png 768w, https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BScheme.png 880w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/div>\n<p>He even posted a suitable PCB layout.<\/p>\n<div style=\"clear: both; text-align: center;\"><a href=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BPCB.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-56 size-medium\" src=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BPCB-300x205.png\" alt=\"\" width=\"300\" height=\"205\" srcset=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BPCB-300x205.png 300w, https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/EscConverter-2BPCB.png 346w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/div>\n<p>I also came across a similar post by <a href=\"http:\/\/www.cooperman.talktalk.net\/\">Tweakie<\/a> on the\u00a0<a href=\"http:\/\/openbuilds.com\/builds\/software-speed-control-of-a-brushless-dc-bldc-motor-from-mach3.762\/\">OpenBuilds<\/a>\u00a0website which discusses exactly the same type of process, again with hex files for use on a PIC micro-controller.<\/p>\n<div style=\"clear: both; text-align: center;\"><a href=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/escpwm.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-57 size-medium\" src=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/escpwm-300x201.jpg\" alt=\"\" width=\"300\" height=\"201\" srcset=\"https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/escpwm-300x201.jpg 300w, https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/escpwm-768x515.jpg 768w, https:\/\/blog.hslracing.com\/wp-content\/uploads\/sites\/2\/2015\/11\/escpwm.jpg 800w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/div>\n<p>His implementation uses NAND gates to provide buffering and a clean square wave, and is further enhanced with the provision for manual control via a potentiometer.<\/p>\n<p>Now I have nothing against PIC chips, especially as <a href=\"http:\/\/www.microchip.com\/\">Microchip<\/a> are willing to give away free samples of their micro controllers, which is more than can be said for <a href=\"http:\/\/www.atmel.com\/\">Atmel<\/a>, I just have yet to become familiar with their associated programming environment.<\/p>\n<p>As such I decided to attempt to port the code written by Kretov to a suitable AVR chip.<\/p>\n<p>My first choice, given the limited number of pins required (3), was to use an <a href=\"http:\/\/www.atmel.com\/devices\/attiny85.aspx\">ATtiny25\/45\/85<\/a> (DIP8) chip, unfortunately, this has 2 x 8 bit timers, and this project calls for 1 x 8 bit and 1 x 16 bit timer or ideally 2 x 16 bit timers.<\/p>\n<p>So the next size up is the <a href=\"http:\/\/www.atmel.com\/devices\/attiny84a.aspx\">ATtiny24\/44\/84<\/a> (DIP 16) family, where it does indeed have the required timers.<\/p>\n<p>Unfortunately, \/16 is not an available prescaler for the 8 bit timer and so I had to make use of \/64 instead.<\/p>\n<p>This is still a work in progress and has yet to be tested, but I believe I now have a useable set of code:<\/p>\n<pre>\/\/ 8 bit Timer 0 and \/64 prescaler used for input, 125 ticks = 1ms\r\n\/\/ 16 bit Timer 1 and \/8 prescaler used for output, 1000 ticks = 1ms\r\n\/\/ PWM input connected to PA0 (Pin 13)\r\n\/\/ ESC output connected to PB0 (Pin 2)<\/pre>\n<p>uint16_t MIN_WIDTH = 125; \/\/ 8MHz \/8 = 1000 clock ticks = 1ms<br \/>\nuint16_t MAX_LENGTH = 125; \/\/ 8MHz \/8 = 1000 clock ticks = 1ms<br \/>\nuint16_t OUT_PERIOD = 1000; \/\/ 8MHz \/16 = 16000 clock ticks = 20ms<br \/>\nuint16_t MAX_WIDTH = MIN_WIDTH + MAX_LENGTH; \/\/ 2ms<br \/>\nuint16_t InPeriod = 0;<br \/>\nvolatile uint16_t Pulse = MIN_WIDTH; \/\/ 1ms<\/p>\n<p>void setup(void)<br \/>\n{<br \/>\n\/\/ Setup Interrupts<br \/>\nGIMSK |= (1 &lt;&lt; PCIE1); \/\/ Enable Interrupts on Pin Change<br \/>\nPCMSK0 |= (1 &lt;&lt; PCINT0); \/\/ Generate Interrupts on PA0 (Pin 13)<br \/>\nsei(); \/\/ enable interrupts<\/p>\n<p>\/\/ Setup Timer 0<br \/>\nTCCR0B |= (1 &lt;&lt; CS00) | (1 &lt;&lt; CS01); \/\/ \/64 prescaler on Timer 0<br \/>\nTCNT0 = 0; \/\/ Initialise counter for Timer 0<\/p>\n<p>\/\/ Setup Timer 1<br \/>\nTCCR1B |= (1 &lt;&lt; CS11); \/\/ \/8 prescaler on timer 1<br \/>\nTIFR1 |= (1 &lt;&lt; ICF1); \/\/ clear interrupt-flag<br \/>\nTIMSK1 |= (1 &lt;&lt; ICIE1); \/\/ enable Timer1 input capture interrupt<br \/>\nTCNT1 = 0; \/\/ Initialise counter for Timer 1<\/p>\n<p>\/\/ Setup Ports<br \/>\nDDRB |= (1 &lt;&lt; DDB0); \/\/ enable port B0 (pin 2) for output<\/p>\n<p>CalcOutput(); \/\/ arm ESC<br \/>\n}<\/p>\n<p>void CalcOutput() { \/\/ calculate Timer 1 overflow based on Pulse<br \/>\nuint16_t i = 0xFFFF;<\/p>\n<p>if (PINB &amp; (1 &lt;&lt; PINB0)) { \/\/ last input low<br \/>\ni -= OUT_PERIOD &#8211; Pulse; \/\/<br \/>\n} else { \/\/ last input high<br \/>\ni -= Pulse;<br \/>\n}<br \/>\nTCNT1 = i;<br \/>\n}<\/p>\n<p>ISR (PCINT0_vect) {<br \/>\nif (TOV1 == 0b1) { \/\/ Timer 1 wrapped<br \/>\nPORTB ^= (1 &lt;&lt; 0); \/\/ Flip Port B0<br \/>\nCalcOutput();<br \/>\nTIFR1 &amp;= ~(1 &lt;&lt; TOV1); \/\/ Reset Timer 1 Overflow flag<br \/>\n}<\/p>\n<p>if (PCINT0 == 0b1) { \/\/ Input pin data changed<br \/>\nif (PINA &amp; (1 &lt;&lt; PINA0)) { \/\/ last input high<br \/>\nInPeriod = TCNT1; \/\/ Period = timer count<br \/>\nTCNT1 = 0; \/\/ Reset Timer Count<br \/>\n} else {<br \/>\nif (InPeriod &gt; 0) { \/\/ don&#8217;t calculate on first run through<br \/>\nPulse = MAX_WIDTH + MAX_LENGTH * TCNT0 \/ InPeriod; \/\/ re-scale output<br \/>\nif (Pulse &gt; MAX_WIDTH) Pulse = MAX_WIDTH;<br \/>\nif (Pulse &lt; MIN_WIDTH) Pulse = MIN_WIDTH;<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>if (TOV0 == 0b1) { \/\/ Timer 0 wrapped &#8211; no pulses detected<br \/>\nif (PINA &amp; (1 &lt;&lt; PINA0)) { \/\/ last input high<br \/>\nPulse = MAX_WIDTH; \/\/ max pulse<br \/>\n} else { \/\/ last input low<br \/>\nPulse = MIN_WIDTH; \/\/ min pulse<br \/>\n}<br \/>\nInPeriod = 0; \/\/ Reset Period<br \/>\nTIFR0 &amp;= ~(1 &lt;&lt; TOV0); \/\/ Reset Timer 0 overflow flag<br \/>\n}<br \/>\n}<\/p>\n<p>void loop() { \/\/ Do Nothing &#8211; all handled in ISR<br \/>\n}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have been looking at ways of using the PWM output of GRBL to control a brushless RC motor via an ESC. Now there is a commercial option available from Logicnc, but I object to paying $34.99 for something that can potentially be made for pennies. I came across a post by Kretov on the&hellip;<\/p>\n","protected":false},"author":2,"featured_media":55,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-10","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/posts\/10","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":4,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/posts\/10\/revisions"}],"predecessor-version":[{"id":179,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/posts\/10\/revisions\/179"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/media\/55"}],"wp:attachment":[{"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/media?parent=10"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/categories?post=10"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.hslracing.com\/electronics\/wp-json\/wp\/v2\/tags?post=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}