1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-02 19:02:35 +02:00

Finished implementing PWM and UART pin users

This commit is contained in:
Stefan de Bruijn
2020-11-03 13:35:56 +01:00
parent 7d5c9a68bd
commit 0594ff5f4d
4 changed files with 123 additions and 1 deletions

View 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);
}
}

View 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; }
};
}

View File

@@ -4,6 +4,7 @@
#include "../Pins/PinOptionsParser.h"
#include "../Assert.h"
#include "LimitedResource.h"
#include <driver/uart.h>
namespace PinUsers {

View File

@@ -1,9 +1,10 @@
#pragma once
#include "../Pin.h"
#include <WString.h>
#include "../Assert.h"
#include <WString.h>
// 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
// in the single constructor, which works, but could throw an exception.