Yes 50,000 hertz.
Yeah I've been reading that, I think I'm getting it figured out.
50,000 Hertz check, THX!
Place the code you are having trouble with into a working program so we can see for ourselves how it is eating up your available time, even if it doesn't in the small working example.
Put the code into some context so we can see how it works, how it is supposed to work. That will make diagnosis and treatment possible and vastly increase (!) the number of ppl who will put eyes (and instruments) on it.
a7
The Nano is able to output 8-bit resolution PWM at 490Hz on pins 3, 9, 10 & 11, as well as 980Hz on pins 5 & 6 using the analogWrite() function.
As others have mentioned, the analogWrite() function is efficient, since it's using the Nano's internal timers to generate the output, so there's no CPU intervention required.
If you require a 50kHz signal, it's possible to use the Nano's 16-bit timer 1 on digital pin D9. The below code sets up fast (single slope) PWM on D9 at a frequency of 50kHz with a 50% duty-cycle:
// Output 50kHz single slope (fast) PWM on digital pin D9
void setup() {
pinMode(9, OUTPUT); // Set digital pin 9 as an output
TCCR1A = _BV(WGM11) | _BV(COM1A1); // Enable the non-inverting PWM output OC1A on digital pin 9
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // Set up fast PWM and prescaler of 1 on timer 1
ICR1 = 319; // Set the timer 1 PWM frequency to 50kHz
OCR1A = 160; // Set the PWM duty cycle to 50%
}
void loop() {}
Note that with fast PWM there's a slight anomaly, in that when the duty-cycle is set to 0 (OCRA1 = 0), a thin single-tick pulse is still output on D9. This may or may not be an issue, depending on you application.
The part of analogWrite()
that is slow is Changing the value. That's what I'm trying to get around
Ok I'll do that
Link to library since its fairly obscure
GitHub - sadr0b0t/arduino-timer-api: Cross-platform Arduino timer API
#include <timer-api.h>
byte pwm = 1;
void setup() {
timer_init_ISR_50KHz(TIMER_DEFAULT);
}
void loop() {
pwm = analogRead(A0) * .249;
}
void timer_handle_interrupts(int timer) {
static byte pwmCount;
pwmCount++;
if (pwmCount < pwm or pwm == 255) {
PORTB = B00000010;
}
else {
PORTB = B00000100;
}
}
I'm not sure what's slow about changing the analogWrite() duty-cycle?
In any case, on the Nano you can't get any faster than simply changing the timers' OCRAx/OCRBx registers, like I showed in the 50kHz PWM example above.
The library you provided a link to, is calling the timer's Interrupt Service Routine at 50,000 times a second, just to bit bang the output. That's really inefficient. At that frequency the Nano will be doing little else other than servicing the ISR.
If that is your code you posted, you have floating point calculations in loop(). Those are slow. You haven't really given it much of a test, either, always sending the same value. Also it's not clear from that, how you determined that it is running slowly.
Also, you haven't explained why a motor controller would ever need to produce sub microsecond speed changes.
floating point multiplication is faster than division
I forget the exact results of my testing but changing analogWrite()
took substantially longer than DigitalWrite()
Also I'll look into that library, and see what I can do to fix it.
That is true. However, it's several hundred times slower than integer division.
pwm = analogRead(A0) / 4;
In this case, the compiler optimizes it to:
pwm = analogRead(A0) >> 2;
which might be several thousand times faster than floating point multiplication.
Also, you only responded to one out of four enquiries that I made...
I didn't realize that the compiler optimizes the division in that way.
I'm not sure what you mean by always sending it the same value.
I determined that the code was running slowly with a simple counter and the Serial monitor.
A motor controller probably doesn't need those speeds but as soon as the loop runs too slow my screen interface gets laggy, but this is irrelevant to my original question.
Does this satisfy your desire to know how I tested my loop speed?
#include <timer-api.h>
byte pwm = 1;
unsigned int counter;
unsigned long loops;
void setup() {
Serial.begin(2000000);
timer_init_ISR_50KHz(TIMER_DEFAULT);
}
void loop() {
loops++;
if(counter >= 50000){
Serial.println(loops);
counter = 0;
loops = 0;
}
pwm = analogRead(A0) * .249;
}
void timer_handle_interrupts(int timer) {
static byte pwmCount;
counter++;
pwmCount++;
if (pwmCount < pwm or pwm == 255) {
PORTB = B00000010;
}
else {
PORTB = B00000000;
}
}
Ok, there seems to be a misunderstanding about the way analogWrite() and digitalWrite() functions operate.
The digitalWrite() function sets the specified Arduino digital output either HIGH or LOW. Each change in the output from high to low or vice-versa requires CPU intervention and there's a slight delay as the CPU carries out the instructions to do this.
The analogWrite() function on the other hand sets up one of the microcontroller's internal timers. Once analogWrite() has been called, the timer continues to output the waveform without any CPU intervention, until the either the CPU changes the duty-cycle or alternatively tells it to stop.
If you're operating at PWM frequencies of 50kHz, it far more preferable to simply get the timer to automatically output the waveform at this speed without any CPU intervention using analogWrite(), than it is to interrupt the CPUs operation by calling an ISR each time the output needs toggling with digitalWrite().
By the way, if you need to toggle the output at 50,000 times a second, you'll need to call the ISR at double that, at 100,000 times a second. Using a 16MHz microcontroller to service a 100kHz ISR, doesn't leave much time for the CPU to do anything else.
You tested analogRead(), not analogWrite().
This kinda remarks
A motor controller probably doesn't need those speeds but as soon as the loop runs too slow my screen interface gets laggy, but this is irrelevant to my original question.
makes me ask you to get in the crib with me and explain why you need 50 thousand Hertz at all anywhere for something you are doing.
Again if I missed it sry.
a7
Also the answer was provided, a few steps back in the thread. I haven't tried it, but I see no reason why you couldn't use analogWrite() once to set up the PWM on a pin, and then simply modify the compare register directly from that time forward. That won't give you 50kHz but I frankly doubt that you need it. If you do, code was provided up thread.
I'm also frustrated that you won't answer simple questions about your application.
I suspect that the slowness that you complain about is caused by calling a timer interrupt every 20 microseconds. The test you showed us, didn't test the thing you are complaining about.
-_- I was testing my pwm system in this, not analogWrite. The analogRead is just the so the loops has something to do, maybe its not necessary but I thought it could be.
I'm confused as to how you came to the conclusion that that was what i was trying to test as it makes no sense if you actually read the code.
You commented (I think more than once) that you are concerned about analogWrite being too slow. I (mis)understood that this sketch was to test that. What aspect of your code does it test then?
I did actually read the code. Carefully.