Author Topic: Controlling the speed of a DC motor via PWM  (Read 7415 times)

0 Members and 1 Guest are viewing this topic.

Offline engineheatTopic starter

  • Frequent Contributor
  • **
  • Posts: 273
  • Country: us
Re: Controlling the speed of a DC motor via PWM
« Reply #50 on: July 21, 2023, 12:37:23 am »
I like the way you used interrupts in your code. My version does not use interrupts and the displayed rpm is not stable.

I didn't realize you can stop the millis() clock with interrupts. My current PWM of 25khz is implemented using timers, the TCCR1A, TCCR1B, ICR1 stuff. Will interrupts screw up the PWM signal?

Thanks
« Last Edit: July 21, 2023, 01:04:36 am by engineheat »
 

Offline engineheatTopic starter

  • Frequent Contributor
  • **
  • Posts: 273
  • Country: us
Re: Controlling the speed of a DC motor via PWM
« Reply #51 on: July 21, 2023, 12:53:05 am »
My next step is to make the setup more permanent by soldering it to a solderable breadboard (Perfboard?). I do want the power source and the motor to be easily detachable in case I need to change them. Ideally, those can use a screw-like connection. Are there connectors (terminal block?) that can fit on the spacing of that of a breadboard?

Thanks
 

Offline pqass

  • Frequent Contributor
  • **
  • Posts: 915
  • Country: ca
Re: Controlling the speed of a DC motor via PWM
« Reply #52 on: July 21, 2023, 06:39:00 am »
I like the way you used interrupts in your code. My version does not use interrupts and the displayed rpm is not stable.

I didn't realize you can stop the millis() clock with interrupts. My current PWM of 25khz is implemented using timers, the TCCR1A, TCCR1B, ICR1 stuff. Will interrupts screw up the PWM signal?

Thanks

millis() returns the value of an internal variable that is updated every 1.024 milliseconds via TIMER0_OVF_vect ISR.  Pin 2 external interrupt is handled by the INT0_vect ISR which Arduino hides behind the attachInterrupt() call.  Assuming 1000 RPM fan, that's 16.6 times per second or an interrupt every 60 milliseconds.

The noInterrupts() call stops all ISRs from executing.  All timer interrupts and the external interrupt raise a flag when their interrupt occurs (see: TIFR0:TOV, TIFR1, EIFR).  And will run their ISR (and clear the flag) as soon as the call to interrupts() re-enables global interrupts.

But we shouldn't stay in this interrupts-disabled state too long otherwise subsequent interrupts will be missed (flag still set, ISR yet to run when a newer interrupt arrives).  TIMER0 is set and forget by Arduino runtime initialization.  TIMER1, the one you are using, should also be set and forget until the need to change the PWM value.  I'm not sure of the need to call any ISR for TIMER1 (ICR1?).

So by keeping the interrupts-disabled state to a minimum (kept way below min(1ms,16ms)+overhead), you shouldn't lose any interrupts. And TIMER1 should still be outputting the same PWM even if the CPU is in an ISR. It'll just need to finish before you can change to a new PWM value.

I've updated the code below to do the bare minimum amount of work; just take a snapshot of the vars (5 assignments + 1.5us interrupt overhead, I think).  That way any slower math and floating point operations can be taken out of the critical section. Also, the rate is in RPM to avoid a divide by zero (in the last version).

EDIT: We don't stop the millis() clock; just hold-off updating it by preventing the ISR to run briefly.
EDIT2: Localized the rate calculating logic to the getTachRateInRPM() function.
EDIT3: Confirmed that the code works.  It just needed a cast to float in the function return.

Code: [Select]
const byte interruptPin = 2;   // or 3 would work too
volatile int counts = 0;
unsigned long last = 0;

void incCount() {
  counts++;
}

void setup() {
  pinMode(interruptPin, INPUT_PULLUP);    // tach output needs pullup to MCU Vcc
  attachInterrupt(digitalPinToInterrupt(interruptPin), incCount, FALLING);
}

float getTachRateInRPM() {
  noInterrupts();    // stop the count and millis() update for a brief moment
  unsigned long now = millis();
  unsigned long lastLast = last;
  int lastCounts = counts;
  last = now;
  counts = 0;
  interrupts();      // carry on counting

  // may need to divide counts var by n if the fan generates n counts per revolution.
  return (float)lastCounts / (last - lastLast) * 1000 * 60;
}

