feat: 全量同步 254 个常用的 Arduino 扩展库文件
This commit is contained in:
411
arduino-libs/arduino-cli/libraries/ESP32Servo/src/ESP32PWM.cpp
Normal file
411
arduino-libs/arduino-cli/libraries/ESP32Servo/src/ESP32PWM.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* ESP32PWM.cpp
|
||||
*
|
||||
* Created on: Sep 22, 2018
|
||||
* Author: hephaestus
|
||||
*/
|
||||
|
||||
#include <ESP32PWM.h>
|
||||
#include "esp32-hal-ledc.h"
|
||||
|
||||
// initialize the class variable ServoCount
|
||||
int ESP32PWM::PWMCount = -1; // the total number of attached servos
|
||||
bool ESP32PWM::explicateAllocationMode=false;
|
||||
ESP32PWM * ESP32PWM::ChannelUsed[NUM_PWM]; // used to track whether a channel is in service
|
||||
long ESP32PWM::timerFreqSet[4] = { -1, -1, -1, -1 };
|
||||
int ESP32PWM::timerCount[4] = { 0, 0, 0, 0 };
|
||||
|
||||
static const char* TAG = "ESP32PWM";
|
||||
|
||||
// The ChannelUsed array elements are 0 if never used, 1 if in use, and -1 if used and disposed
|
||||
// (i.e., available for reuse)
|
||||
/**
|
||||
* allocateTimer
|
||||
* @param a timer number 0-3 indicating which timer to allocate in this library
|
||||
* Switch to explicate allocation mode
|
||||
*
|
||||
*/
|
||||
void ESP32PWM::allocateTimer(int timerNumber){
|
||||
if(timerNumber<0 || timerNumber>3)
|
||||
return;
|
||||
if(ESP32PWM::explicateAllocationMode==false){
|
||||
ESP32PWM::explicateAllocationMode=true;
|
||||
for(int i=0;i<4;i++)
|
||||
ESP32PWM::timerCount[i]=4;// deallocate all timers to start mode
|
||||
}
|
||||
ESP32PWM::timerCount[timerNumber]=0;
|
||||
}
|
||||
|
||||
ESP32PWM::ESP32PWM() {
|
||||
resolutionBits = 8;
|
||||
pwmChannel = -1;
|
||||
pin = -1;
|
||||
myFreq = -1;
|
||||
if (PWMCount == -1) {
|
||||
for (int i = 0; i < NUM_PWM; i++)
|
||||
ChannelUsed[i] = NULL; // load invalid data into the storage array of pin mapping
|
||||
PWMCount = PWM_BASE_INDEX; // 0th channel does not work with the PWM system
|
||||
}
|
||||
}
|
||||
|
||||
ESP32PWM::~ESP32PWM() {
|
||||
if (attached()) {
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
ledcDetach(pin);
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
#endif
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
#endif
|
||||
}
|
||||
deallocate();
|
||||
}
|
||||
|
||||
double ESP32PWM::_ledcSetupTimerFreq(uint8_t pin, double freq,
|
||||
uint8_t bit_num) {
|
||||
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
return ledcAttach(pin, freq, bit_num);
|
||||
#else
|
||||
return ledcSetup(pin, freq, bit_num);
|
||||
#endif
|
||||
#else
|
||||
return ledcSetup(pin, freq, bit_num);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int ESP32PWM::timerAndIndexToChannel(int timerNum, int index) {
|
||||
int localIndex = 0;
|
||||
for (int j = 0; j < NUM_PWM; j++) {
|
||||
if (((j / 2) % 4) == timerNum) {
|
||||
if (localIndex == index) {
|
||||
return j;
|
||||
}
|
||||
localIndex++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int ESP32PWM::allocatenext(double freq) {
|
||||
long freqlocal = (long) freq;
|
||||
if (pwmChannel < 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bool freqAllocated = ((timerFreqSet[i] == freqlocal)
|
||||
|| (timerFreqSet[i] == -1));
|
||||
if (freqAllocated && timerCount[i] < 4) {
|
||||
if (timerFreqSet[i] == -1) {
|
||||
//Serial.println("Starting timer "+String(i)+" at freq "+String(freq));
|
||||
timerFreqSet[i] = freqlocal;
|
||||
}
|
||||
//Serial.println("Free channel timer "+String(i)+" at freq "+String(freq)+" remaining "+String(4-timerCount[i]));
|
||||
|
||||
timerNum = i;
|
||||
for (int index=0; index<4; ++index)
|
||||
{
|
||||
int myTimerNumber = timerAndIndexToChannel(timerNum,index);
|
||||
if ((myTimerNumber >= 0) && (!ChannelUsed[myTimerNumber]))
|
||||
{
|
||||
pwmChannel = myTimerNumber;
|
||||
// Serial.println(
|
||||
// "PWM on ledc channel #" + String(pwmChannel)
|
||||
// + " using 'timer " + String(timerNum)
|
||||
// + "' to freq " + String(freq) + "Hz");
|
||||
ChannelUsed[pwmChannel] = this;
|
||||
timerCount[timerNum]++;
|
||||
PWMCount++;
|
||||
myFreq = freq;
|
||||
return pwmChannel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if(timerFreqSet[i]>0)
|
||||
// Serial.println("Timer freq mismatch target="+String(freq)+" on timer "+String(i)+" was "+String(timerFreqSet[i]));
|
||||
// else
|
||||
// Serial.println("Timer out of channels target="+String(freq)+" on timer "+String(i)+" was "+String(timerCount[i]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return pwmChannel;
|
||||
}
|
||||
ESP_LOGE(TAG,
|
||||
"ERROR All PWM timers allocated! Can't accomodate %d Hz\r\nHalting...", freq);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void ESP32PWM::deallocate() {
|
||||
if (pwmChannel < 0)
|
||||
return;
|
||||
ESP_LOGE(TAG, "PWM deallocating LEDc #%d",pwmChannel);
|
||||
timerCount[getTimer()]--;
|
||||
if (timerCount[getTimer()] == 0) {
|
||||
timerFreqSet[getTimer()] = -1; // last pwn closed out
|
||||
}
|
||||
timerNum = -1;
|
||||
attachedState = false;
|
||||
ChannelUsed[pwmChannel] = NULL;
|
||||
pwmChannel = -1;
|
||||
PWMCount--;
|
||||
|
||||
}
|
||||
|
||||
int ESP32PWM::getChannel() {
|
||||
if (pwmChannel < 0) {
|
||||
ESP_LOGE(TAG, "FAIL! must setup() before using get channel!");
|
||||
}
|
||||
return pwmChannel;
|
||||
}
|
||||
|
||||
double ESP32PWM::setup(double freq, uint8_t resolution_bits) {
|
||||
checkFrequencyForSideEffects(freq);
|
||||
|
||||
resolutionBits = resolution_bits;
|
||||
if (attached()) {
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
ledcDetach(pin);
|
||||
double val = ledcAttach(getPin(), freq, resolution_bits);
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
double val = ledcSetup(getChannel(), freq, resolution_bits);
|
||||
#endif
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
double val = ledcSetup(getChannel(), freq, resolution_bits);
|
||||
#endif
|
||||
|
||||
attachPin(pin);
|
||||
return val;
|
||||
}
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
return ledcAttach(getPin(), freq, resolution_bits);
|
||||
#else
|
||||
return ledcSetup(getChannel(), freq, resolution_bits);
|
||||
#endif
|
||||
#else
|
||||
return ledcSetup(getChannel(), freq, resolution_bits);
|
||||
#endif
|
||||
}
|
||||
double ESP32PWM::getDutyScaled() {
|
||||
return mapf((double) myDuty, 0, (double) ((1 << resolutionBits) - 1), 0.0,
|
||||
1.0);
|
||||
}
|
||||
void ESP32PWM::writeScaled(double duty) {
|
||||
write(mapf(duty, 0.0, 1.0, 0, (double) ((1 << resolutionBits) - 1)));
|
||||
}
|
||||
void ESP32PWM::write(uint32_t duty) {
|
||||
myDuty = duty;
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
ledcWrite(getPin(), duty);
|
||||
#else
|
||||
ledcWrite(getChannel(), duty);
|
||||
#endif
|
||||
#else
|
||||
ledcWrite(getChannel(), duty);
|
||||
#endif
|
||||
}
|
||||
void ESP32PWM::adjustFrequencyLocal(double freq, double dutyScaled) {
|
||||
timerFreqSet[getTimer()] = (long) freq;
|
||||
myFreq = freq;
|
||||
if (attached()) {
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
ledcDetach(pin);
|
||||
// Remove the PWM during frequency adjust
|
||||
_ledcSetupTimerFreq(getPin(), freq, resolutionBits);
|
||||
writeScaled(dutyScaled);
|
||||
ledcAttach(getPin(), freq, resolutionBits); // re-attach the pin after frequency adjust
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
// Remove the PWM during frequency adjust
|
||||
_ledcSetupTimerFreq(getChannel(), freq, resolutionBits);
|
||||
writeScaled(dutyScaled);
|
||||
ledcAttachPin(pin, getChannel()); // re-attach the pin after frequency adjust
|
||||
#endif
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
// Remove the PWM during frequency adjust
|
||||
_ledcSetupTimerFreq(getChannel(), freq, resolutionBits);
|
||||
writeScaled(dutyScaled);
|
||||
ledcAttachPin(pin, getChannel()); // re-attach the pin after frequency adjust
|
||||
#endif
|
||||
|
||||
} else {
|
||||
_ledcSetupTimerFreq(getPin(), freq, resolutionBits);
|
||||
writeScaled(dutyScaled);
|
||||
}
|
||||
}
|
||||
void ESP32PWM::adjustFrequency(double freq, double dutyScaled) {
|
||||
if(dutyScaled<0)
|
||||
dutyScaled=getDutyScaled();
|
||||
writeScaled(dutyScaled);
|
||||
for (int i = 0; i < timerCount[getTimer()]; i++) {
|
||||
int pwm = timerAndIndexToChannel(getTimer(), i);
|
||||
if (ChannelUsed[pwm] != NULL) {
|
||||
if (ChannelUsed[pwm]->myFreq != freq) {
|
||||
ChannelUsed[pwm]->adjustFrequencyLocal(freq,
|
||||
ChannelUsed[pwm]->getDutyScaled());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
double ESP32PWM::writeTone(double freq) {
|
||||
for (int i = 0; i < timerCount[getTimer()]; i++) {
|
||||
int pwm = timerAndIndexToChannel(getTimer(), i);
|
||||
if (ChannelUsed[pwm] != NULL) {
|
||||
if (ChannelUsed[pwm]->myFreq != freq) {
|
||||
ChannelUsed[pwm]->adjustFrequencyLocal(freq,
|
||||
ChannelUsed[pwm]->getDutyScaled());
|
||||
}
|
||||
write(1 << (resolutionBits-1)); // writeScaled(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
double ESP32PWM::writeNote(note_t note, uint8_t octave) {
|
||||
const uint16_t noteFrequencyBase[12] = {
|
||||
// C C# D Eb E F F# G G# A Bb B
|
||||
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459,
|
||||
7902 };
|
||||
|
||||
if (octave > 8 || note >= NOTE_MAX) {
|
||||
return 0;
|
||||
}
|
||||
double noteFreq = (double) noteFrequencyBase[note]
|
||||
/ (double) (1 << (8 - octave));
|
||||
return writeTone(noteFreq);
|
||||
}
|
||||
uint32_t ESP32PWM::read() {
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
return ledcRead(getPin());
|
||||
#else
|
||||
return ledcRead(getChannel());
|
||||
#endif
|
||||
#else
|
||||
return ledcRead(getChannel());
|
||||
#endif
|
||||
|
||||
}
|
||||
double ESP32PWM::readFreq() {
|
||||
return myFreq;
|
||||
}
|
||||
void ESP32PWM::attach(int p) {
|
||||
pin = p;
|
||||
attachedState = true;
|
||||
}
|
||||
void ESP32PWM::attachPin(uint8_t pin) {
|
||||
|
||||
if (hasPwm(pin)) {
|
||||
attach(pin);
|
||||
bool success=true;
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
success=ledcAttach(pin, readFreq(), resolutionBits);
|
||||
#else
|
||||
ledcAttachPin(pin, getChannel());
|
||||
#endif
|
||||
#else
|
||||
ledcAttachPin(pin, getChannel());
|
||||
#endif
|
||||
if(success)
|
||||
return;
|
||||
ESP_LOGE(TAG, "ERROR PWM channel failed to configure on!",pin);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
ESP_LOGE(TAG, "ERROR PWM channel unavailable on pin requested! %d PWM available on: 1-21,26,33-42",pin);
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
ESP_LOGE(TAG, "ERROR PWM channel unavailable on pin requested! %d PWM available on: 1-21,35-45,47-48",pin);
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
ESP_LOGE(TAG, "ERROR PWM channel unavailable on pin requested! %d PWM available on: 1-10,18-21",pin);
|
||||
#else
|
||||
ESP_LOGE(TAG, "ERROR PWM channel unavailable on pin requested! %d PWM available on: 2,4,5,12-19,21-23,25-27,32-33",pin);
|
||||
#endif
|
||||
|
||||
}
|
||||
void ESP32PWM::attachPin(uint8_t pin, double freq, uint8_t resolution_bits) {
|
||||
|
||||
if (hasPwm(pin)){
|
||||
int ret=setup(freq, resolution_bits);
|
||||
ESP_LOGW(TAG, "Pin Setup %d with code %d",pin,ret);
|
||||
}
|
||||
else
|
||||
ESP_LOGE(TAG, "ERROR Pin Failed %d ",pin);
|
||||
attachPin(pin);
|
||||
}
|
||||
void ESP32PWM::detachPin(int pin) {
|
||||
#ifdef ESP_ARDUINO_VERSION_MAJOR
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
|
||||
ledcDetach(pin);
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
#endif
|
||||
#else
|
||||
ledcDetachPin(pin);
|
||||
#endif
|
||||
deallocate();
|
||||
}
|
||||
/* Side effects of frequency changes happen because of shared timers
|
||||
*
|
||||
* LEDC Chan to Group/Channel/Timer Mapping
|
||||
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
|
||||
** ledc: 1 => Group: 0, Channel: 1, Timer: 0
|
||||
** ledc: 2 => Group: 0, Channel: 2, Timer: 1
|
||||
** ledc: 3 => Group: 0, Channel: 3, Timer: 1
|
||||
** ledc: 4 => Group: 0, Channel: 4, Timer: 2
|
||||
** ledc: 5 => Group: 0, Channel: 5, Timer: 2
|
||||
** ledc: 6 => Group: 0, Channel: 6, Timer: 3
|
||||
** ledc: 7 => Group: 0, Channel: 7, Timer: 3
|
||||
** ledc: 8 => Group: 1, Channel: 0, Timer: 0
|
||||
** ledc: 9 => Group: 1, Channel: 1, Timer: 0
|
||||
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
|
||||
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
|
||||
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
|
||||
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
|
||||
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
|
||||
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
|
||||
*/
|
||||
|
||||
bool ESP32PWM::checkFrequencyForSideEffects(double freq) {
|
||||
|
||||
allocatenext(freq);
|
||||
for (int i = 0; i < timerCount[getTimer()]; i++) {
|
||||
int pwm = timerAndIndexToChannel(getTimer(), i);
|
||||
|
||||
if (pwm == pwmChannel)
|
||||
continue;
|
||||
if (ChannelUsed[pwm] != NULL)
|
||||
if (ChannelUsed[pwm]->getTimer() == getTimer()) {
|
||||
double diff = abs(ChannelUsed[pwm]->myFreq - freq);
|
||||
if (abs(diff) > 0.1) {
|
||||
ESP_LOGW(TAG,
|
||||
"\tWARNING PWM channel %d \
|
||||
shares a timer with channel %d\n \
|
||||
\tchanging the frequency to %d \
|
||||
Hz will ALSO change channel %d \
|
||||
\n\tfrom its previous frequency of %d Hz\n "
|
||||
,pwmChannel, pwm, freq,pwm, ChannelUsed[pwm]->myFreq);
|
||||
ChannelUsed[pwm]->myFreq = freq;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ESP32PWM* pwmFactory(int pin) {
|
||||
for (int i = 0; i < NUM_PWM; i++)
|
||||
if (ESP32PWM::ChannelUsed[i] != NULL) {
|
||||
if (ESP32PWM::ChannelUsed[i]->getPin() == pin)
|
||||
return ESP32PWM::ChannelUsed[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user