what is the reason for unequal voltages in different ports in pwm? - avr

I have a piece of code for getting same analog pwm output voltage from PB4 and PB5 using fast pwm in output compare mode. However the voltage from them is different. What could possibly be the reason for this ? Also the voltage from neither of the pins is close to 1.23 V which is what should be the output voltage should be.
Here is the code.
#include <`avr/io.h`>
#include <`avr/interrupt.h`>
ISR(TIMER0_COMP_vect)
{
cli();
PORTB &= ~(1<<PB5);
sei();
}
ISR(TIMER0_OVF_vect)
{
cli();
PORTB |= (1<<PB5);
sei();
}
void init(void)
{
TCCR0 |= (0<<FOC0)|(1<<WGM01)|(1<<WGM00)|(1<<COM01)|(1<<COM00)|(1<<CS02)|(1<<CS01)|(1<<CS00);
OCR0 = 63;
TIMSK |= (1<<OCIE0)|(1<<TOIE0);
}
int main(void)
{
DDRB = 0xFF;
PORTB = 0xFF;
init();
sei();
while(1);
}

Firstly, if you're using something like an ATMega328p, having all three CS bits set will enable an external clock source, rather than using the internal clock, and so the timer won't run (unless you do actually have an external timer clock source). Depending on what microcontroller you are using, make sure that those bits are enabling a particular prescaler value instead.
Secondly, you might also encounter problems due to your measurement method and the way PWM actually works. Though it is often listed as an analog output when dealing with Arduinos, pulse width modulation actually does exactly what it says - it rapidly switches a digital output between ground and VCC (likely 5V), with a varying duty cycle. If one of those output pins is viewed on an oscilloscope, it will probably show some form of square wave.
When measured with a multimeter, the value you are seeing will be a combination of samples taken while the output is either high or low, and possibly an average of these randomly timed samples, hence the unexpected reading.
To get your desired result, you really need to smooth out the digital output. In short, this is often done with a low pass filter, composed of a resistor and capacitor attached to the output pin.
This works by using the square wave to charge the capacitor through the resistor while it is high, and discharge it while it is low. By having more time high than low (a longer duty cycle), the capacitor stabilises at a higher voltage (and vice versa). The resistor limits the current drawn from the AVR output pin (as if the capacitor was at 0V and the output gets driven high, you're effectively shorting the output to ground momentarily).
For your case, a resistor somewhere around 4.7K and a capacitor around 2uf will probably suit. Increase the capacitance or the resistance to reduce ripple.

Related

GPIO32 pin works in analog mode, always reads 0 in digital mode

I'm having some difficulty getting PCNT pulse counting working with a prototype ESP32 device board.
I have a water level sensor (model D2LS-A) that signals state by the frequency of a square wave signal it sends to GPIO32 (20Hz, 50Hz, 100Hz, 200Hz, 400Hz).
Sadly, the PCNT counter stays at 0.
To troubleshoot, I tried putting GPIO32 in ADC mode (attenuation 0, 10-bit mode) to read the raw signal (sampling it many times a second), and I'm getting values that I would expect (0-1023). But trying the same thing using digital GPIO mode, it always returns 0, never 1 in all the samples.
Since the PCNT ESP IDF component depends on reading the pin digitally, the counter never increments past 0.
So the real problem I'm having is: why aren't the ADC readings (between 0-1023) translating to digital readings of 0-1 as one would expect?

Multiple PWM Channels on PIC

I use the PIC16F88 for my project, with XC8 compiler.
What I'm trying to achieve is to control 4 LEDs with 4 buttons, when you press a buttons it increases the duty cycle of the corresponding LED by 10%.
When you press the button on RB0 it increases the duty cycle of the LED on RB4, and so on.
Every LED is independent, therefore it can have a different duty cycle.
The problem is that the PIC i'm using only have one PWM module on either RB0 or RB3 (using CCPMX bit).
After some research I decided to implement software PWM to have four different channels, each channels would control one duty cycle, but most of the sources I found didn't provide any explanation on how to do it.
Or is there a way to mirror PWM to multiple pins ?
Thanks by advance for helping me out.
Mirroring is not an option.
PWM is relatively simple. You have to set PWM frequency (which you will not change) and PWM duty cycle (which you need to change in order to have 0-100% voltage range). You have to decide about resolution of PWM, voltage step that you need (built in PWM for example is 8-bit and has 0-255 steps).
Finally, you have to set timer to interrupt based on PWM frequency * PWM resolution. In Timer ISR routine you need to check resolution counts and PWM value of all your channels. Resolution count will have to reset when resolution value is reached (and start to count from 0 again, all outputs go HIGH here, also). When PWM value of output is reached you have to toggle (pull it LOW) corresponding pin (and reset it back to HIGH with every resolution count reset).
This is only one way of doing it, involves only one timer and should be most simple since your PIC is low with resources.
Hope it helps...

lpc17xx frequency detection of square wave using polling

I have to read 5 different frequencies(square wave) up to 20KHz by polling 5 different pins.
Im using a single timer interrupt only,for every 1 millisecond.
Polling of the pins would be done in the ISR.
The algorithm i have thought of so far is:
1.Count number of HIGH
2.Count number of LOW
3.Check if sum of HIGH+LOW=Time period.
This algorithm seems slow and is not practical.
Is there any Filter functions that i could use to check the frequency at pin so that all i have to do would be to call that function?
Any other algorithms, for frequency detection would be good.
I am restricted to only 1 interrupt in my code(timer interrupt)
you need to take in mind what are the input signal properties
as you are limited to just single interrupt (which is pretty odd)
and the timer has only 1 KHz
the input signal must not be above 0.5 KHz
if the signal is with noise the frequency can easily rise above that limit many times
speed
you wrote that the simple counting period approach is slow
what CPU and IO power have you?
I am used to Atmel AVR32 AT32UC3 chips which are 2 generation before ARM cortex chips
and I have around 96MIPS and 2-5 MHz pin R/W frequency there without DMA or interrupts
so what exactly is slow on that approach?
I would code it with your constrains like this (it is just C++ pseudo code not using your platform):
const int n=5;
volatile int T[n],t[n],s[n],r[n]; // T last measured period,t counter,s what edge is waitng for?
int T0[n]={?,?,?,...?}; // periods to compare with
void main() // main process
{
int i;
for (i=0;i<n;i++) { T[i]=0; t[i]=0; s[i]=0; r[i]=0; }
// config pins
// config and start timer
for (;;) // inf loop
{
for (i=0;i<n;i++) // test all pins
if (r[i]>=2) // ignore not fully measured pins
{
r[i]=2;
if (abs(T[i]-T[0])>1) // compare +/- 1T of timer can use even bigger number then 1
// frequency of pin(i) is not as it should be
}
}
}
void ISR_timer() // timer interrupt
{
// test_out_pin=H
int i;
bool p;
for (i=0;i<n;i++)
{
p=get_pin_state(i); // just read pin as true/false H/L
t[i]++; // inc period counter
if (s[i]==0){ if ( p) s[i]=1; } // edge L->H
else { if (!p) s[i]=0; T[i]=t[i]; t=0; r[i]++; } // edge H->L
}
// test_out_pin=L
}
you can also scan as comparation between last pin state and actual
that would eliminate the need of s[]
something like p0=p1; p1=get_pin_state(i); if ((p1)&&(p0!=p1)) { T[i]=t[i]; t[i]=0; }
this way you can also more easily implement SW glitch filters
but I think he MCU should have HW filters too (like most MCU does)
How would I do this without your odd constraints?
I would use external interrupt
usually they can be configured to be trigger on specific edge of signal
also including the HW filtering of noise
on each interrupt take the internal CPU clock counter value
and if it is not at disposal then timer/counter state
substract with the last measured one
restore from overflow if occured
change to s or Hz if needed
this way I can scan pins on MCU with 30MHz clock reliably with frequency up to 15MHz (use this for IRC decoder)
and yes IRC can give you above 1 MHz frequencies on occasions (on edge between states)
if you want the ratio also the you can:
have 2 interrupts one for positive and second for negative edge
or use just one and reconfigure the edge after each hit (Atmel UC3L chips I used some time ago had problem with this one due to internal bugs)
[notes]
it is essential that the pins you accessing are at the same IO port
so you can read them all at once and then just decode the pins after
also the GPIO module is usually configurable so check what clock is it powered with
there are usually 2 clocks one for interfacing the GPIO module with CPU core
and the second for the GPIO itself so check both
you can also use DMA instead of external interrupt
if you can configure to read the IO port by DMA ... to memory somewhere
then you can inspect on the background process independent to IO

IR emitter and PWM output

I have been using FRDM_KL46Z development board to do some IR communication experiment. Right now, I got two PWM outputs with same setting (50% duty cycle, 38 kHz) had different voltage levels. When both were idle, one was 1.56V, but another was 3.30V. When the outputs were used to power the same IR emitter, the voltages were changed to 1.13V and 2.29V.
And why couldn't I use one PWM output to power two IR emitters at the same time? When I tried to do this, it seemed that the frequency was changed, so two IR receivers could not work.
I am not an expert in freescale, but how are you controlling your pwm? I'm guessing each pwm comes from a separate timer, maybe they are set up differently. Like one is in 16 bit mode (the 3.3V) and the other in 32 (1.56v) in that case even if they have the same limit in the counter ((2^17 - 1) / 2) would be 50% duty cycle of a 16 bit timer. But in a 32 bit, that same value would only be 25% duty so, one output would be ~1/2 the voltage of the other. SO I suggest checking the timer setup.
The reason the voltage changed is because the IR emmiters were loading the circuit. In an ideal situation this wouldn't happen, but if a source is giving too much current the voltage usually drops a bit.

PID Control Loops with large and unpredictable anomalies

Short Question
Is there a common way to handle very large anomalies (order of magnitude) within an otherwise uniform control region?
Background
I am working on a control algorithm that drives a motor across a generally uniform control region. With no / minimal loading the PID control works great (fast response, little to no overshoot). The issue I'm running into is there will usually be at least one high load location. The position is determined by the user during installation, so there is no reasonable way for me to know when / where to expect it.
When I tune the PID to handle the high load location, it causes large over shoots on the non-loaded areas (which I fully expected). While it is OK to overshoot mid travel, there are no mechanical hard stops on the enclosure. The lack of hardstops means that any significant overshoot can / does cause the control arm to be disconnected from the motor (yielding a dead unit).
Things I'm Prototyping
Nested PIDs (very agressive when far away from target, conservative when close by)
Fixed gain when far away, PID when close
Conservative PID (works with no load) + an external control that looks for the PID to stall and apply additional energy until either: the target is achieved or rapid rate of change is detected (ie leaving the high load area)
Hardware Limitations
Full travel defined
Hardstops cannot be added (at this point in time)
Update
My answer does not indicate that this is best solution. It's just my current solution that I thought I would share.
Initial Solution
stalled_pwm_output = PWM / | ΔE |
PWM = Max PWM value
ΔE = last_error - new_error
The initial relationship successfully ramps up the PWM output based on the lack of change in the motor. See the graph below for the sample output.
This approach makes since for the situation where the non-aggressive PID stalled. However, it has the unfortunate (and obvious) issue that when the non-aggressive PID is capable of achieving the setpoint and attempts to slow, the stalled_pwm_output ramps up. This ramp up causes a large overshoot when traveling to a non-loaded position.
Current Solution
Theory
stalled_pwm_output = (kE * PID_PWM) / | ΔE |
kE = Scaling Constant
PID_PWM = Current PWM request from the non-agressive PID
ΔE = last_error - new_error
My current relationship still uses the 1/ΔE concept, but uses the non-aggressive PID PWM output to determine the stall_pwm_output. This allows the PID to throttle back the stall_pwm_output when it starts getting close to the target setpoint, yet allows 100% PWM output when stalled. The scaling constant kE is needed to ensure the PWM gets into the saturation point (above 10,000 in graphs below).
Pseudo Code
Note that the result from the cal_stall_pwm is added to the PID PWM output in my current control logic.
int calc_stall_pwm(int pid_pwm, int new_error)
{
int ret = 0;
int dE = 0;
static int last_error = 0;
const int kE = 1;
// Allow the stall_control until the setpoint is achived
if( FALSE == motor_has_reached_target())
{
// Determine the error delta
dE = abs(last_error - new_error);
last_error = new_error;
// Protect from divide by zeros
dE = (dE == 0) ? 1 : dE;
// Determine the stall_pwm_output
ret = (kE * pid_pwm) / dE;
}
return ret;
}
Output Data
Stalled PWM Output
Note that in the stalled PWM output graph the sudden PWM drop at ~3400 is a built in safety feature activated because the motor was unable to reach position within a given time.
Non-Loaded PWM Output

Resources