void loop() {
  float rate = getTachRateInRPM();

  delay(1000);       // do other stuff or wait some brief period of time before calculating rate again
}
« Last Edit: July 22, 2023, 12:31:42 pm by pqass »
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #53 on: July 21, 2023, 07:14:05 am »
what a lot of convolution to beat the arduino into doing what the very same micro could do if it was just programmed properly.

You set your timer up to run as fast as it can without overflowing between the slowest pulses (actually that is a way of extending the timer if it has other interrupts that let you count up those overflows), at every pulse the count is stored in a capture register and the timer resets.
 

Offline pqass

  • Frequent Contributor
  • **
  • Posts: 915
  • Country: ca
Re: Controlling the speed of a DC motor via PWM
« Reply #54 on: July 21, 2023, 07:52:59 am »
what a lot of convolution...

I see now. 
But you'd need another timer (TIMER2?) to create the PWM output for the fan.
Then, no more timers.
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #55 on: July 21, 2023, 08:16:43 am »
Even the ATmega328 has 3 timers: https://www.microchip.com/en-us/product/ATmega328#

2x 8 bit and one 16 bit. Now you need 25kHz PWM ? if the thing were running at 20MHz that would give you 800 steps (20MHz / 25kHz). with the 16MHz that most people use that is 640 steps, or to run at 25kHz on a 100 step PWM that is a divider of 6.4, or if you were at 20MHz that is 8, wonder where I see that number a lot, it is likely that the counters can have a prescaler of 8.

Now if you are not super hot on your accuracy of speed measuring what you can do is not only have a capture compare output running for PWM but the top count/rollover interrupt enabled. This means that you know every time the counter got to 100, that means you can increment a variable every 40µs, even at a fan speed of 2000rpm that is 30ms/rev or 15ms per pulse? at 2 pulses per rev. that is 750 counts even at the highest speed. at 400rpm you will have 75ms pulses which will be 1875 counts. You also have a system clock variable that you can use, that is in a decent round number and unlike the arduino is what it says it is.

You get everything done with one counter and have a system timer for free and you don't even have to worry about reading the counter value but you could if you wanted 50ns accuracy.

This is how micro controllers were supposed to be used, not as sodding PC's!!!
 

Offline pqass

  • Frequent Contributor
  • **
  • Posts: 915
  • Country: ca
Re: Controlling the speed of a DC motor via PWM
« Reply #56 on: July 21, 2023, 08:43:08 am »
Thanks, that's good to know you can do both in one timer.

But we're in the Beginners forum and the TIMER1 docs are 20 pages long.

Apart from his UI, all he has to call is pinMode(pin, OUTPUT) and analogWrite(pin, pwmVal) occasionally.
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #57 on: July 21, 2023, 09:04:22 am »
Thanks, that's good to know you can do both in one timer.

But we're in the Beginners forum and the TIMER1 docs are 20 pages long.

Apart from his UI, all he has to call is pinMode(pin, OUTPUT) and analogWrite(pin, pwmVal) occasionally.


This is the problem I have with my apprentice. He thinks bit plipping in registers is a waste of time and only wants to work on high level stuff and never looks at how something works. This means that everything he does is a start from scratch copying examples etc. The problem here is that with this way of working you get to a point where your screen does not update fast enough so you keep cranking the clock frequency beyond what it should be and are still amazed that it's even working and that the updating problem is still there. The he comes and tells me about it and I say OK, have you actually measured the screen clock frequency, so he does and it's low, OK so that is why the screen did not fall over when the clock was set even higher. OK, describe the system to me, what blocks does it have and how do they interact? Oh there is your problem, it's a general system wide problem that delays the screen data transfer, not that the screen is not being sent data fast enough....

So 20 pages you say? doddle, this is what a forum like this is for, to help you with that. If you are frightened by the datasheet of I assume an AVR then don't think about touching anything else, that is as simple as it gets. once you understand the counter in one micro controller you are over half way there for any counter in any other micro controller, while there are 100's of manufacturers most sort of do it the same way.

The problem I found when I started was that no one explains in one piece how programming micro's works. You need to understand the chip, how to use C to setup the hardware because all C lessons are about PC environments and this was the big stumbling block for me. Then you need explaining that there are the chip's header files and how to use them. I did one project in Arduino, after struggling to get into micro controllers, then I converted it into a project written in the manufacturers IDE and never looked back. Every time I think of using an Arduino for a quick lash up, 5 seconds is about as far in as I get before I realize that the way in which the Arduino abstracts the hardware for you is actually crippling your ability to get stuff done. So I go back to a plain micro controller and continue to increase my own basic code base to use as a starter for any project.

