Merge pull request #68 from lancaster-university/updating-dynamic-pwm
DynamicPwm behaviour modifications, and added a new Servo API to MicroBitPin
This commit is contained in:
commit
c568dd7cf0
5 changed files with 504 additions and 191 deletions
110
inc/DynamicPwm.h
110
inc/DynamicPwm.h
|
@ -4,7 +4,7 @@
|
|||
#define MICROBIT_DYNAMIC_PWM_H
|
||||
|
||||
#define NO_PWMS 3
|
||||
#define MICROBIT_DISPLAY_PWM_PERIOD 1000
|
||||
#define MICROBIT_DEFAULT_PWM_PERIOD 20000
|
||||
|
||||
enum PwmPersistence
|
||||
{
|
||||
|
@ -15,28 +15,30 @@ enum PwmPersistence
|
|||
/**
|
||||
* Class definition for DynamicPwm.
|
||||
*
|
||||
* This class addresses a few issues found in the underlying libraries.
|
||||
* This class addresses a few issues found in the underlying libraries.
|
||||
* This provides the ability for a neat, clean swap between PWM channels.
|
||||
*/
|
||||
class DynamicPwm : public PwmOut
|
||||
{
|
||||
private:
|
||||
private:
|
||||
static DynamicPwm* pwms[NO_PWMS];
|
||||
static uint8_t lastUsed;
|
||||
static uint16_t sharedPeriod;
|
||||
uint8_t flags;
|
||||
|
||||
|
||||
float lastValue;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An internal constructor used when allocating a new DynamicPwm representation
|
||||
* @param pin the name of the pin for the pwm to target
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
|
||||
* @param period the frequency of the pwm channel in us.
|
||||
*/
|
||||
DynamicPwm(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT, int period = MICROBIT_DISPLAY_PWM_PERIOD);
|
||||
|
||||
public:
|
||||
|
||||
DynamicPwm(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Redirects the pwm channel to point at a different pin.
|
||||
* @param pin the new pin to direct PWM at.
|
||||
|
@ -48,12 +50,12 @@ class DynamicPwm : public PwmOut
|
|||
* @endcode
|
||||
*/
|
||||
void redirect(PinName pin);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a pointer to the first available free pwm channel - or the first one that can be reallocated.
|
||||
* @param pin the name of the pin for the pwm to target
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
|
||||
* @param period the frequency of the pwm channel in us.
|
||||
*
|
||||
|
@ -62,8 +64,8 @@ class DynamicPwm : public PwmOut
|
|||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* @endcode
|
||||
*/
|
||||
static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT, int period = MICROBIT_DISPLAY_PWM_PERIOD);
|
||||
|
||||
static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
|
||||
|
||||
/**
|
||||
* Frees this DynamicPwm instance if the pointer is valid.
|
||||
*
|
||||
|
@ -74,31 +76,95 @@ class DynamicPwm : public PwmOut
|
|||
* @endcode
|
||||
*/
|
||||
void release();
|
||||
|
||||
|
||||
/**
|
||||
* A lightweight wrapper around the super class' write in order to capture the value
|
||||
*
|
||||
* @param value the duty cycle percentage in floating point format.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate();
|
||||
* pwm->write(0.5);
|
||||
* @endcode
|
||||
*/
|
||||
int write(float value);
|
||||
|
||||
/**
|
||||
* Retreives the pin name associated with this DynamicPwm instance.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPinName(); // equal to n
|
||||
* pwm->getPinName();
|
||||
* @endcode
|
||||
*/
|
||||
PinName getPinName();
|
||||
|
||||
|
||||
/**
|
||||
* Retreives the last value that has been written to this pwm channel.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int getValue();
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module in microseconds.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int getPeriodUs();
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module in milliseconds.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int getPeriod();
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in microseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriodUs(1000); // period now is 1ms
|
||||
* @endcode
|
||||
*
|
||||
* @note The display uses the pwm module, if you change this value the display may flicker.
|
||||
*/
|
||||
void setPeriodUs(int period);
|
||||
|
||||
int setPeriodUs(int period);
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in milliseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriod(1); // period now is 1ms
|
||||
* @endcode
|
||||
*/
|
||||
int setPeriod(int period);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,40 +3,44 @@
|
|||
|
||||
#include "mbed.h"
|
||||
#include "MicroBitComponent.h"
|
||||
// Status Field flags...
|
||||
#define IO_STATUS_DIGITAL_IN 0x01 // Pin is configured as a digital input, with no pull up.
|
||||
#define IO_STATUS_DIGITAL_OUT 0x02 // Pin is configured as a digital output
|
||||
#define IO_STATUS_ANALOG_IN 0x04 // Pin is Analog in
|
||||
#define IO_STATUS_ANALOG_OUT 0x08 // Pin is Analog out (not currently possible)
|
||||
#define IO_STATUS_TOUCH_IN 0x10 // Pin is a makey-makey style touch sensor
|
||||
#define IO_STATUS_EVENTBUS_ENABLED 0x80 // Pin is will generate events on change
|
||||
// Status Field flags...
|
||||
#define IO_STATUS_DIGITAL_IN 0x01 // Pin is configured as a digital input, with no pull up.
|
||||
#define IO_STATUS_DIGITAL_OUT 0x02 // Pin is configured as a digital output
|
||||
#define IO_STATUS_ANALOG_IN 0x04 // Pin is Analog in
|
||||
#define IO_STATUS_ANALOG_OUT 0x08 // Pin is Analog out
|
||||
#define IO_STATUS_TOUCH_IN 0x10 // Pin is a makey-makey style touch sensor
|
||||
#define IO_STATUS_EVENTBUS_ENABLED 0x80 // Pin is will generate events on change
|
||||
|
||||
//#defines for each edge connector pin
|
||||
#define MICROBIT_PIN_P0 P0_3 //P0 is the left most pad (ANALOG/DIGITAL) used to be P0_3 on green board
|
||||
#define MICROBIT_PIN_P1 P0_2 //P1 is the middle pad (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P2 P0_1 //P2 is the right most pad (ANALOG/DIGITAL) used to be P0_1 on green board
|
||||
#define MICROBIT_PIN_P3 P0_4 //COL1 (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P4 P0_17 //BTN_A
|
||||
#define MICROBIT_PIN_P5 P0_5 //COL2 (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P6 P0_12 //COL9
|
||||
#define MICROBIT_PIN_P7 P0_11 //COL8
|
||||
#define MICROBIT_PIN_P8 P0_18 //PIN 18
|
||||
#define MICROBIT_PIN_P9 P0_10 //COL7
|
||||
#define MICROBIT_PIN_P10 P0_6 //COL3 (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P11 P0_26 //BTN_B
|
||||
#define MICROBIT_PIN_P12 P0_20 //PIN 20
|
||||
#define MICROBIT_PIN_P13 P0_23 //SCK
|
||||
#define MICROBIT_PIN_P14 P0_22 //MISO
|
||||
#define MICROBIT_PIN_P15 P0_21 //MOSI
|
||||
#define MICROBIT_PIN_P16 P0_16 //PIN 16
|
||||
#define MICROBIT_PIN_P19 P0_0 //SCL
|
||||
#define MICROBIT_PIN_P20 P0_30 //SDA
|
||||
#define MICROBIT_PIN_P0 P0_3 //P0 is the left most pad (ANALOG/DIGITAL) used to be P0_3 on green board
|
||||
#define MICROBIT_PIN_P1 P0_2 //P1 is the middle pad (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P2 P0_1 //P2 is the right most pad (ANALOG/DIGITAL) used to be P0_1 on green board
|
||||
#define MICROBIT_PIN_P3 P0_4 //COL1 (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P4 P0_17 //BTN_A
|
||||
#define MICROBIT_PIN_P5 P0_5 //COL2 (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P6 P0_12 //COL9
|
||||
#define MICROBIT_PIN_P7 P0_11 //COL8
|
||||
#define MICROBIT_PIN_P8 P0_18 //PIN 18
|
||||
#define MICROBIT_PIN_P9 P0_10 //COL7
|
||||
#define MICROBIT_PIN_P10 P0_6 //COL3 (ANALOG/DIGITAL)
|
||||
#define MICROBIT_PIN_P11 P0_26 //BTN_B
|
||||
#define MICROBIT_PIN_P12 P0_20 //PIN 20
|
||||
#define MICROBIT_PIN_P13 P0_23 //SCK
|
||||
#define MICROBIT_PIN_P14 P0_22 //MISO
|
||||
#define MICROBIT_PIN_P15 P0_21 //MOSI
|
||||
#define MICROBIT_PIN_P16 P0_16 //PIN 16
|
||||
#define MICROBIT_PIN_P19 P0_0 //SCL
|
||||
#define MICROBIT_PIN_P20 P0_30 //SDA
|
||||
|
||||
#define MICROBIT_PIN_MAX_OUTPUT 1023
|
||||
#define MICROBIT_PIN_MAX_OUTPUT 1023
|
||||
|
||||
#define MICROBIT_PIN_MAX_SERVO_RANGE 180
|
||||
#define MICROBIT_PIN_DEFAULT_SERVO_RANGE 1000
|
||||
#define MICROBIT_PIN_DEFAULT_SERVO_CENTER MICROBIT_PIN_DEFAULT_SERVO_RANGE + MICROBIT_PIN_DEFAULT_SERVO_RANGE/2
|
||||
|
||||
|
||||
/**
|
||||
* Pin capabilities enum.
|
||||
* Pin capabilities enum.
|
||||
* Used to determine the capabilities of each Pin as some can only be digital, or can be both digital and analogue.
|
||||
*/
|
||||
enum PinCapability{
|
||||
|
@ -45,7 +49,7 @@ enum PinCapability{
|
|||
PIN_CAPABILITY_TOUCH = 0x04,
|
||||
PIN_CAPABILITY_AD = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG,
|
||||
PIN_CAPABILITY_ALL = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG | PIN_CAPABILITY_TOUCH
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -56,56 +60,62 @@ enum PinCapability{
|
|||
class MicroBitPin : public MicroBitComponent
|
||||
{
|
||||
/**
|
||||
* Unique, enumerated ID for this component.
|
||||
* Unique, enumerated ID for this component.
|
||||
* Used to track asynchronous events in the event bus.
|
||||
*/
|
||||
|
||||
|
||||
void *pin; // The mBed object looking after this pin at any point in time (may change!).
|
||||
PinCapability capability;
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect any attached mBed IO from this pin.
|
||||
* Used only when pin changes mode (i.e. Input/Output/Analog/Digital)
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
|
||||
/**
|
||||
* Performs a check to ensure that the current Pin is in control of a
|
||||
* DynamicPwm instance, and if it's not, allocates a new DynamicPwm instance.
|
||||
*/
|
||||
int obtainAnalogChannel();
|
||||
|
||||
public:
|
||||
PinName name; // mBed pin name of this pin.
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructor.
|
||||
* Create a Button representation with the given ID.
|
||||
* @param id the ID of the new Pin object.
|
||||
* @param name the pin name for this MicroBitPin instance to represent
|
||||
* @param capability the capability of this pin.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitPin(int id, PinName name, PinCapability capability);
|
||||
|
||||
|
||||
/**
|
||||
* Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'.
|
||||
* @param value 0 (LO) or 1 (HI)
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have digital capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.setDigitalValue(1); // P0 is now HI
|
||||
* @endcode
|
||||
*/
|
||||
int setDigitalValue(int value);
|
||||
|
||||
|
||||
/**
|
||||
* Configures this IO pin as a digital input (if necessary) and tests its current value.
|
||||
* @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.getDigitalValue(); // P0 is either 0 or 1;
|
||||
* @endcode
|
||||
|
@ -120,13 +130,28 @@ class MicroBitPin : public MicroBitComponent
|
|||
*/
|
||||
int setAnalogValue(int value);
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms,
|
||||
* and sets the duty cycle between 0.05 and 0.1 (i.e. 5% or 10%) based on the value given to this method.
|
||||
*
|
||||
* A value of 180 sets the duty cycle to be 10%, and a value of 0 sets the duty cycle to be 5% by default.
|
||||
*
|
||||
* This range can be modified to fine tune, and also tolerate different servos.
|
||||
*
|
||||
* @param value the level to set on the output pin, in the range 0 - 180
|
||||
* @param range which gives the span of possible values the i.e. lower and upper bounds center ± range/2 (Defaults to: MICROBIT_PIN_DEFAULT_SERVO_RANGE)
|
||||
* @param center the center point from which to calculate the lower and upper bounds (Defaults to: MICROBIT_PIN_DEFAULT_SERVO_CENTER)
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
int setServoValue(int value, int range = MICROBIT_PIN_DEFAULT_SERVO_RANGE, int center = MICROBIT_PIN_DEFAULT_SERVO_CENTER);
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analogue input (if necessary and possible).
|
||||
* @return the current analogue level on the pin, in the range 0 - 1024, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024
|
||||
* @endcode
|
||||
|
@ -160,35 +185,61 @@ class MicroBitPin : public MicroBitComponent
|
|||
/**
|
||||
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
|
||||
* @return 1 if pin is touched, 0 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL);
|
||||
* if(P0.isTouched())
|
||||
* {
|
||||
* uBit.display.clear();
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
int isTouched();
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms,
|
||||
* and sets the pulse width, based on the value it is given
|
||||
*
|
||||
* @param pulseWidth the desired pulse width in microseconds.
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
int setServoPulseUs(int pulseWidth);
|
||||
|
||||
/**
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
*
|
||||
* @param period The new period for the analog output in milliseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
*/
|
||||
int setAnalogPeriod(int period);
|
||||
|
||||
/**
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
*
|
||||
* @param period The new period for the analog output in microseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
*/
|
||||
int setAnalogPeriodUs(int period);
|
||||
|
||||
/**
|
||||
* Retrieves the PWM period of the analog output.
|
||||
*
|
||||
* @return the period on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
int getAnalogPeriodUs();
|
||||
|
||||
/**
|
||||
* Retrieves the PWM period of the analog output.
|
||||
*
|
||||
* @return the period on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
int getAnalogPeriod();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,8 @@ DynamicPwm* DynamicPwm::pwms[NO_PWMS] = { NULL };
|
|||
|
||||
uint8_t DynamicPwm::lastUsed = NO_PWMS+1; //set it to out of range i.e. 4 so we know it hasn't been used yet.
|
||||
|
||||
uint16_t DynamicPwm::sharedPeriod = 0; //set the shared period to an unknown state
|
||||
|
||||
/**
|
||||
* Reassigns an already operational PWM channel to the given pin
|
||||
* #HACK #BODGE # YUCK #MBED_SHOULD_DO_THIS
|
||||
|
@ -11,9 +13,9 @@ uint8_t DynamicPwm::lastUsed = NO_PWMS+1; //set it to out of range i.e. 4 so we
|
|||
* @param pin The pin to start running PWM on
|
||||
* @param oldPin The pin to stop running PWM on
|
||||
* @param channel_number The GPIOTE channel being used to drive this PWM channel
|
||||
*/
|
||||
*/
|
||||
void gpiote_reinit(PinName pin, PinName oldPin, uint8_t channel_number)
|
||||
{
|
||||
{
|
||||
// Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as an output.
|
||||
NRF_GPIO->PIN_CNF[pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
|
||||
| (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
|
||||
|
@ -37,21 +39,20 @@ void gpiote_reinit(PinName pin, PinName oldPin, uint8_t channel_number)
|
|||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
|
||||
NRF_TIMER2->CC[channel_number] = 0;
|
||||
|
||||
NRF_TIMER2->CC[channel_number] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal constructor used when allocating a new DynamicPwm representation
|
||||
* @param pin the name of the pin for the pwm to target
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
|
||||
* @param period the frequency of the pwm channel in us.
|
||||
*/
|
||||
DynamicPwm::DynamicPwm(PinName pin, PwmPersistence persistence, int period) : PwmOut(pin)
|
||||
DynamicPwm::DynamicPwm(PinName pin, PwmPersistence persistence) : PwmOut(pin)
|
||||
{
|
||||
this->flags = persistence;
|
||||
this->setPeriodUs(period);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,24 +66,23 @@ DynamicPwm::DynamicPwm(PinName pin, PwmPersistence persistence, int period) : Pw
|
|||
* @endcode
|
||||
*/
|
||||
void DynamicPwm::redirect(PinName pin)
|
||||
{
|
||||
gpiote_reinit(pin, _pwm.pin, (uint8_t)_pwm.pwm);
|
||||
{
|
||||
gpiote_reinit(pin, _pwm.pin, (uint8_t)_pwm.pwm);
|
||||
this->_pwm.pin = pin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a pointer to the first available free pwm channel - or the first one that can be reallocated.
|
||||
* @param pin the name of the pin for the pwm to target
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
|
||||
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
|
||||
* @param period the frequency of the pwm channel in us.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* @endcode
|
||||
*/
|
||||
DynamicPwm* DynamicPwm::allocate(PinName pin, PwmPersistence persistence, int period)
|
||||
DynamicPwm* DynamicPwm::allocate(PinName pin, PwmPersistence persistence)
|
||||
{
|
||||
//try to find a blank spot first
|
||||
for(int i = 0; i < NO_PWMS; i++)
|
||||
|
@ -90,31 +90,35 @@ DynamicPwm* DynamicPwm::allocate(PinName pin, PwmPersistence persistence, int pe
|
|||
if(pwms[i] == NULL)
|
||||
{
|
||||
lastUsed = i;
|
||||
pwms[i] = new DynamicPwm(pin, persistence, period);
|
||||
pwms[i] = new DynamicPwm(pin, persistence);
|
||||
return pwms[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//no blank spot.. try to find a transient PWM
|
||||
for(int i = 0; i < NO_PWMS; i++)
|
||||
int channelIterator = (lastUsed + 1 > NO_PWMS - 1) ? 0 : lastUsed + 1;
|
||||
|
||||
while(channelIterator != lastUsed)
|
||||
{
|
||||
if(pwms[i]->flags & PWM_PERSISTENCE_TRANSIENT && i != lastUsed)
|
||||
if(pwms[channelIterator]->flags & PWM_PERSISTENCE_TRANSIENT)
|
||||
{
|
||||
lastUsed = i;
|
||||
pwms[i]->flags = persistence;
|
||||
pwms[i]->redirect(pin);
|
||||
return pwms[i];
|
||||
}
|
||||
lastUsed = channelIterator;
|
||||
pwms[channelIterator]->flags = persistence;
|
||||
pwms[channelIterator]->redirect(pin);
|
||||
return pwms[channelIterator];
|
||||
}
|
||||
|
||||
channelIterator = (channelIterator + 1 > NO_PWMS - 1) ? 0 : channelIterator + 1;
|
||||
}
|
||||
|
||||
|
||||
//if we haven't found a free one, we must try to allocate the last used...
|
||||
if(pwms[lastUsed]->flags & PWM_PERSISTENCE_TRANSIENT)
|
||||
{
|
||||
pwms[lastUsed]->flags = persistence;
|
||||
pwms[lastUsed]->redirect(pin);
|
||||
return pwms[lastUsed];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//well if we have no transient channels - we can't give any away! :( return null
|
||||
return (DynamicPwm*)NULL;
|
||||
}
|
||||
|
@ -132,9 +136,9 @@ void DynamicPwm::release()
|
|||
{
|
||||
//free the pwm instance.
|
||||
NRF_GPIOTE->CONFIG[(uint8_t) _pwm.pwm] = 0;
|
||||
pwmout_free(&_pwm);
|
||||
pwmout_free(&_pwm);
|
||||
this->flags = PWM_PERSISTENCE_TRANSIENT;
|
||||
|
||||
|
||||
//set the pointer to this object to null...
|
||||
for(int i =0; i < NO_PWMS; i++)
|
||||
if(pwms[i] == this)
|
||||
|
@ -144,6 +148,30 @@ void DynamicPwm::release()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A lightweight wrapper around the super class' write in order to capture the value
|
||||
*
|
||||
* @param value the duty cycle percentage in floating point format.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate();
|
||||
* pwm->write(0.5);
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::write(float value){
|
||||
|
||||
if(value < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
PwmOut::write(value);
|
||||
lastValue = value;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the pin name associated with this DynamicPwm instance.
|
||||
*
|
||||
|
@ -155,21 +183,92 @@ void DynamicPwm::release()
|
|||
*/
|
||||
PinName DynamicPwm::getPinName()
|
||||
{
|
||||
return _pwm.pin;
|
||||
return _pwm.pin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the last value that has been written to this DynamicPwm instance.
|
||||
* The value is in the range 0-1024
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getValue();
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::getValue()
|
||||
{
|
||||
return (float)lastValue * float(MICROBIT_PIN_MAX_OUTPUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::getPeriodUs()
|
||||
{
|
||||
return sharedPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives the current period in use by the entire PWM module
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->getPeriod();
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::getPeriod()
|
||||
{
|
||||
return getPeriodUs() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in microseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriodUs(1000); // period now is 1ms
|
||||
* @endcode
|
||||
*
|
||||
* @note The display uses the pwm module, if you change this value the display may flicker.
|
||||
*/
|
||||
void DynamicPwm::setPeriodUs(int period)
|
||||
int DynamicPwm::setPeriodUs(int period)
|
||||
{
|
||||
if(period < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
//#HACK this forces mbed to update the pulse width calculation.
|
||||
period_us(period);
|
||||
write(lastValue);
|
||||
sharedPeriod = period;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
|
||||
*
|
||||
* @param period the desired period in microseconds.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
|
||||
* pwm->setPeriod(1); // period now is 1ms
|
||||
* @endcode
|
||||
*/
|
||||
int DynamicPwm::setPeriod(int period)
|
||||
{
|
||||
return setPeriodUs(period * 1000);
|
||||
}
|
||||
|
|
|
@ -2,29 +2,29 @@
|
|||
#include "MicroBitPin.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructor.
|
||||
* Create a Button representation with the given ID.
|
||||
* @param id the ID of the new Pin object.
|
||||
* @param name the pin name for this MicroBitPin instance to represent
|
||||
* @param capability the capability of this pin, can it only be digital? can it only be analog? can it be both?
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitPin::MicroBitPin(int id, PinName name, PinCapability capability)
|
||||
{
|
||||
//set mandatory attributes
|
||||
MicroBitPin::MicroBitPin(int id, PinName name, PinCapability capability)
|
||||
{
|
||||
//set mandatory attributes
|
||||
this->id = id;
|
||||
this->name = name;
|
||||
this->capability = capability;
|
||||
|
||||
|
||||
// Power up in a disconnected, low power state.
|
||||
// If we're unused, this is how it will stay...
|
||||
this->status = 0x00;
|
||||
this->pin = NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,16 +45,16 @@ void MicroBitPin::disconnect()
|
|||
NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled; // forcibly disable the ADC - BUG in mbed....
|
||||
delete ((AnalogIn *)pin);
|
||||
}
|
||||
|
||||
|
||||
if (status & IO_STATUS_ANALOG_OUT)
|
||||
{
|
||||
if(((DynamicPwm *)pin)->getPinName() == name)
|
||||
((DynamicPwm *)pin)->release();
|
||||
}
|
||||
((DynamicPwm *)pin)->release();
|
||||
}
|
||||
|
||||
if (status & IO_STATUS_TOUCH_IN)
|
||||
delete ((MicroBitButton *)pin);
|
||||
|
||||
|
||||
this->pin = NULL;
|
||||
this->status = status & IO_STATUS_EVENTBUS_ENABLED; //retain event bus status
|
||||
}
|
||||
|
@ -62,9 +62,9 @@ void MicroBitPin::disconnect()
|
|||
/**
|
||||
* Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'.
|
||||
* @param value 0 (LO) or 1 (HI)
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.setDigitalValue(1); // P0 is now HI
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
|
@ -80,14 +80,14 @@ int MicroBitPin::setDigitalValue(int value)
|
|||
// Ensure we have a valid value.
|
||||
if (value < 0 || value > 1)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
|
||||
// Move into a Digital input state if necessary.
|
||||
if (!(status & IO_STATUS_DIGITAL_OUT)){
|
||||
disconnect();
|
||||
disconnect();
|
||||
pin = new DigitalOut(name);
|
||||
status |= IO_STATUS_DIGITAL_OUT;
|
||||
}
|
||||
|
||||
|
||||
// Write the value.
|
||||
((DigitalOut *)pin)->write(value);
|
||||
|
||||
|
@ -97,9 +97,9 @@ int MicroBitPin::setDigitalValue(int value)
|
|||
/**
|
||||
* Configures this IO pin as a digital input (if necessary) and tests its current value.
|
||||
* @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.getDigitalValue(); // P0 is either 0 or 1;
|
||||
* @endcode
|
||||
|
@ -109,20 +109,32 @@ int MicroBitPin::getDigitalValue()
|
|||
//check if this pin has a digital mode...
|
||||
if(!(PIN_CAPABILITY_DIGITAL & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
|
||||
// Move into a Digital input state if necessary.
|
||||
if (!(status & IO_STATUS_DIGITAL_IN)){
|
||||
disconnect();
|
||||
pin = new DigitalIn(name,PullDown);
|
||||
disconnect();
|
||||
pin = new DigitalIn(name,PullDown);
|
||||
status |= IO_STATUS_DIGITAL_IN;
|
||||
}
|
||||
|
||||
|
||||
return ((DigitalIn *)pin)->read();
|
||||
}
|
||||
|
||||
int MicroBitPin::obtainAnalogChannel()
|
||||
{
|
||||
// Move into an analogue input state if necessary, if we are no longer the focus of a DynamicPWM instance, allocate ourselves again!
|
||||
if (!(status & IO_STATUS_ANALOG_OUT) || !(((DynamicPwm *)pin)->getPinName() == name)){
|
||||
disconnect();
|
||||
pin = (void *)DynamicPwm::allocate(name);
|
||||
status |= IO_STATUS_ANALOG_OUT;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output, and change the output value to the given level.
|
||||
* @param value the level to set on the output pin, in the range 0 - 1024
|
||||
* @param value the level to set on the output pin, in the range 0 - 1023
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
|
@ -131,34 +143,65 @@ int MicroBitPin::setAnalogValue(int value)
|
|||
//check if this pin has an analogue mode...
|
||||
if(!(PIN_CAPABILITY_ANALOG & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
//sanitise the brightness level
|
||||
|
||||
//sanitise the level value
|
||||
if(value < 0 || value > MICROBIT_PIN_MAX_OUTPUT)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
|
||||
float level = (float)value / float(MICROBIT_PIN_MAX_OUTPUT);
|
||||
|
||||
// Move into an analogue input state if necessary, if we are no longer the focus of a DynamicPWM instance, allocate ourselves again!
|
||||
if (!(status & IO_STATUS_ANALOG_OUT) || !(((DynamicPwm *)pin)->getPinName() == name)){
|
||||
disconnect();
|
||||
pin = (void *)DynamicPwm::allocate(name);
|
||||
status |= IO_STATUS_ANALOG_OUT;
|
||||
}
|
||||
|
||||
//perform a write with an extra check! :)
|
||||
if(((DynamicPwm *)pin)->getPinName() == name)
|
||||
((DynamicPwm *)pin)->write(level);
|
||||
|
||||
//obtain use of the DynamicPwm instance, if it has changed / configure if we do not have one
|
||||
if(obtainAnalogChannel() == MICROBIT_OK)
|
||||
return ((DynamicPwm *)pin)->write(level);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms,
|
||||
* and sets the duty cycle between 0.05 and 0.1 (i.e. 5% or 10%) based on the value given to this method.
|
||||
*
|
||||
* A value of 180 sets the duty cycle to be 10%, and a value of 0 sets the duty cycle to be 5% by default.
|
||||
*
|
||||
* This range can be modified to fine tune, and also tolerate different servos.
|
||||
*
|
||||
* @param value the level to set on the output pin, in the range 0 - 180
|
||||
* @param range which gives the span of possible values the i.e. lower and upper bounds center ± range/2 (Defaults to: MICROBIT_PIN_DEFAULT_SERVO_RANGE)
|
||||
* @param center the center point from which to calculate the lower and upper bounds (Defaults to: MICROBIT_PIN_DEFAULT_SERVO_CENTER)
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
int MicroBitPin::setServoValue(int value, int range, int center)
|
||||
{
|
||||
//check if this pin has an analogue mode...
|
||||
if(!(PIN_CAPABILITY_ANALOG & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
//sanitise the servo level
|
||||
if(value < 0 || range < 1 || center < 1)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
//clip - just in case
|
||||
if(value > MICROBIT_PIN_MAX_SERVO_RANGE)
|
||||
value = MICROBIT_PIN_MAX_SERVO_RANGE;
|
||||
|
||||
//calculate the lower bound based on the midpoint
|
||||
int lower = (center - (range / 2)) * 1000;
|
||||
|
||||
value = value * 1000;
|
||||
|
||||
//add the percentage of the range based on the value between 0 and 180
|
||||
int scaled = lower + (range * (value / MICROBIT_PIN_MAX_SERVO_RANGE));
|
||||
|
||||
return setServoPulseUs(scaled / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analogue input (if necessary and possible).
|
||||
* @return the current analogue level on the pin, in the range 0 - 1024, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024
|
||||
* @endcode
|
||||
|
@ -168,14 +211,14 @@ int MicroBitPin::getAnalogValue()
|
|||
//check if this pin has an analogue mode...
|
||||
if(!(PIN_CAPABILITY_ANALOG & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
|
||||
// Move into an analogue input state if necessary.
|
||||
if (!(status & IO_STATUS_ANALOG_IN)){
|
||||
disconnect();
|
||||
disconnect();
|
||||
pin = new AnalogIn(name);
|
||||
status |= IO_STATUS_ANALOG_IN;
|
||||
}
|
||||
|
||||
|
||||
//perform a read!
|
||||
return ((AnalogIn *)pin)->read_u16();
|
||||
}
|
||||
|
@ -219,14 +262,14 @@ int MicroBitPin::isAnalog()
|
|||
/**
|
||||
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
|
||||
* @return 1 if pin is touched, 0 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL);
|
||||
* if(P0.isTouched())
|
||||
* {
|
||||
* uBit.display.clear();
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitPin::isTouched()
|
||||
|
@ -234,22 +277,53 @@ int MicroBitPin::isTouched()
|
|||
//check if this pin has a touch mode...
|
||||
if(!(PIN_CAPABILITY_TOUCH & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
|
||||
// Move into a touch input state if necessary.
|
||||
if (!(status & IO_STATUS_TOUCH_IN)){
|
||||
disconnect();
|
||||
pin = new MicroBitButton(id, name);
|
||||
disconnect();
|
||||
pin = new MicroBitButton(id, name);
|
||||
status |= IO_STATUS_TOUCH_IN;
|
||||
}
|
||||
|
||||
|
||||
return ((MicroBitButton *)pin)->isPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms,
|
||||
* and sets the pulse width, based on the value it is given
|
||||
*
|
||||
* @param pulseWidth the desired pulse width in microseconds.
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
int MicroBitPin::setServoPulseUs(int pulseWidth)
|
||||
{
|
||||
//check if this pin has an analogue mode...
|
||||
if(!(PIN_CAPABILITY_ANALOG & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
//sanitise the pulse width
|
||||
if(pulseWidth < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
//Check we still have the control over the DynamicPwm instance
|
||||
if(obtainAnalogChannel() == MICROBIT_OK)
|
||||
{
|
||||
//check if the period is set to 20ms
|
||||
if(((DynamicPwm *)pin)->getPeriodUs() != MICROBIT_DEFAULT_PWM_PERIOD)
|
||||
((DynamicPwm *)pin)->setPeriodUs(MICROBIT_DEFAULT_PWM_PERIOD);
|
||||
|
||||
((DynamicPwm *)pin)->pulsewidth_us(pulseWidth);
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
*
|
||||
* @param period The new period for the analog output in microseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
int MicroBitPin::setAnalogPeriodUs(int period)
|
||||
|
@ -257,18 +331,42 @@ int MicroBitPin::setAnalogPeriodUs(int period)
|
|||
if (!(status & IO_STATUS_ANALOG_OUT))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
((DynamicPwm *)pin)->setPeriodUs(period);
|
||||
return MICROBIT_OK;
|
||||
return ((DynamicPwm *)pin)->setPeriodUs(period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
*
|
||||
* @param period The new period for the analog output in microseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
*/
|
||||
int MicroBitPin::setAnalogPeriod(int period)
|
||||
{
|
||||
return setAnalogPeriodUs(period*1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the PWM period of the analog output.
|
||||
*
|
||||
* @return the period on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
int MicroBitPin::getAnalogPeriodUs()
|
||||
{
|
||||
if (!(status & IO_STATUS_ANALOG_OUT))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
return ((DynamicPwm *)pin)->getPeriodUs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the PWM period of the analog output.
|
||||
*
|
||||
* @return the period on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
int MicroBitPin::getAnalogPeriod()
|
||||
{
|
||||
return getAnalogPeriodUs()/1000;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "ble.h"
|
||||
|
||||
/*
|
||||
/*
|
||||
* Return to our predefined compiler settings.
|
||||
*/
|
||||
#if !defined(__arm)
|
||||
|
@ -37,8 +37,8 @@ const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL;
|
|||
|
||||
/*
|
||||
* Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods.
|
||||
* So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit
|
||||
* whilst keeping the code modular.
|
||||
* So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit
|
||||
* whilst keeping the code modular.
|
||||
*/
|
||||
static MicroBitBLEManager *manager = NULL;
|
||||
|
||||
|
@ -73,15 +73,15 @@ static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructor.
|
||||
*
|
||||
* Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
|
||||
* Note that the BLE stack *cannot* be brought up in a static context.
|
||||
* (the software simply hangs or corrupts itself).
|
||||
* Hence, we bring it up in an explicit init() method, rather than in the constructor.
|
||||
*/
|
||||
MicroBitBLEManager::MicroBitBLEManager()
|
||||
{
|
||||
MicroBitBLEManager::MicroBitBLEManager()
|
||||
{
|
||||
manager = this;
|
||||
this->ble = NULL;
|
||||
this->pairingStatus = 0;
|
||||
|
@ -93,53 +93,53 @@ MicroBitBLEManager::MicroBitBLEManager()
|
|||
* this callback to restart advertising.
|
||||
*/
|
||||
void MicroBitBLEManager::onDisconnectionCallback()
|
||||
{
|
||||
{
|
||||
if(ble)
|
||||
ble->startAdvertising();
|
||||
ble->startAdvertising();
|
||||
}
|
||||
|
||||
/**
|
||||
* Post constructor initialisation method.
|
||||
* After *MUCH* pain, it's noted that the BLE stack can't be brought up in a
|
||||
* After *MUCH* pain, it's noted that the BLE stack can't be brought up in a
|
||||
* static context, so we bring it up here rather than in the constructor.
|
||||
* n.b. This method *must* be called in main() or later, not before.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* @code
|
||||
* uBit.init();
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber)
|
||||
{
|
||||
{
|
||||
ManagedString BLEName("BBC micro:bit");
|
||||
|
||||
this->deviceName = deviceName;
|
||||
|
||||
// Start the BLE stack.
|
||||
// Start the BLE stack.
|
||||
ble = new BLEDevice();
|
||||
ble->init();
|
||||
|
||||
// automatically restart advertising after a device disconnects.
|
||||
ble->onDisconnection(bleDisconnectionCallback);
|
||||
|
||||
// configure the stack to hold on to CPU during critical timing events.
|
||||
// mbed-classic performs __disabe_irq calls in its timers, which can cause MIC failures
|
||||
// on secure BLE channels.
|
||||
// configure the stack to hold on to CPU during critical timing events.
|
||||
// mbed-classic performs __disabe_irq calls in its timers, which can cause MIC failures
|
||||
// on secure BLE channels.
|
||||
ble_common_opt_radio_cpu_mutex_t opt;
|
||||
opt.enable = 1;
|
||||
sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
|
||||
sd_ble_opt_set(BLE_COMMON_OPT_RADIO_CPU_MUTEX, (const ble_opt_t *)&opt);
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_PRIVATE_ADDRESSES)
|
||||
// Configure for private addresses, so kids' behaviour can't be easily tracked.
|
||||
ble->setAddress(Gap::ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Setup our security requirements.
|
||||
ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback);
|
||||
ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback);
|
||||
ble->securityManager().init(MICROBIT_BLE_ENABLE_BONDING, MICROBIT_BLE_REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY);
|
||||
|
||||
// Bring up any configured auxiliary services.
|
||||
// Bring up any configured auxiliary services.
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE)
|
||||
new MicroBitDFUService(*ble);
|
||||
#endif
|
||||
|
@ -150,29 +150,29 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
|
|||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE)
|
||||
new MicroBitEventService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_LED_SERVICE)
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_LED_SERVICE)
|
||||
new MicroBitLEDService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE)
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE)
|
||||
new MicroBitAccelerometerService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE)
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE)
|
||||
new MicroBitMagnetometerService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE)
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE)
|
||||
new MicroBitButtonService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE)
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE)
|
||||
new MicroBitIOPinService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE)
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE)
|
||||
new MicroBitTemperatureService(*ble);
|
||||
#endif
|
||||
|
||||
|
@ -189,7 +189,7 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
|
|||
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
|
||||
ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
|
||||
ble->setAdvertisingInterval(200);
|
||||
ble->startAdvertising();
|
||||
ble->startAdvertising();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,7 +219,7 @@ void MicroBitBLEManager::pairingComplete(bool success)
|
|||
* of the micro:bit in cases where BLE is disabled during normal operation.
|
||||
*/
|
||||
void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
|
||||
{
|
||||
{
|
||||
ManagedString namePrefix("BBC micro:bit [");
|
||||
ManagedString namePostfix("]");
|
||||
ManagedString BLEName = namePrefix + deviceName + namePostfix;
|
||||
|
@ -237,7 +237,7 @@ void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
|
|||
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
|
||||
ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
|
||||
ble->setAdvertisingInterval(200);
|
||||
ble->startAdvertising();
|
||||
ble->startAdvertising();
|
||||
|
||||
// Stop any running animations on the display
|
||||
display.stopAnimation();
|
||||
|
@ -336,6 +336,5 @@ void MicroBitBLEManager::showNameHistogram(MicroBitDisplay &display)
|
|||
|
||||
for (int j=0; j<h+1; j++)
|
||||
display.image.setPixelValue(MICROBIT_DFU_HISTOGRAM_WIDTH-i-1, MICROBIT_DFU_HISTOGRAM_HEIGHT-j-1, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue