L.R.A 78 Posted December 30, 2013 Share Posted December 30, 2013 Well i had noticed this problem quite a while ago but now i decided to look into it. Basicaly, I have 2 codes. Each one as diferent effects in a motor speed that is being controled by stelaris trough a l293d. The effect is very noticeable. Right now i only have the behavior or the DC motor to see that but as soon i can get my hands on a osciloscope (probaly next week) ill check the frequency and duty of the PWM. Notice that i use PWMWrite() wich is alredy a fuction included in Energia, i just enable the direct use of it. Also it's to note that when i use 500Hz istead of 15kHz the change in speed behavior is less noticeable. I know that this is not enough the motor but the pins in l293d that chose the direction are directly conected to VCC and GND for this test So 1st code: void setup() { // put your setup code here, to run once: pinMode(PF_0,OUTPUT); } void loop() { PWMWrite(PF_0,256,200,15000); } 2nd code (this one the motor only starts moving at dutys as high as 80%): void setup() { // put your setup code here, to run once: pinMode(PF_0,OUTPUT); } void loop() { PWMWrite(PF_0,256,200,15000); delay(100); } Quote Link to post Share on other sites
spirilis 1,265 Posted December 30, 2013 Share Posted December 30, 2013 Taking a look at this one, is there a good reason why you are merely delay(100)'ing and then letting loop() exit (thus letting Energia re-run it, including re-running the PWMWrite() function) after using PWMWrite? PWMWrite mucks with a bunch of registers, so it's possible you're interrupting the PWM process every 100ms (based on your delay) and interfering with its ability to do its job. Sounds like PWMWrite should be run at the end of setup()... The first example continuously re-runs the PWMWrite() function, causing a similar issue I bet. L.R.A 1 Quote Link to post Share on other sites
L.R.A 78 Posted December 30, 2013 Author Share Posted December 30, 2013 This a simplified code that i used to see what was the problem in a bigger code. But i will try to edit the code to only call PWMWrite when it's needed. But i guess that doing this would be the same: void setup() { // put your setup code here, to run once: pinMode(PF_0,OUTPUT); } void loop() { PWMWrite(PF_0,256,200,15000); while(1){ delay(100); } } But so i can't use a delay while there's a PWM being generated in a pin? Quote Link to post Share on other sites
spirilis 1,265 Posted December 30, 2013 Share Posted December 30, 2013 Yeah that should work. I have a Tiva-C LP and a Saleae Logic16 with me right now ... I'll try running that later and see what it gets. It has 100MHz sampling capability when using up to 3 signals so it should be able to measure this with good accuracy. L.R.A 1 Quote Link to post Share on other sites
L.R.A 78 Posted December 30, 2013 Author Share Posted December 30, 2013 Thanks Quote Link to post Share on other sites
spirilis 1,265 Posted December 30, 2013 Share Posted December 30, 2013 Ok: #include <wiring_private.h> void setup() { // put your setup code here, to run once: pinMode(PF_0, OUTPUT); } void loop() { // put your main code here, to run repeatedly: PWMWrite(PF_0, 256, 200, 15000); while(1) delay(100); } Saleae Logic16 shows a waveform with width=52.1uS, period=66.68uS, frequency = 14.997KHz. Pretty close. 52.1/66.68 = 0.781343, 256*0.781343 = 200.02 so that looks right. Running this: #include <wiring_private.h> void setup() { // put your setup code here, to run once: pinMode(PF_0, OUTPUT); } void loop() { // put your main code here, to run repeatedly: PWMWrite(PF_0, 256, 200, 15000); delay(100); } ...produces ALMOST the same thing, but every 100ms there's a single pulse whose width is 101.65uS instead of the typical 52.1uS. Running this: #include <wiring_private.h> void setup() { // put your setup code here, to run once: pinMode(PF_0, OUTPUT); } void loop() { // put your main code here, to run repeatedly: PWMWrite(PF_0, 256, 200, 15000); } Produces no waveform at all; the signal goes HIGH after Energia starts and then stays there with no transitions. dubnet, MichelKohler, Fmilburn and 2 others 5 Quote Link to post Share on other sites
L.R.A 78 Posted December 30, 2013 Author Share Posted December 30, 2013 Thanks! Then now i guess i gotta make some codding so i only call PWMWrite when duty is changed. Quote Link to post Share on other sites
L.R.A 78 Posted January 1, 2014 Author Share Posted January 1, 2014 BTW, how to change the title to add [sOLVED] Quote Link to post Share on other sites
vladn 3 Posted March 20, 2014 Share Posted March 20, 2014 I hit this problem recently. Apparently the analogWrite (which maps to PWMWrite) reconfigures the entire timer instead of just changing the compare register(s) and messes up the PWM phase. Is there a cleaner version of PWM (Energia/Arduino style) suitable for frequent duty cycle updates (sensored motor control, pwm audio out) ? [vent] I did my last project with the MSP430 the "hard" way (CCS and no libraries). Energia/Arduino is great when things work as you expect, but when something does not fit your needs there is a whole onion of code layers providing the hardware abstraction functionality. I find it harder to reverse engineer and tweak the HAL than to write a platform specific code from scratch. [end of vent] Quote Link to post Share on other sites
vladn 3 Posted March 20, 2014 Share Posted March 20, 2014 Ok, I found a partial workaround within a baseline Energia framework. The idea is to re-sync analogWrite() to the pwm signal iself . This works OK up to around 580Hz PWM frequency (good enough for my brushed motor PID controller project). For highly dynamic PWM (like audio) I have to dig deeper... int pwm; int dir; void setup() { //attach the PWM update interrupt handler to the PWM pin itself //*must* use the *rising* edge (falling edge messes up PWM) //on my Tiva-C Launchpad this works up to ~580Hz PWM frequency attachInterrupt(RED_LED, handler, RISING); //prime the pwm pin interrupts pwm = 1, dir = 1; analogWrite (RED_LED, pwm); } void loop() { pwm += dir; //pwm value should be constrained between 1 and 245, otherwise interrupts stop if (pwm == 254 || pwm == 1) dir = -dir; delayMicroseconds(2733); //some random value } //handler without the pwm value change detection logic void handler() { analogWrite (RED_LED, pwm); } /* //handler with the pwm value change detection logic void handler() { static int p_pwm = -1; if (p_pwm != pwm) { analogWrite (RED_LED, pwm); p_pwm = pwm; } } */ MichelKohler 1 Quote Link to post Share on other sites
vladn 3 Posted April 3, 2014 Share Posted April 3, 2014 I've spent some time recently experimenting with the Tiva timer PWM mode (not the PWM module). I have modified the wiring_analog.c such that duty cycle changes using PWMWrite() are now glitch free. Hence it is suitable for driving servos and other timing critical sources with frequent duty cycle updates. No interrupts are required. The changes are: - bypassing the timer disable/reset if it is already initialized to the PWM mode; - setting both MRSU and ILD bits in the Mode register such that both frequency and match register update are postponed to the next timer period; - the intermediate result of the duty cycle computation is increased so that large analog_res values do not cause overflow (useful for setting the duty cycle in microseconds for the servo) I tried to do a "minimally invasive" code modification to avoid compatibility issues. If the module interface change is acceptable then things can be done a bit cleaner/faster. Since I've already spend time learning the Tiva timer internals I can do further tweaks to the code if there is a community consensus on the optimal PWM interface (as a superset of Arduino). Try the code and see if you find any issues with it. If it does not cause any compatibility problems perhaps someone can help me integrate it into the next energia release. wiring_analog.c MichelKohler and L.R.A 2 Quote Link to post Share on other sites
vladn 3 Posted April 4, 2014 Share Posted April 4, 2014 To illustrate the benefits of the glitch free PWM here is a super trivial (essentially a one liner) servo library. No interrupts required - very efficient. Supports digital servos at higher PWM freqs too ! Two examples are included - a minimalistic one for a single servo, and a bit more involved one running 3 servos asynchronously with different control PWM frequencies and sweep periods. This library *requires* the wiring_analog.c file from the post above (it replaces the original one in the hardware/lm4f/cores/lm4f/). TServo.zip L.R.A 1 Quote Link to post Share on other sites
Paulmac1426459983 0 Posted April 10, 2014 Share Posted April 10, 2014 Looking forward to seeing this work on a Launchpad...! Quote Link to post Share on other sites
vladn 3 Posted April 23, 2014 Share Posted April 23, 2014 The linker seems to have a sporadic problem (huge .bin files) with uint64_t that I used in the updated PWMWrite(). Changed the type to float and things seem to work OK now. Please use the updated version: wiring_analog.c Also added support for the floating point angle to the TServo TServo.zip Updated code also posted to github: https://github.com/vladn2/Energia/ L.R.A 1 Quote Link to post Share on other sites
madias 0 Posted May 20, 2014 Share Posted May 20, 2014 Dear vladn, thank you for your work! I use the new wiring_analog.c for some audio stuff. With the "new one" you can hear a much cleaner tone on pwm output, without indifferences! It should be definitly in the library for a new energia release! Regards Matthias Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.