#include "PwmPin.h" /////////////////// LedC::LedC(uint8_t pin, uint16_t freq){ if(freq==0) freq=DEFAULT_PWM_FREQ; for(int nMode=0;nModespeed_mode=(ledc_mode_t)nMode; timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; timerList[nTimer][nMode]->freq_hz=freq; int res=20; // find the maximum possible resolution while(getApbFrequency()/(freq*pow(2,res))<1) res--; timerList[nTimer][nMode]->duty_resolution=(ledc_timer_bit_t)res; ledc_timer_config(timerList[nTimer][nMode]); } if(timerList[nTimer][nMode]->freq_hz==freq){ // if timer matches desired frequency (always true if newly-created above) channelList[nChannel][nMode]=new ledc_channel_config_t; // create new channel instance channelList[nChannel][nMode]->speed_mode=(ledc_mode_t)nMode; channelList[nChannel][nMode]->channel=(ledc_channel_t)nChannel; channelList[nChannel][nMode]->timer_sel=(ledc_timer_t)nTimer; channelList[nChannel][nMode]->intr_type=LEDC_INTR_DISABLE; channelList[nChannel][nMode]->hpoint=0; channelList[nChannel][nMode]->gpio_num=pin; timer=timerList[nTimer][nMode]; channel=channelList[nChannel][nMode]; return; } } } } } } /////////////////// LedPin::LedPin(uint8_t pin, uint8_t level, uint16_t freq) : LedC(pin, freq){ if(!channel) Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); set(level); } /////////////////// void LedPin::set(float level){ if(!channel) return; Serial.printf("LED pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", channel->gpio_num, channel->channel, channel->speed_mode, channel->timer_sel, timer->freq_hz, timer->duty_resolution ); if(level>100) level=100; channel->duty=level*(pow(2,timer->duty_resolution)-1); channel->duty/=100; ledc_channel_config(channel); } /////////////////// void LedPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ // The algorithm below was provided on the web at https://www.cs.rit.edu/~ncs/color/t_convert.html // h = [0,360] // s = [0,1] // v = [0,1] int i; float f, p, q, t; if( s == 0 ){ *r = *g = *b = v; return; } h /= 60; i = floor( h ) ; f = h - i; p = v * ( 1 - s ); q = v * ( 1 - s * f ); t = v * ( 1 - s * ( 1 - f ) ); switch( i % 6 ) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; } } //////////////////////////// ServoPin::ServoPin(uint8_t pin, double initDegrees, uint16_t minMicros, uint16_t maxMicros, double minDegrees, double maxDegrees) : LedC(pin, 50){ if(!channel) Serial.printf("\n*** ERROR: Can't create ServoPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); this->minMicros=minMicros; this->maxMicros=maxMicros; this->minDegrees=minDegrees; microsPerDegree=(double)(maxMicros-minMicros)/(maxDegrees-minDegrees); set(initDegrees); } /////////////////// void ServoPin::set(double degrees){ if(!channel) return; Serial.printf("Servo pin=%d, ch=%d, mode=%d, timer=%d, freq=%d, res=%d\n", channel->gpio_num, channel->channel, channel->speed_mode, channel->timer_sel, timer->freq_hz, timer->duty_resolution ); double usec=(degrees-minDegrees)*microsPerDegree+minMicros; if(usecmaxMicros) usec=maxMicros; usec*=timer->freq_hz/1e6*(pow(2,timer->duty_resolution)-1); channel->duty=usec; ledc_channel_config(channel); } //////////////////////////// ledc_channel_config_t *LedC::channelList[LEDC_CHANNEL_MAX][LEDC_SPEED_MODE_MAX]={}; ledc_timer_config_t *LedC::timerList[LEDC_TIMER_MAX][LEDC_SPEED_MODE_MAX]={}; //////////////////////////// //******************************************************* // DEPRECATED - INCLUDED FOR BACKWARDS COMPATIBILITY ONLY //******************************************************* PwmPin::PwmPin(uint8_t channel, uint8_t pin){ this->channel=channel & 0x0F; this->pin=pin; ledc_timer_config_t ledTimer; ledTimer.timer_num=LEDC_TIMER_0; ledTimer.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE; ledTimer.duty_resolution=LEDC_TIMER_10_BIT; ledTimer.freq_hz=5000; ledc_timer_config(&ledTimer); ledChannel.gpio_num=pin; ledChannel.speed_mode=(this->channel)<8?LEDC_HIGH_SPEED_MODE:LEDC_LOW_SPEED_MODE; ledChannel.channel=(ledc_channel_t)(this->channel&0x07); ledChannel.intr_type=LEDC_INTR_DISABLE; ledChannel.timer_sel=LEDC_TIMER_0; ledChannel.duty=0; ledChannel.hpoint=0; ledc_channel_config(&ledChannel); } /////////////////// void PwmPin::set(uint8_t channel, uint8_t level){ ledChannel.duty=level*1023; ledChannel.duty/=100; ledChannel.duty&=0x03FF; ledc_channel_config(&ledChannel); } /////////////////// void PwmPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ // The algorithm below was provided on the web at https://www.cs.rit.edu/~ncs/color/t_convert.html // h = [0,360] // s = [0,1] // v = [0,1] int i; float f, p, q, t; if( s == 0 ){ *r = *g = *b = v; return; } h /= 60; i = floor( h ) ; f = h - i; p = v * ( 1 - s ); q = v * ( 1 - s * f ); t = v * ( 1 - s * ( 1 - f ) ); switch( i % 6 ) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; } }