Arduino for example will not allow you to use ADC's very well, you have to ask for a conversion and wait. In my code I set up the ADC to run in a round robin mode so that it simply cycles through the channels I want it to and at any time without worrying about interacting directly with the ADC I take my results from a variable that the interrupt routine put them into. These are already oversampled and/or filtered because relying on a single conversion is a really bad idea, but this is what the Arduino teaches you to do.

Everything the Arduino system leads you to believe is wrong in my view. If you are one of the prescribed target Audience - hacker whatever the hell that is, maker, um same, hobbyist, artist anything but engineer or aspiring engineer then fine. But if you are an engineer or want to be one the Arduino is not for you, it was designed for non technical people to give people with no interest in electronics something to use. But like most things people forgot to read the specs: designed for non electronics people and maybe programmers.
« Last Edit: July 21, 2023, 09:06:50 am by Simon »
 

Offline Infraviolet

  • Super Contributor
  • ***
  • Posts: 1152
  • Country: gb
Re: Controlling the speed of a DC motor via PWM
« Reply #58 on: July 21, 2023, 06:11:21 pm »
If you're using arduino's IDE and its uploading/programming functionality (AVRDUDE is the actual command line tool doing this part underneath) specifically for AVR microcontrollers and use the more abstracted functions only in very limited places (if pinMode is a bit slow, but only used once during initial setup then so what, it is very different to digitalWrite being slow when you need to bitbang out some unusual data protocol at speed) I would say it can be pretty adequate. Especially if you load programs on to their final chips with the programemr method, rather than the usual upload (lets them recover much faster after a reset). The problem with arduino isn't it in itself, it is with overly using its easy abstraction functions, and using it for chips very different from AVRs where there aren't such simple ways to directly call the underlying register functions hence you get more easily forced in to the abstraction layers, and using libraries without first looking carefully inside them to verify they work sensibly beneath their own abstractions and don't stack extra abstraction on top of already highly abstracted functions.
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #59 on: July 21, 2023, 07:05:41 pm »
the problem with the Arduino is that it was designed for an AVR, the limitations this imposed onto the software environment and what you have available to you are then inherited into systems made with more complex chips.

Again take the analogue read example. On an AVR it only gets as bad as you do it in polling mode so your program waits an eternity as the ADC takes over 10 ADC clock cycles to make a conversion which typically runs at a mere 100kHz, so now your 16-20MHz CPU is sat waiting for say 2400 cycles doing nothing while waiting for the ADC conversion. OK, so the AVR has no hardware to support ADC averaging or oversampling so it is just thousands of CPU cycles gone to waste unless and interrupt makes use of them.

But enter say the SAMD, this now runs at 48MHz with an ADC that can do 1MSPS, so your CPU will just waste 48 clock cycles waiting. But there is still this thing that you should not rely on a single ADC result unless you have good reason to, I mean just look at the.... od sorry, Arduino users do not care for datasheets. Anyway, look at the datasheet and you will find that there are caveats galore on everything in that bit at the back that makes the 12 bit ADC just about good to do 10 bit, if you want to rely an ever last count of that ADC result you need to filter. Well the SAD has the hardware to accumulate results and bit shift them so that the while process presents itself in the same way as your single unreliable ADC result in the AVR but all that work is done in the back ground. If you go banannas on it that is a result every 1ms or so. But wait, the arduino knows nothing of this, you still get a single result and may end up writing averaging code at great expense of CPU resources when you already have hardware to do that.

I know that the modern approach is to show something snazzy and slowly work backwards and that is fine, but if the snazzy thing is so hopelessly useless except to those that do not care that you will have to unlearn so much and start again then good luck....
 

Offline pqass

  • Frequent Contributor
  • **
  • Posts: 915
  • Country: ca
Re: Controlling the speed of a DC motor via PWM
« Reply #60 on: July 21, 2023, 08:32:53 pm »
Every clock cycle is NOT sacred. God will NOT get irate if some are wasted.

Using the Arduino APIs allows the developer to work at the level of his current understanding.  With every project, if he chooses, he can explore a bit of the low-level hardware then replace the training wheels with an impenetrable yet efficient wall of register assignments.   That's much better than being thrown into the deep end with only a hardware reference manual and maybe a code-generator.

