Jump to content

Generating PWM signal


jreveane
 Share

Recommended Posts

Hi,

 

I'm a brand new user of TinkerForge devices which I've only discovered recently.

I'd like to be able to generate a PWM signal to control the speed of a pump.

I thought that I could do that either with the 4 Digital I/O or the

AnalogOut Bricklets but reading the API documentation did not confirm this.

I don't think that the DC motors bricklets would be appropriate either.

Does anyone know how I could generate this kind of signal easily then ?

Thanks in advance for your help.

Link to comment
Share on other sites

The Servo Brick can generate 7 PWM signals, but you cannot drive a load directly with them, as they are designed as control signals only.

 

The DC Brick can generate 1 PWM signal with enough power to drive a load.

 

The Digital I/O and AnalogOut Bricklets don't have hardware support for generating PWM signals. You could manually generate a PWM signal, but this has some disadvantages compared to the Servo and DC Brick. The Digital I/O and AnalogOut Bricklets are limited in their switching frequency and precision due to the speed and possible jitter in the communication between the PC and the Bricklets.

 

So the correct approach depends on the actual interface of your pump. Can you provide more information about it?

Link to comment
Share on other sites

Thanks a lot for your reply.

Regarding the pump itself, the power is provided by main AC 230V

but its speed is controlled by a PWM signal (1Kz) with a usable

and variable speed range from 10 to 80%.

So, basically, I would need to be able to emulate and get

the same behavior than the Arduino  AnalogWrite() for example.

BTW, I've noticed that the Breakout Bricklet does expose a PWM signal.

I guess it is used for the SPI interface could it be used for

this purpose if there is no attached SPI device on this slot ?

Thanks.

 

Link to comment
Share on other sites

Your required PWM signal can very easily be created by a Servo Brick. The PWM signal of the Servo Brick has a fixed output voltage of 5V. If that works for the control interface of your pump then I suggest a Servo Brick for this purpose.

 

Regarding the PWM label on the Breakout Bricklet: This is basically a mislabeling, there is no usable PWM signal on that pin.

Link to comment
Share on other sites

Thanks for your reply, I do appreciate.

The main issue is the prince then since using a servo brick is at least 5 times more expensive than

a simple bricklet to provide this kind of feature.

I had a look at the servo brick C/C++ API and unless I'm wrong I should use:

- int servo_set_period(Servo *servo, uint8_t servo_num, uint16_t period)

to setup the PWM frequency

- int servo_set_pulse_width(Servo *servo, uint8_t servo_num, uint16_t min, uint16_t max)

to setup the PWM duty cycle

 

I my case, how should I set the min and max values, I mean can they have

the same value ?

Regarding the PWM frequency, it sounds that the max is 500 Hz ?

Last, can I use the servo brick without external power if I simply

need to generate a PWM command signal ?

Thanks.

 

Link to comment
Share on other sites

Here's an example for PWM generation with the Servo Brick:

 

#include <stdio.h>

#include "ip_connection.h"
#include "brick_servo.h"

#define HOST "localhost"
#define PORT 4223
#define UID "6dKCNw" // Change to your UID

// Due to the internal clock dividing mechanism of the Servo Brick not all
// arbitrary PWM frequency values can be achieved. For example, the upper most
// three available PWM frequency values are 1MHz, 500kHz and 250kHz. The steps
// are coarser on the high frequency end and much finer on the low end. You can
// set any value here between 15Hz and 1MHz and the Servo Brick will try to
// match it as closely as possible.
#define PWM_FREQUENCY 175000 // in Hz [15Hz to 1MHz]
#define PWM_DUTY_CYCLE 20 // in % [0% to 100%]

int main() {
// Create IP connection
IPConnection ipcon;
ipcon_create(&ipcon);

// Create device object
Servo servo;
servo_create(&servo, UID, &ipcon);

// Connect to brickd
if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
	fprintf(stderr, "Could not connect\n");
	exit(1);
}
// Don't use device before ipcon is connected

// Set degree range to 0-100, this will allow to
// set the PWM duty cycle in 1% steps
servo_set_degree(&servo, 0, 0, 100);

// Set PWM frequency (1-65535µs == 1MHz-15Hz)
int period = 1000000 / PWM_FREQUENCY;

if (period < 1) {
	period = 1; // 1MHz
} else if (period > 65535) {
	period = 65535; // ~15Hz
}

servo_set_pulse_width(&servo, 0, 0, period);
servo_set_period(&servo, 0, period);

// Fast acceleration and full speed
servo_set_acceleration(&servo, 0, 65535);
servo_set_velocity(&servo, 0, 65535);

// Set PWM duty cycle (0-100 %)
int position = PWM_DUTY_CYCLE;

if (position < 0) {
	position = 0;
} else if (position > 100) {
	position = 100;
}

servo_set_position(&servo, 0, position);

// Enable PWM signal
servo_enable(&servo, 0);

printf("Press key to exit\n");
getchar();
ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally
}

 

Regarding the PWM frequency, it sounds that the max is 500 Hz ?

 

The Servo Brick can generate PWM frequencies up to 1MHz. Why do you think it's 500Hz, were did you get that information?

 

Last, can I use the servo brick without external power if I simply

need to generate a PWM command signal ?

 

Yes, the power for the PWM signal is taken from the USB connection. The black power connector on the Servo Brick is for powering the servo motors. So you don't need it if you just want to use the PWM signal only.

 

Here's and other example of using an IO-4 Bricklet for 3.3V PWM generation. In this example the whole timing is done from the PC and is affected by the jitter of the operating system scheduler and is limited by the USB speed.

 

#include <stdio.h>
#include <sys/time.h>

#include "ip_connection.h"
#include "bricklet_io4.h"

#define HOST "localhost"
#define PORT 4223
#define UID "hf4" // Change to your UID

#define PWM_FREQUENCY 100 // Hz
#define PWM_DUTY_CYCLE 20 // 0% to 100%

uint64_t microseconds(void) {
struct timeval tv;

gettimeofday(&tv, NULL);

return tv.tv_sec * 1000000 + tv.tv_usec;
}

// have to use busy waiting here, using usleep() is not accurate enough
void delay(uint64_t ms) {
uint64_t last = microseconds();
uint64_t now = last;

while (now < last + ms) {
	now = microseconds();
	continue;
}
}

int main() {
// Create IP connection
IPConnection ipcon;
ipcon_create(&ipcon);

// Create device object
IO4 io;
io4_create(&io, UID, &ipcon);

// Connect to brickd
if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
	fprintf(stderr, "Could not connect\n");
	exit(1);
}
// Don't use device before ipcon is connected

// Set pin 0 to output low
io4_set_configuration(&io, 1 << 0, 'o', false);

int high_time = ((1000000 * PWM_DUTY_CYCLE) / 100) / PWM_FREQUENCY;
int low_time = ((1000000 * (100 - PWM_DUTY_CYCLE)) / 100) / PWM_FREQUENCY;

for (; {
	io4_set_value(&io, 1 << 0);
	delay(high_time);

	io4_set_value(&io, 0 << 0);
	delay(low_time);
}

printf("Press key to exit\n");
getchar();
ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally
}

 

I can achieve a somewhat stable PWM signal with up to 100Hz with this. If I go any higher then the duty cycle isn't stable anymore and starts to jump between 10% and 40% for this example.

 

So this approach is limited by the 1000 messages per second USB can transfer to the Brick and the scheduling of the operating system. In contrast the Servo Brick can generate much more stable PWM signals with much higher frequencies because all the timing is done on the Servo Brick and is not affected by USB or the operating system of the controlling PC.

 

Depending on your requirements on frequency and stability of the PWM signal you might be able to use one of the I/O Bricklets. If your PWM frequency should be below 100Hz and doesn't have to be that stable it might work out. Otherwise I still suggest a Servo Brick, even if it's a little bit expensive if you just use it as a single channel PWM generator :)

Link to comment
Share on other sites

Hi,

 

Thanks for your detailed answer, it is very helpful.

 

 

Regarding the PWM frequency, it sounds that the max is 500 Hz ?

 

The Servo Brick can generate PWM frequencies up to 1MHz. Why do you think it's 500Hz, were did you get that information?

 

 

Well, I have probably miss interpreted the C API then:

int servo_set_period(Servo *servo, uint8_t servo_num, uint16_t period)

    Sets the period of the specified servo in µs.

    .....
    The minimum possible period is 2000µs and the maximum is 65535µs.

 

The minimum period seems to be of 2 ms if I'm correct and not 1us ?

 

I don't think that going the USB is an option for me so it sounds

that I will have to use a Servo Brick. At least this will provide

two more bricklets ports.

 

I have one additional question for you if you don't mind:

- wouldn't it be possible to modify a master brick firmware

to run exactly the same sequence of code for turning on/off

the port of an I/O bricklet ?

Thanks.

Link to comment
Share on other sites

Ah, the documentation of the Servo Brick is outdated in that point, sorry. The minimum limit used to be 2000µs, but it was lowered to 1µs quite a while ago. Seems that we missed to update the documentation about this. I fixed this now, thanks for finding this one.

 

About modifying the firmware: You can certainly modify the firmware to bit-bang a PWM signal on any pin of an I/O Bricklet. But that's no that easy to do, because things like this don't match well with the internal task scheduling of the Bricks. In this system you cannot have an endless loop that just sits there and generates a PWM signal, assuming you want the rest of the system to work as before, such as other Bricklets on the same Brick, stack and USB communication etc.

 

In contrast the Servo Brick is designed for this and uses dedicated hardware units for PWM signal generation. That allows to integrate the signal generation nicely with the task scheduling system.

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...