Skip to content

Commit

Permalink
[pwm] Require PWM period/pulseWidth to be set at the same time
Browse files Browse the repository at this point in the history
This is a wise API choice because you can go through invalid states
by setting the wrong one first, where the pulse width is bigger than
the period. I convinced Zephyr itself to make this change, but we
hadn't gotten around to reflecting this in our own API.

Fixes intel#359.

Signed-off-by: Geoff Gustafson <geoff@linux.intel.com>
  • Loading branch information
grgustaf committed Mar 28, 2017
1 parent 6b36b16 commit a4038e5
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 230 deletions.
60 changes: 15 additions & 45 deletions docs/pwm.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,8 @@ dictionary PWMInit {

[NoInterfaceObject]
interface PWMPin {
void setPeriod(double ms);
void setPeriodCycles(unsigned long cycles);
void setPulseWidth(double ms);
void setPulseWidthCycles(unsigned long cycles);
void setCycles(unsigned long period, unsigned long pulseWidth);
void setMilliseconds(double period, double pulseWidth);
};
```

Expand Down Expand Up @@ -89,63 +87,35 @@ the period. *NOTE: This doesn't seem to work currently on Arduino 101.*
The function returns a PWMPin object that can be used to change the period and
pulse width later.

### PWMPin.setPeriod
### PWMPin.setCycles

`void setPeriod(double ms);`
`void setCycles(unsigned long period, unsigned long pulseWidth);`

Sets the repeat period for the pulse signal. It is given in milliseconds, so
these can be fractional to provide microsecond timings, etc. The actual
resolution available will depend on the hardware, so the value you provide may
get rounded.
*TODO: We could probably have the period attribute show the actual setting for
the device when it is read back.*

This version of the API is useful when the timing of the pulse matters (e.g.
the 'servo' model of PWM control described in the
[Introduction](#introduction)).

### PWMPin.setPeriodCycles

`void setPeriodCycles(unsigned long cycles);`

Sets the repeat period for the pulse signal, in terms of hardware cycles. One
hardware cycle is the minimum amount of time the hardware supports having the
pulse signal on (high).
Sets the repeat period and pulse width for the signal, in terms of hardware
cycles. One hardware cycle is the minimum amount of time the hardware supports
having the pulse signal on (high).

This version of the API is useful when the duty cycle is what matters (e.g.
using the 'analog' model of PWM control described in the
[Introduction](#introduction)). For example, a period of 2 with a pulse width of
1 will make an LED at 50% brightness, with no flicker because the changes occur
far faster than visible to the human eye.

### PWMPin.setPulseWidth
### PWMPin.setMilliseconds

`void setPulseWidth(double ms);`
`void setMilliseconds(double periodMS, double pulseWidthMS);`

Sets the pulse width for the signal. It is given in milliseconds, so these can
be fractional to provide microsecond timings, etc. The actual resolution
available will depend on the hardware, so the value you provide may get rounded.
*TODO: We could probably have the pulseWidth attribute show the actual
setting for the device when it is read back.*
Sets the repeat period and pulse width for the signal. It is given in
milliseconds, so these can be fractional to provide microsecond timings, etc.
The actual resolution available will depend on the hardware, so the value you
provide may get rounded.
*TODO: We could probably have the period attribute show the actual setting for
the device when it is read back.*

This version of the API is useful when the timing of the pulse matters (e.g.
the 'servo' model of PWM control described in the
[Introduction](#introduction)).

### PWMPin.setPulseWidthCycles

`void setPulseWidthCycles(unsigned long cycles);`

Sets the pulse width for the signal, in terms of hardware cycles. One hardware
cycle is the minimum amount of time the hardware supports having the pulse
signal on (high).

This version of the API is useful when the duty cycle is what matters (e.g.
using the 'analog' model of PWM control described in the
[Introduction](#introduction)). For example, a period of 2 with a pulse width of
1 will make an LED at 50% brightness, with no flicker because the changes occur
far faster than visible to the human eye.

Sample Apps
-----------
* [PWM sample](../samples/PWM.js)
Expand Down
10 changes: 3 additions & 7 deletions samples/PWM.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ var pins = require("arduino101_pins");
var led0 = pwm.open({channel: pins.IO3});

// set timings in milliseconds
led0.setPeriod(1500);
led0.setPulseWidth(1000);
led0.setMilliseconds(1500, 1000);

// set brightness to 33% using hw cycle-based values
var led1 = pwm.open({channel: pins.IO5, period: 3, pulseWidth: 1});
Expand All @@ -29,8 +28,7 @@ var period = maxPeriod;
var dir = 0;

// set initial state
led2.setPeriod(period);
led2.setPulseWidth(period / 2);
led2.setMilliseconds(period, period / 2);

setInterval(function () {
if (dir) {
Expand All @@ -50,7 +48,5 @@ setInterval(function () {
}
}

led2.setPeriod(period);
led2.setPulseWidth(period / 2);

led2.setMilliseconds(period, period / 2);
}, 4000);
8 changes: 4 additions & 4 deletions samples/WebBluetoothDemo.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ColorCharacteristic._value.writeUInt8(0, 1);
ColorCharacteristic._value.writeUInt8(0, 2);

ColorCharacteristic.ledR = pwm.open({
channel: pins.IO3, period: 0.256, pulseWidth: 255 / 1000
channel: pins.IO3, period: 0.256, pulseWidth: 0.255
});
ColorCharacteristic.ledG = pwm.open({
channel: pins.IO5, period: 0.256, pulseWidth: 0
Expand Down Expand Up @@ -129,9 +129,9 @@ ColorCharacteristic.onWriteRequest = function(data, offset, withoutResponse,
return;
}

this.ledR.setPulseWidth(this._value.readUInt8(0) / 1000);
this.ledG.setPulseWidth(this._value.readUInt8(1) / 1000);
this.ledB.setPulseWidth(this._value.readUInt8(2) / 1000);
this.ledR.setCycles(256, this._value.readUInt8(0));
this.ledG.setCycles(256, this._value.readUInt8(1));
this.ledB.setCycles(256, this._value.readUInt8(2));
// TODO: probably only supposed to call this if withoutResponse is false?
callback(this.RESULT_SUCCESS);
};
Expand Down
6 changes: 2 additions & 4 deletions samples/arduino/basics/Fade.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,16 @@ var pins = require("arduino101_pins");
var led1 = pwm.open({
channel: pins.IO3
});
led1.setPeriodCycles(256);

var led2 = pwm.open({
channel: pins.IO5,
polarity: "reverse"
});
led2.setPeriodCycles(256);

// update the brightness every 30ms
setInterval(function () {
led1.setPulseWidthCycles(brightness);
led2.setPulseWidthCycles(brightness);
led1.setCycles(256, brightness);
led2.setCycles(256, brightness);

// adjust the brightness for next time
brightness += fadeAmount;
Expand Down
11 changes: 3 additions & 8 deletions samples/arduino/starterkit/ColorMixingLamp.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ var blueSensor = aio.open({
pin: pins.A2
});

// initialize the period of the PWMs to 256 hardware cycles
redLED.setPeriodCycles(256);
greenLED.setPeriodCycles(256);
blueLED.setPeriodCycles(256);

setInterval(function () {
var redValue = redSensor.read();
var greenValue = greenSensor.read();
Expand All @@ -70,9 +65,9 @@ setInterval(function () {
"\tGreen: " + greenValue +
"\tBlue: " + blueValue);

redLED.setPulseWidthCycles(redValue);
greenLED.setPulseWidthCycles(greenValue);
blueLED.setPulseWidthCycles(blueValue);
redLED.setCycles(256, redValue);
greenLED.setCycles(256, greenValue);
blueLED.setCycles(256, blueValue);

// FIXME: Currently, ZJS only reads analog pins once per second, so there's
// no point in checking more often. This should be fixed soon.
Expand Down
2 changes: 1 addition & 1 deletion src/zjs_modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ module_t zjs_modules_array[] = {
{ "grove_lcd", zjs_grove_lcd_init, zjs_grove_lcd_cleanup },
#endif
#ifdef BUILD_MODULE_PWM
{ "pwm", zjs_pwm_init },
{ "pwm", zjs_pwm_init, zjs_pwm_cleanup },
#endif
#ifdef BUILD_MODULE_I2C
{ "i2c", zjs_i2c_init },
Expand Down
Loading

0 comments on commit a4038e5

Please sign in to comment.