In response to questioners, specific features should be referenced by their name as they appear in the manual, a quick refresher on what they are and how they are typically used, any obvious dependencies/limitations, and include code snips where possible.  I was not aware of the ICR1 register and TIMER1_CAPT ISR nor am I entirely sure which PWM mode it would work with.  Timers are the most dense and configurable subsystem on the MCU and need to be digested piecemeal.  I think I presented a straightforward, undemanding solution.
 
The following users thanked this post: eugene

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #61 on: July 21, 2023, 09:53:42 pm »
learning about the micros register will not teach you basic signal processing, you are either into the engineering or you are not, this was the point of Arduino, like Yorkie bars it is for the boys, it is not for engineers!

No clock cycles are not sacred, but with the wrong approach and a total lack of understanding one will be left wondering why with such a fast processor it takes so long to do anything, so the solution must be an even faster processor. next a Blinking LED on a Pentium?

Same logic as my apprentice that thought he was cranking up his video clock when in fact something else was holding it up! And it was I who understood nothing of the specific system but enough about "systems" that got him to reason through to what was wrong.
 

Offline engineheatTopic starter

  • Frequent Contributor
  • **
  • Posts: 273
  • Country: us
Re: Controlling the speed of a DC motor via PWM
« Reply #62 on: July 23, 2023, 01:49:05 am »
You guys have been mighty helpful. I'm able to successfully control the 4 wire fan via 25khz PMW with the Arduino and adjust/display the speed.

Only question now is, when I measured the various current draw at different duty cycles, I got about 0.17A at 100% duty cycle and half of that at 50% duty cycle, which makes sense. But when I connected the fan directly to the power source bypassing the Arduino, the current is about 0.20A, which is not that different from 0.17A but I'm kinda curious why there is a difference.

I also would like to know why this is much different than the "rated current", which according to the datasheet is 0.34 (max: 0.42) A

https://www.digikey.com/en/products/detail/delta-electronics/BFB0712HH-AWPH/13997125?s=N4IgTCBcDaIEIDE4AYDsBGMAJLBaAggOoAKWIAugL5A
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #63 on: July 23, 2023, 08:04:17 am »
Well I would be quite surprised to see only half the current at 50% but then I understand fan laws, oh yes, you want to do "electronics", well you are dead in the water if you don't have a basic understanding of the real world so lots of I suppose physics.

What are the actual speeds? the duty cycle of the PWM to current comparison is meaningless. As the fan is so small other factors may contribute in a way that has the whole thing deviate from fan laws as these apply to the mechanical input energy to the impellor. The datasheet seems to suggest a linear relationship of PWM duty to speed but they are so vague that it is anyone's guess. Fan laws state that the flow goes up or down proportional to speed and the pressure follows a square law. So double your speed and you get twice the flow and 4 times the pressure. This is fortunate as if you want to move air inside a duct at twice the speed you will need 4 times the pressure as that bit of fluid dynamics follows the same square law.

So what that means is that the power input to the impellor changes in relation to the speed with a cubic relationship. double your speed and the power required is 2^3 = 8 times. Do this in reverse and at halve speed you should be using 1/8 the power. Now obviously on something so small you also have to take into account that just getting the unloaded motor turning will take some considerable power compared to running the fan so the results will be skewed. This is one reason to have fan speed control, apart from noise reduction there are huge efficiencies in power by running at a constant lower speed rather than sporadically at the maximum speed (think auto radiator). When I worked around automotive stuff I did some calculations, by running an 850W brushless fan at 50% speed you would probably double the lifespan of the fan and save an amount of fuel equivalent to £10'000 over the lifetime of the fan. At the time I was working on a buss project and the company were talking about up to 10 fans on one bus.

The other thing to remember is that the power demand from the impellor is down to how much air it is moving, not how much pressure it is exerting. This is highly counter intuitive but and most people get confused over it, even engineers specing fans, if you block the fan inlet or outlet stopping the airflow the current will plummet, this is because all you are doing now is spinning a fly wheel as air is not being moved. The maximum current they state may be with the fan impellor in open air or maybe you had the airflow a little restricted.

Also that fan runs up to 13.8V it will use the more current as with a higher voltage more speed can be achieved but more torque (current) will be required to drive the fan pushing more air because if the speed goes from 12 to 13.8V that is 15% increase in speed on the motor, now we now know that the increase in flow will be 15% and power at this speed is 1.15*1.15*1.15 = 1.52. The voltage has gone up by 15% so we can make that 1.15*1.15 = 1.32, a 32% increase in current requirement. 0.42/0.2 = extra 70%, but remember that real fans will not do fan laws perfectly and you have a cheap little motor in there.

