mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-09-03 19:32:39 +02:00
Finished implementing PWM and UART pin users
This commit is contained in:
84
Grbl_Esp32/src/PinUsers/PwmPin.cpp
Normal file
84
Grbl_Esp32/src/PinUsers/PwmPin.cpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#include "PwmPin.h"
|
||||||
|
|
||||||
|
#include "../Pin.h"
|
||||||
|
#include "../Assert.h"
|
||||||
|
#include "LimitedResource.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
namespace PinUsers {
|
||||||
|
class NativePwm : public PwmDetail {
|
||||||
|
static LimitedResource<16>& PwmChannelResources() {
|
||||||
|
// The ESP32 chip has 16 PWM channels.
|
||||||
|
|
||||||
|
static LimitedResource<16> instances_;
|
||||||
|
return instances_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pin pin_;
|
||||||
|
int pwmChannel_;
|
||||||
|
uint32_t frequency_;
|
||||||
|
uint32_t maxDuty_;
|
||||||
|
uint8_t resolutionBits_;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculate the highest precision of a PWM based on the frequency in bits
|
||||||
|
|
||||||
|
80,000,000 / freq = period
|
||||||
|
determine the highest precision where (1 << precision) < period
|
||||||
|
*/
|
||||||
|
uint8_t calculatePwmPrecision(uint32_t freq) {
|
||||||
|
uint8_t precision = 0;
|
||||||
|
|
||||||
|
// increase the precision (bits) until it exceeds allow by frequency the max or is 16
|
||||||
|
// TODO is there a named value for the 80MHz?
|
||||||
|
while ((1 << precision) < (uint32_t)(80000000 / freq) && precision <= 16) {
|
||||||
|
precision++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return precision - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
NativePwm(Pin pin, uint32_t frequency, uint32_t maxDuty) : frequency_(frequency), maxDuty_(maxDuty) {
|
||||||
|
auto native = pin.getNative(Pin::Capabilities::PWM | Pin::Capabilities::Native);
|
||||||
|
|
||||||
|
pwmChannel_ = PwmChannelResources().tryClaim();
|
||||||
|
Assert(pwmChannel_ != -1, "PWM Channel could not be claimed. Are all PWM channels in use?");
|
||||||
|
|
||||||
|
resolutionBits_ = calculatePwmPrecision(frequency);
|
||||||
|
|
||||||
|
ledcSetup(pwmChannel_, frequency, resolutionBits_);
|
||||||
|
ledcAttachPin(native, pwmChannel_);
|
||||||
|
ledcWrite(pwmChannel_, 0);
|
||||||
|
|
||||||
|
// grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "PWM Output:%d on Pin:%s Freq:%0.0fHz", _number, _pin.name().c_str(), _pwm_frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getFrequency() const override { return frequency_; }
|
||||||
|
uint32_t getMaxDuty() const override { return maxDuty_; }
|
||||||
|
|
||||||
|
void setValue(float value) {
|
||||||
|
if (value < 0) {
|
||||||
|
value = 0;
|
||||||
|
} else if (value > 1) {
|
||||||
|
value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto duty = value * (uint32_t(1) << int(resolutionBits_));
|
||||||
|
ledcWrite(pwmChannel_, uint32_t(duty));
|
||||||
|
}
|
||||||
|
|
||||||
|
~NativePwm() override {
|
||||||
|
ledcWrite(pwmChannel_, 0);
|
||||||
|
PwmChannelResources().release(pwmChannel_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PwmPin::PwmPin(Pin pin, uint32_t frequency, uint32_t maxDuty) {
|
||||||
|
Assert(pin.capabilities().has(Pin::Capabilities::PWM | Pin::Capabilities::Native), "Pin does not support PWM");
|
||||||
|
|
||||||
|
// For now, we only support Native pins. In the future, we might support other pins.
|
||||||
|
_detail = new NativePwm(pin, frequency, maxDuty);
|
||||||
|
}
|
||||||
|
}
|
36
Grbl_Esp32/src/PinUsers/PwmPin.h
Normal file
36
Grbl_Esp32/src/PinUsers/PwmPin.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Pin.h"
|
||||||
|
#include "../Assert.h"
|
||||||
|
|
||||||
|
namespace PinUsers {
|
||||||
|
class PwmDetail {
|
||||||
|
public:
|
||||||
|
virtual uint32_t getFrequency() const = 0;
|
||||||
|
virtual uint32_t getMaxDuty() const = 0;
|
||||||
|
|
||||||
|
// Sets the PWM value from 0..1.
|
||||||
|
virtual void setValue(float value) = 0;
|
||||||
|
|
||||||
|
virtual ~PwmDetail() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PwmPin {
|
||||||
|
Pin _pin;
|
||||||
|
PwmDetail* _detail;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PwmPin() : _pin(Pin::UNDEFINED), _detail(nullptr) {}
|
||||||
|
PwmPin(Pin pin, uint32_t frequency, uint32_t maxDuty);
|
||||||
|
|
||||||
|
// Returns actual frequency which might not be exactly the same as requested(nearest supported value)
|
||||||
|
inline uint32_t getFrequency() const { return _detail->getFrequency(); }
|
||||||
|
|
||||||
|
// Returns actual maxDuty which might not be exactly the same as requested(nearest supported value)
|
||||||
|
inline uint32_t getMaxDuty() const { return _detail->getMaxDuty(); }
|
||||||
|
|
||||||
|
inline void setValue(float value) const { return _detail->setValue(value); }
|
||||||
|
|
||||||
|
inline ~PwmPin() { delete _detail; }
|
||||||
|
};
|
||||||
|
}
|
@@ -4,6 +4,7 @@
|
|||||||
#include "../Pins/PinOptionsParser.h"
|
#include "../Pins/PinOptionsParser.h"
|
||||||
#include "../Assert.h"
|
#include "../Assert.h"
|
||||||
#include "LimitedResource.h"
|
#include "LimitedResource.h"
|
||||||
|
|
||||||
#include <driver/uart.h>
|
#include <driver/uart.h>
|
||||||
|
|
||||||
namespace PinUsers {
|
namespace PinUsers {
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Pin.h"
|
#include "../Pin.h"
|
||||||
#include <WString.h>
|
|
||||||
#include "../Assert.h"
|
#include "../Assert.h"
|
||||||
|
|
||||||
|
#include <WString.h>
|
||||||
|
|
||||||
// TODO FIXME: Uart also suffers from the way settings works: What you would want is 2 phases,
|
// TODO FIXME: Uart also suffers from the way settings works: What you would want is 2 phases,
|
||||||
// so (1) validation and preparation, and (2) building the actual uart. Now, it's all combined
|
// so (1) validation and preparation, and (2) building the actual uart. Now, it's all combined
|
||||||
// in the single constructor, which works, but could throw an exception.
|
// in the single constructor, which works, but could throw an exception.
|
||||||
|
Reference in New Issue
Block a user