stefanbruens / esp8266_new_pwm Goto Github PK
View Code? Open in Web Editor NEWThis is a drop-in replacement for the ESP8266 SDK PWM
License: GNU General Public License v2.0
This is a drop-in replacement for the ESP8266 SDK PWM
License: GNU General Public License v2.0
Hi, i should want to drive a 3 wire pc fan with this library. Wich is the better way to set pwm to the 25Khz need to smooth operations of the fan ? Thank you
http://www.esp8266.com/viewtopic.php?p=52345#p52345
Please use NMI interrupt source, the "normal" source doesn't always work (for me: never).
Dude, the license is not compatible with esp-open-rtos so stop saying it is a drop in solution
Hello :)
I am working on a board that can easily control up to 5 pwm outputs or 1 RGB light an 2 pwm outputs using one ESP12f. It is all up and running using the FadeLed class (https://github.com/septillion-git/FadeLed) which is based on the analogWrite(). In order to drive led (former halogen) bulbs, I need a low active option for my board. Besides that, I can hear some harmonics of the 1 kHz PWM. I tried to use your class including it using
extern "C" {
#include <pwm.h>
}
but it wouldn't work. The error I get is
/Users/jt/Documents/Arduino/libraries/FadeLedNewPwm/src/FadeLedNewPwm.cpp:32:9: error: expected constructor, destructor, or type conversion before '(' token
pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info);
^
/Users/jt/Documents/Arduino/libraries/FadeLedNewPwm/src/FadeLedNewPwm.cpp:33:12: error: expected constructor, destructor, or type conversion before ';' token
pwm_start();
^
/Users/jt/Documents/Arduino/libraries/FadeLedNewPwm/src/FadeLedNewPwm.cpp:34:1: error: expected declaration before '}' token
}
I guess the reason for this is that the compiler expects a "FadeLed::" in front of every function, right?
I tried to understand your code in order to implement it in to the FadeLed class but failed. Do you have any idea or could change your code to an independent class?
I study electronics at THM in Gießen, GER, so I try my best in programming but I'm not into it very deeply. If communicating with me is easier in German, feel free to contact me :-)
Best
Hi,
I receive this error when attempting to compile mariusmotea's diyHue code (which uses your pwm.c as an addition):
Arduino: 1.8.4 (Mac OS X), Board: "Generic ESP8266 Module, 80 MHz, ck, 26 MHz, 40MHz, QIO, 1M (128K SPIFFS), 2, v2 Lower Memory, Disabled, None, Only Sketch, 115200"
Archiving built core (caching) in: /var/folders/yf/v0mm1gt17d75p1rdyd5vjlkw0000gn/T/arduino_cache_140262/core/core_esp8266_esp8266_generic_CpuFrequency_80,ResetMethod_ck,CrystalFreq_26,FlashFreq_40,FlashMode_qio,FlashSize_1M128,led_2,LwIPVariant_v2mss536,Debug_Disabled,DebugLevel_None____,FlashErase_none,UploadSpeed_115200_7f04165fe51592c926f91225eac66eae.a
sketch/Generic_RGBW_Light.ino.cpp.o: In function `pwm_start':
sketch/pwm.c:356: multiple definition of `pwm_start'
sketch/pwm.c.o:sketch/pwm.c:356: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `_Function_base':
sketch/pwm.c:403: multiple definition of `pwm_set_duty'
sketch/pwm.c.o:sketch/pwm.c:403: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `pwm_init':
sketch/pwm.c:415: multiple definition of `pwm_get_duty'
sketch/pwm.c.o:sketch/pwm.c:415: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `pwm_init':
sketch/pwm.c:426: multiple definition of `pwm_set_period'
sketch/pwm.c.o:sketch/pwm.c:426: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `String::operator==(char const*) const':
sketch/pwm.c:161: multiple definition of `pwm_init'
sketch/pwm.c.o:sketch/pwm.c:161: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `operator()':
sketch/pwm.c:436: multiple definition of `pwm_get_period'
sketch/pwm.c.o:sketch/pwm.c:436: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `operator()':
sketch/pwm.c:442: multiple definition of `get_pwm_version'
sketch/pwm.c.o:sketch/pwm.c:442: first defined here
sketch/Generic_RGBW_Light.ino.cpp.o: In function `operator()':
sketch/pwm.c:446: multiple definition of `set_pwm_debug_en'
sketch/pwm.c.o:sketch/pwm.c:446: first defined here
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Generic ESP8266 Module.
I reached out to mariusmotea about the issue and he directed me here. I would greatly appreciate if you could shed some light on why this is occurring. Does it have to do with a conflict with function definitions contained in the ESP8266 board manager? Thank you for your time.
First of all, nice code good solution, thanks for the lib!
I have a problem when the pwm period is lower than ~1500, the esp is restarted with wdt reset when using wifi in promiscuous mode. I tried to speed up the module to 160MHz but the behavior is the same.
Example code:
uint32 pwm_duty_init[3] = {20, 120, 250};
uint32 io_info[3][3] = {
{PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12},
{PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13, 13},
{PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14, 14}
};
pwm_init(255, pwm_duty_init, 3, io_info);
pwm_start();
wifi_set_opmode(STATION_MODE);
wifi_set_phy_mode(PHY_MODE_11B);
wifi_set_user_rate_limit(RC_LIMIT_11B, 0x00, RATE_11B_B1M, RATE_11B_B1M);
wifi_set_user_limit_rate_mask(0x01);
wifi_set_channel(1);
wifi_promiscuous_enable(1);
I'm experiencing an issue with some RGB controllers. I'm using low frequencies (period = 10000). Using NMI works great but when I use TIMER1 only duty cycles of 0 or 10000 (100%) work. Anything in between just doesn't change anything. I have the feeling it could be hardware related (maybe the SPI flash?). Any ideas?
Hi,
Are there any issues using this with ESP8266_RTOS_SDK? I'm just getting started and I'm not sure which resources the RTOS is using for it's own purposes.
Hi,
I'm testing your library but unfortunately I'm not able to get it work.
sketch\pwm.c:96:51: error: invalid conversion from 'void*' to 'gpio_regs*' [-fpermissive]
static struct gpio_regs* gpio = (void*)(0x60000300);
sketch\pwm.c:110:53: error: invalid conversion from 'void*' to 'timer_regs*' [-fpermissive]
static struct timer_regs* timer = (void*)(0x60000600);
The problem seems to be in casting constant to pointer to struct.
I'm not using the timer directly, but I have some libraries that probably depend on it (ESP8266HTTPUpdateServer, WifiManager, ...). Therefore I had to enable this in pwm.c for the library to work:
#define PWM_USE_NMI 1
The PWM works very well, but if I enable color cycling in my loop()
, where I change the PWM settings according to a HSV color table in each cycle, I get a wdt reset after some time (tens of seconds to some minutes):
ets Jan 8 2013,rst cause:4, boot mode:(3,0)
wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
va3a36545
~ld
<new boot here>
For of all, one can not praise people, that put their code online and provide support, enough, so " Thank you so much !"
I wouldn't be writing if i would not be experiencing an issue, and i fact i had not even noticed the issue my self. The application is using an ESP-01 (a 8685 to be exact) as a controller for 5050 RGB ledstrip, using mosfets to drive them. Since nearly all available pins need to be pulled 'HIGH' at boot, and that would cause the strip to be 'fully-on' i added a 7402, and used pin 3 to block the signal initially. This means that as a result the signal is inverted. 100 duty cycle is 'OFF' and 0% duty cycle is 'ON' Now what happens is that when 2 of my 3 channels (or all of them) reach 100%, from a lesser duty cycle, a drop out occurs, which in this case causes a short flash. The solution i found so far is to reduce the PWM PEROD to 1024 (from 5000) and it appears to have resolved the issue (I can't see it anymore, but more testing is required) but i am also curious as to what could be the cause.
This is my SetColor() function, which is called repeatedly from loop()
void SetColor(uint32_t color32) {
uint8_t i = 3;
while (i) {
i--;
float gamma = color32 & 0xFF;
float bright = BrightnessFade();
gamma = gamma * bright;
if (gamma > 255) gamma = 255 ;
uint16_t gamma16 = Cosine(gamma);
if (!INVERT) gamma16 = PWM_PERIOD - gamma16;
pwm_set_duty(gamma16, i);
color32 = color32 >> 8;
}
pwm_start();
}
uint16_t Cosine(float gamma) {
float cosval = cos (( gamma * PI ) / 510.0) * PWM_PERIOD;
int cosine = (int) cosval;
if (cosine < 0) cosine = 0;
if (cosine > PWM_PERIOD) cosine = PWM_PERIOD;
return (uint16_t) cosine;
}
BrightnessFade() can be considered to return 1.0 . As you can see i've been making trying to make sure that Cosine() doesn't return a value outside of it's range, but that is probably not at all required. I don't have anything else that is interrupt based running except for wifi connections (both AP & STA) and i required i can try and connect an oscilloscope though mine isn't very good.
error: expected '=', ',', ';', or 'asm' etc before 'pwm_set_duty'
by all the other functions i got the same error. What is the problem I cloned this rep and then adjusted the paths to the files, because I am using RTOS SDK but all the paths are existing.
Hi,
just wondering about two things:
Thx in advance
Hello,
First thanks for the library which I consider to be the best OSS PWM library for ESP8266 I found.
I am observing soft LED flickering when using this PWM implementation.
The complete code:
#include "c_types.h"
#include "pwm.h"
#include "eagle_soc.h"
uint32 io_info[][3] = {
{ PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13, 13 }
};
uint32 pwm_duty_init[5] = {20};
void user_init() {
pwm_init(250, pwm_duty_init, 1, io_info);
}
uint32_t user_rf_cal_sector_set() {
}
Measurements with oscilloscope shows that most of the pulses take 4.07 μs:
But if I set trigger to pulse width of higher values, then it often triggers:
Original firmware of the device, which is closed source, doesn't have this issue. But according to strings in the binary blob it seems to be build with RTOS.
Is there anything I can do to prevent this?
Hi,
First of all, thanks for this awesome library! I've been using it a lot.
Second, I began wondering if the timing works correctly when the CPU frequency is set to 160 MHz. As far as I can tell from the documentation, the bus frequency doesn't change if CPU frequency is changed, so neither should the timer base clock.
Then there's the question of interrupt overhead. Do you think the interrupt overhead is memory-induced and thus wouldn't be affected by the CPU frequency?
The busy wait loop at https://github.com/StefanBruens/ESP8266_new_pwm/blob/master/pwm.c#L132 at least needs changing - instead of multiplying by 4, we should probably multiply by 8 when CPU frequency is doubled.
I'm willing to do some experiments, but it would be nice to hear what you know about this.
Hi,
Could you share it as closed library named libpwm.a like exact replacement of the original one?
I'm using Arduino version of esp8266 software and I don't know how to add the pwm.c file to the project and where to configure it for just 3 pwm pins for rgb led controller.
Thanks in advance
Because the 1Khz pwm then period = 5000 , so I want the 10kHz pwm , and I set code as:
pwm_init(500,pwm_duty_init, 4, io_infos);
pwm_set_duty(10,0);
pwm_set_duty(500,1);
pwm_set_duty(51,2);
pwm_set_duty(102,3);
pwm_start();`
but show result : (is not 10Khz , please tell me how to set the 10kHz pwm )
I am trying to use this library with arduino.
Here is my code:
// PWM https://github.com/StefanBruens/ESP8266_new_pwm
#include "Arduino.h"
extern "C" {
#include "pwm.h"
}
#define PWM_CHANNELS 1
const uint32_t period = 5000;
void setup() {
Serial.begin(115200);
uint32 io_info[PWM_CHANNELS][3] = {
{PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12}
};
uint32 pwm_duty_init[PWM_CHANNELS] = {0};
pinMode(12, OUTPUT);
pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info);
pwm_set_duty(4, 0); //GPIO12 = D6
pwm_start();
}
void loop() {
delay(1);
}
Just setup and running a simple loop, without even changing duty cycle.
It results with an exception and resets every time, about 10 seconds after start.
Without delay(1) in the loop it works fine. It also works fine with other instructions in the loop - e.g. Serial.println(...);
Any ideas? Am I doing something wrong?
Hey Stefan,
great Code! You helped me a lot with my porject :)
I was wondering if it would be possibe to phase shift the PWM of 5 channels? Reason is that my PSU starts to coil whine and I tought it could be stopped if not all channels would be off or on at the same time. I didn't try to configure > 20khz jet.
Regards
I get this error:
Compiling 'pwmTest' for 'NodeMCU 1.0 (ESP-12E Module)'
pwmTest.cpp.o: (.text.setup+0xc): undefined reference to pwm_init(unsigned int, unsigned int*, unsigned int, unsigned int (*) [3])
pwmTest.cpp.o: (.text.setup+0x10): undefined reference to pwm_start()
pwmTest.cpp.o: In function setup
pwmTest.ino:23: undefined reference to pwm_init(unsigned int, unsigned int*, unsigned int, unsigned int (*) [3])
pwmTest.ino:24: undefined reference to pwm_start()
collect2.exe*: error: ld returned 1 exit status
Error compiling for board NodeMCU 1.0 (ESP-12E Module)
pwmTest.ino:
#include<pwm.h>
#define PWM_CHANNELS 1
const uint32_t period = 5000; // * 200ns ^= 1 kHz
// PWM setup
uint32 io_info[PWM_CHANNELS][3] = {
// MUX, FUNC, PIN
{ PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12 }
};
// initial duty: all off
uint32 pwm_duty_init[PWM_CHANNELS] = { 0 };
void setup() {
pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info);
pwm_start();
}
void loop() {
}
I have found "core_esp8266_wiring_pwm.c" in Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266 and replaced its contents with your code.
What am I doing wrong?
There has been discussion on the ESP8266 Arduino repo about replacing/reworking the pwm code, i.e.: analogWrite(). One possibility that has come up is to use the code in this repo. However, the license is incompatible, as this code is GPL 2.0, while the Arduino repo is LGPL 2.1
Is it possible to change the repo license to the same as the ESP8266 Arduino repo for compatibility, so that this code could be used there?
Hi,
The logic for the SDK_PWM_PERIOD_COMPAT_MODE appears to be incorrect?
#if SDK_PWM_PERIOD_COMPAT_MODE
#define PWM_PERIOD_TO_TICKS(x) (x * 0.2)
#define PWM_DUTY_TO_TICKS(x) (x * 5)
#define PWM_MAX_DUTY (PWM_MAX_TICKS * 0.2)
#define PWM_MAX_PERIOD (PWM_MAX_TICKS * 5)
#else
...
#endif
In README:
By default there is one small difference to the SDK. The code uses a unit of 200ns for both period and duty. E.g. for 10% duty cycle at 1kHz you need to specify a period value of 5000 and a duty cycle value of 500, a duty cycle of 5000 or above switches the channel to full on.
To have full compatibility with the SDK, you have to set the SDK_PWM_PERIOD_COMPAT_MODE define to 1. If set, the code will use 1us for PWM period and 40ns for the duty cycle. E.g. 10% duty cycle at 1kHz is set by a period value of 1000 and a duty cycle value of 2500, full duty at 25000 and above.
Let's say for 1KHZ, if SDK_PWM_PERIOD_COMPAT_MODE is defined to be 1. Then period should multiply by 5 (1000*5=5000) not divided by 5.
The correct logic should be:
#if SDK_PWM_PERIOD_COMPAT_MODE
#define PWM_PERIOD_TO_TICKS(x) (x * 5)
#define PWM_DUTY_TO_TICKS(x) (x * 0.2)
#define PWM_MAX_DUTY (PWM_MAX_TICKS * 5)
#define PWM_MAX_PERIOD (PWM_MAX_TICKS * 0.2)
#else
...
#endif
Thanks.
I'm trying to run example code, but have no results. PWM not working.
#include "pwm.c"
#define PWM_CHANNELS 5
#define SDK_PWM_PERIOD_COMPAT_MODE 1
const uint32_t period = 5000; // * 200ns ^= 1 kHz
uint32 pwm_duty_init[PWM_CHANNELS] = {500, 500, 500, 500, 500};
uint32 io_info[PWM_CHANNELS][3] = {
// MUX, FUNC, PIN
{PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12},
{PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15, 15},
{PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13, 13},
{PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14, 14},
{PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5 , 5},
};
void setup() {
pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info);
pwm_start();
}
void loop() {
}
Hello,
today I replaced my analogWrite() based stuff by you library. All my flicker-issues immediately disappeared - great work!
The only drawback for me is that the use of your library from an Arduino sketch is quite un-intuitive:
I use the pre-defined pins D1...D3. I had to find out what the real GIPOs are (5,4 and 0). Then I had to find out the register names (PERIPHS_IO_MUX_GPIO5_U, PERIPHS_IO_MUX_GPIO4_U, PERIPHS_IO_MUX_GPIO0_U)
To write PWM values, I have to use indices (0,1,2), not GPIO pins or D1...D3. And I always have to call pwm_start() after each change.
It would be great if there where a wrapper around your lib, so that it can easily be used as library in arduino. What do you think about this?
Regards,
Michael.
Can you explain how to use your library with ide?
i have flicker at 50% pwm!
if range=10000 than
pwm from 4998 to 4999 ok but from 4999 to 5000 flicker :-(
Hi SfefanBruens,
like to implement your code to replace the PWM for ESP8266 in Espruino.
Please let me know if this is ok for you and if can come up with some question too.
KR Mark Becker
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.