As for the current change from 0.17 to 0.2, yea, that may be the internal interface circuitry, 100% may not be 100%, I would check the arduino output is really 100% duty, many micros won't do 100%. It is also possible that there is something about the circuit that does not produce the equivalent of 100%. In my early days with speed controlling fans The fan manufacturer had a simple system, the input voltage was put through a resistor followed by a 10V Zener, this made the PWM that you would expect to be at battery voltage 10V, then they cut this in halve with a resistive potential divider that also had a filter capacitor low pass filtering the PWM to a voltage. When I tried to drive a 2N7002 MOSFET from my micro that was pulled up to the battery voltage with a 10k resistor that was quite a bit smaller than the resistors in the fan, customers reported the same behavior you have described. The problem here was that they were trying to push the systems to the limits.
 

Offline engineheatTopic starter

  • Frequent Contributor
  • **
  • Posts: 273
  • Country: us
Re: Controlling the speed of a DC motor via PWM
« Reply #64 on: October 03, 2023, 12:15:12 am »
I got a good prototype working with the 4 wire fan and was able to control the speed using the Arduino via PWM (25khz). This has been a good learning experience.

But so far I've only used a small 12 V BLDC fan like this:


I wonder if there are much bigger fans that I can use to get bigger air flow, yet still has 4 wires and can use the same control circuitry? FYI, this is for air filtration purposes and the small one I built was for personal use. But now I want to build a bigger version that can purify a whole room. Do I need to look for AC fans?

Thanks
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 18035
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: Controlling the speed of a DC motor via PWM
« Reply #65 on: October 03, 2023, 07:46:05 am »
AC fans are your best bet. There are powerful brushless 12V and 24V options as well as mains. Look at ebmpapst, they have mains fans with 10V controls and sometimes a 10V supply. Spal is another option if 12/24V is what you are after, they will only work between 100 and 500Hz, I have made many a controller for them, they will also accept 0-10V input.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6878
  • Country: fi
    • My home page and email address
Re: Controlling the speed of a DC motor via PWM
« Reply #66 on: October 03, 2023, 07:53:47 pm »
I wonder if there are much bigger fans that I can use to get bigger air flow, yet still has 4 wires and can use the same control circuitry? FYI, this is for air filtration purposes and the small one I built was for personal use. But now I want to build a bigger version that can purify a whole room. Do I need to look for AC fans?
I'd take a look at the specs of Noctua IndustrialPPC fans, for example the NF-A14 IndustrialPPC-3000 PWM, and if not sufficient or suitable, move to AC fans; specifically, I'd look at quiet AC duct fans.

NF-A14 IndustrialPPC-3000 runs at 12 VDC as usual, but may draw up to 0.61 A of current (7.3 W).  Uses the exact same control mechanism and specs as your bog-standard 4-pin PWM PC case fans (25 kHz control signal, tach return with two pulses per rotation, et cetera).  It can generate up to 6.58 mm H₂O static pressure, meaning it is well suited for air filtration.  Maximum airflow is 269 m³/h ≃ 158 CFM.

I'll probably use one or two (at lower RPM for quieter operation) for a 40/60-liter soldering open fume hood with HEPA filtering, for use in my small flat.
 

Offline engineheatTopic starter

  • Frequent Contributor
  • **
  • Posts: 273
  • Country: us
Re: Controlling the speed of a DC motor via PWM
« Reply #67 on: October 04, 2023, 04:32:23 am »
Thanks.
While we are on the topic of air filtration and fans, I have a side question. I recently went on a trip to China where the voltage is 220V, 50Hz and I brought along my US bought air purifier that runs on 120V, 60Hz. I used this power converter:

https://www.bestekdirect.com/bestek-universal-travel-power-converter-with-qc-3.0-white

It converts 240/220V to 120/110V.

While the air purifier worked in China, I noticed that it is significantly louder. It might be possible that it was damaged during transit, but I wonder if there might be an electronics explanation? I also noticed a high pitched whine that not even my earplugs can fully block. Unfortunately, I did not bring it back to the US so I cannot test it again.

Could the increased noise be due to the power converter? Does it have to do with sinusoidal/non-sinusoidal waves?
Thanks
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf