Shop OBEX P1 Docs P2 Docs Learn Events
Have inputs that are square waves — Parallax Forums

Have inputs that are square waves

defcon.klaxondefcon.klaxon Posts: 8
edited 2011-03-08 16:42 in Propeller 1
Hi all,

I'm hoping someone can help me with a project that seems to have beaten me after lots of experimentation and debugging. If you can help, I'd be most appreciative. Below is the problem, and I've tried to describe it the best I can. If there's any add'l info that can help you help me, please let me know. Thanks!

I'm working on a senior project and basically stated, I have a square wave generated by the Propeller that's 1kHz, with variable duty cycle. The duty cycle can be as small as 5% or as large as 96%. This signal (0V to 3.3V) is put through a unipolar to bipolar converter (+12V to -12V), then passed through some hardware. The result is that as the circuit changes, the +12V peak is reduced to +9V and +6V (but the -12V reference stays the same). The bipolar square wave is then put through a stack of parallel comparators, and that feeds back into the Propeller. If the square wave is +12V, then all comparators are on. If the square wave is +9V, then the "top" comparator is off but the ones below that are on. If +6V, the top two comparators are off but the rest are on, and etc. Those signals is brought back down to 0V to 3.3V for input to the Propeller.

The challenge is that the comparators are turning on and off with the duty cycle of the square wave so I'm trying to "time" the code correctly to look at the inputs once per cycle. What's odd is that I *think* I've written the code to do what I want, but it's not performing well.

What I've been trying is a POSedge detection...I've fed the square wave output pin into an input pin and then increment PSHA whenever a POSedge has been detected. What I figure is that PSHA will be incremented every time there is a positive edge, so I tell my code that when PSHA equals 1, reset it to zero, then run my logic code. This is in a repeat loop that contains all my code logic (if the square wave is at 12V do this, if 9V do this, etc).

The problem is that my code is doing something that isn't what I *think* I'm asking it to do. A good example is that one of my debugging techniques has been to put a wait command at the end of the repeat loop. I figure if the code runs once and gets to the wait loop, it should wait exactly one second before PSHA sees another positive edge, increments, and then my repeat loop is run where PSHA is reset to 0 and the logic code runs again. This, in actuality, is not what happens. If I ask it to wait one second, it'll actually not respond until about 10 seconds have past. If I ask it to wait 10 seconds, it waits forever. If I ask it to wait for a tenth of a second, it waits for about 1.

The greater problem is that the logic code is not working correctly based on the changing inputs, and I think the instability of the Propeller "looking" at the inputs is the culprit.

Instead of randomly throwing numbers in a wait command to bang it into working, I'd like to figure out why it's not doing what I'm asking, and then go from there. Maybe I'm not using POSedge correctly, maybe I don't understand the timing of the Propeller correctly, I'm not sure.

I have two ideas, not sure if they'll help. First, should I also use a NEGedge command to keep the Propeller waiting to look at the inputs again until the square wave is done for that duty cycle? I haven't tried that yet, but it's an idea. Second, would it be better to rewrite the code so that when there is a positive edge detected the inputs are treated like an array, and then the logic code is run on those values? Then I'm not looking at the inputs in real time, I'm looking at stored values. That's easier said than done, I'm not sure how I would code that in SPIN at the moment but it's an idea.

Sorry this is so long guys, I've tried to be descriptive and accurate so that the problem is clear. If you want to see the code let me know and I'll put it up. Thanks for any help! I've found through this project that what I want the Propeller to do versus what I'm actually programming can be drastically different, so I appreciate any insight from people that have more experience than me!

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-02-19 22:26
    ... I have a square wave generated by the Propeller that's 1kHz, with variable duty cycle.
    ...
    The problem is that my code is doing something that isn't what I *think* I'm asking it to do. A good example is that one of my debugging techniques has been to put a wait command at the end of the repeat loop. I figure if the code runs once and gets to the wait loop, it should wait exactly one second before PSHA sees another positive edge, increments, and then my repeat loop is run where PSHA is reset to 0 and the logic code runs again.
    Unless this is a typo you'll get 1000 positive edges within one second. That said, it'd really help to see some code (in case I misinterpreted the relationship between the generated square wave and the feedback pulses).
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-02-19 23:00
    kuroneko wrote: »
    Unless this is a typo you'll get 1000 positive edges within one second. That said, it'd really help to see some code (in case I misinterpreted the relationship between the generated square wave and the feedback pulses).

    Mathematically, you are correct there are 1000 positive edges in one second. What I meant was, if I waitcnt the code from proceeding for one second, it should be one second before it goes and looks again at the inputs.

    And yeah, I'll get the code up and posted so it'll be easier to see what I'm doing. I'll clean it up and remove some old commented out stuff, then put it up. Thanks for the quick response!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-02-19 23:13
    Re the voltages, that sounds very much like RS232 signal levels and a max232 or similar 3V version could turn that into propeller voltages. But if you already have comparators working that is fine.

    Second issue is the software. You can do this in Spin or PASM. At 1khz, spin should be fast enough. What are you trying to measure - the frequency or the duty cycle or both? If you are wanting to measure the duty cycle, how much accuracy do you need? eg if 1khz and you want it to the nearest 1%, that is now the same as measuring a 100khz wave. It can all be done though, as the propeller has the cnt() function which ticks along at megahertz speed. I presume you have an external crystal (5Mhz?). If so, you can detect the edge, then wait till it changes, then wait till it changes again, and with those three counter values you can work out both the frequency and the duty cycle.

    Maybe post some code first, and we can work on that.
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-02-23 11:44
    Hi guys,

    Here is my code, cleaned up a bit and hopefully understandable.

    Specifically, the project is a charger for electric vehicles. The basic functionality is this:

    1. if no vehicle is present, the signal output is +12V with ground reference.
    2. if a vehicle is plugged in, the square wave starts and the peak is now +9V (dropped by voltage dividers in the vehicle), with -12V reference.
    3. if the vehicle wants to charge, the square wave drops further to +6V (again dropped by voltage dividers in the vehicle), with -12V reference.

    The vehicle actually takes in 120/240VAC and does all the rectification/filtering itself, so the microcontroller is basically controlling solid state relays that provide the AC voltage.

    The frequency of the square wave is 1kHz, but the duty cycle can vary from 5% to 96% and this tells the vehicle how much current it can pull. The most the duty cycle can vary is 2%.

    Basically, the square wave signal goes through comparators and based on where the peak voltage of the square wave is (+12 DC, or +9/+6 square wave) the microcontroller knows if a vehicle is present (start square wave), whether or not it wants to charge, and if the vehicle has been disconnected (square wave cog is killed).

    Any questions, let me know. Thanks for the help!

    posted_to_forums.spin
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-02-23 11:57
    Dr_Acula wrote: »
    What are you trying to measure - the frequency or the duty cycle or both?

    Well, that's a good question. I'm not actually trying to measure the frequency or duty cycle...what I am trying to do is look at the square wave only when it's positive. With the eight parallel comparators, their outputs will say if the vehicle isn't present (which will be a +12V DC signal), if the vehicle is present (a +9V square wave) or if the vehicle is present and wants to charge (+6V square wave). I believe my problem is that I'm trying to look at the square wave only when it's positive, but in actuality the code is looking when it's negative, possibly during transitions. What I'm trying to do is get the code to look at the square wave only when it's positive. Does that make sense?
    If you are wanting to measure the duty cycle, how much accuracy do you need?

    if the square wave is at 5%, it could be as low as 3% or as high as 7% and still meet the technical specification.
    I presume you have an external crystal (5Mhz?).

    that is correct.
    If so, you can detect the edge, then wait till it changes, then wait till it changes again, and with those three counter values you can work out both the frequency and the duty cycle.

    i don't need to measure the actual duty cycle or frequency as described above, but what you describe (detect edge, wait till it changes, wait till it changes again) is exactly what i want to do, and have been trying to do, but have been unsuccessful at getting solid, stable operation. any help is very much appreciated!
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-23 20:54
    I'm a bit worried about the strict phsa == 1 criteria. If you spend too much time in that branch phsa - if checked again - will be >1 which makes you sit there for a while.

    You could try simple manual edge detection possibly in a separate cog as it would block and I'm not sure how much of your main loop needs constant attention.
    waitpne(|<cpmon, |<cpmon, 0)
      waitpeq(|<cpmon, |<cpmon, 0)
    
    What I'm trying to do is get the code to look at the square wave only when it's positive.
    @80MHz this will get you about 180..1160 cycles into the high part of the incoming square wave. I don't know if the monitored square wave has the same duty cycle as the one sent out. Even if that's the case the minimum high cycle seems to be about 7k2 (clkfreq/11000) so plenty of cycles left. That said, SPIN isn't a speed monster so whatever inputs you want to sample, get them immediately after you detect the edge (short of involving PASM).

    To be honest I'm still not entirely sure what you want to look at and when but I'm sure we figure this one out.
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-02-23 22:45
    kuroneko wrote: »
    I'm a bit worried about the strict phsa == 1 criteria. If you spend too much time in that branch phsa - if checked again - will be >1 which makes you sit there for a while.

    Yeah, that was a concern for me as well. I was trying "greater than or equal to 1" but it wasn't helping. I tried "equal to 1" as an experiment, and that's where I left off.

    You could try simple manual edge detection possibly in a separate cog as it would block and I'm not sure how much of your main loop needs constant attention.
    waitpne(|<cpmon, |<cpmon, 0)
      waitpeq(|<cpmon, |<cpmon, 0)
    

    I had just read about waitpeq and waitpne like yesterday...definitely looks like it might be promising. I'll work with that a bit, see if it'll help. As far as how much my main loop needs constant attention, I'd say I'd like to run the loop every tenth of a second. That way it seems instantaneous to the user, but it isn't burning up clock cycles unnecessarily.
    I don't know if the monitored square wave has the same duty cycle as the one sent out.

    It does have the same duty cycle, it's actually the exact same signal. See below for more info that may help.
    To be honest I'm still not entirely sure what you want to look at and when but I'm sure we figure this one out.

    Let me see if I can help explain what I'm doing, I know it can be hard to understand via forum messages. Here are some notes I hope are helpful:

    1. The microcontroller produces a square wave, whose duty cycle tells the electric vehicle how much current it can draw. This is put through a bipolar square wave generator (op amp as a differential amplifier) to go to +12V and -12V.
    2. This square wave is sent to the vehicle, where internal resistive voltage dividers alter the signal; if the vehicle is present, it's a +9V square wave. If the vehicle wants to charge, an additional voltage divider brings the voltage down to +6V.
    3. This square wave is also sent through comparators (this is in electrical parallel with the vehicle's voltage dividers). As the voltages change, the comparators report either a high or low output...this is fed into the microcontroller as 1s and 0s as a parallel line of eight inputs.
    4. Because the square wave is going through the comparators, the comparators only have useful outputs whenever the square wave is high...if it's low, every output is low and no information is there.
    5. What I need is the microcontroller to basically say "Ok, the square wave is high. Take a look at the comparators, and if the car wants to charge (as indicated by the comparators saying the square wave is at +6V) turn on the relay controlling the 120VAC from the wall. Now wait until the square wave is high again before looking at the comparators again."
    6. I think the problem is that my code is looking at the comparators both when the square wave is positive, and also negative.
    7. The charging is controlled by time of day (only charge at night) and simulated grid health. What we need to do is only turn on the charging at night, and then throttle the charging. This means real time throttling (changing of square wave duty cycle), turning on the 120VAC, and then turning it off when the car is done charging. The simulated grid health is a signal from a DAQ coming in from Labview for demonstration purposes.
    8. I'm not interested in reading the frequency or duty cycle of the wave the microcontroller is creating. I'm trying to get the code to only run when the square wave is positive, so that the microcontroller only looks at the comparators when they have usable outputs.

    I've included the schematic of what we're doing and a block diagram. I hope this is coming across as understandable, if not then let me know and I'll try to clear up what's going on.
    1024 x 576 - 65K
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-23 22:56
    OK, much clearer now. Thanks. So the input is only valid while the wave is high. That doesn't leave much time (in SPIN). In that case I suggest something like
    waitpne(|<cpmon, |<cpmon, 0)
      waitpeq(|<cpmon, |<cpmon, 0)
      outb := ina                       ' grab all 32 bits
    
    in order to get the high data as soon as possible. You may ask why I'm using outb instead of e.g. temp. Special registers (like outb) can be addressed by bit, e.g. you can do if outb[20] to check the state of bit 20. Best thing - I think - is to get the sync issue sorted first.
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-23 23:03
    Can you guarantee that the comparator values are valid after 180 cycles (2.25us)?
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-02-24 00:57
    kuroneko wrote: »
    OK, much clearer now. Thanks. So the input is only valid while the wave is high.

    Exactly. I'm glad that I was able to explain that.
    That doesn't leave much time (in SPIN).

    I was worried about this...I was wondering just how long it took to execute all this code, and was worried I was getting to the limits of what SPIN (instead of PASM) could do.
    In that case I suggest something like
    waitpne(|<cpmon, |<cpmon, 0)
      waitpeq(|<cpmon, |<cpmon, 0)
      outb := ina                       ' grab all 32 bits
    
    in order to get the high data as soon as possible.

    I somewhat understand what you're doing here, but I've been having one heck of a time figuring out whether waitpne and waitpeq are waiting until high or waiting until low. I've read the SPIN manual and it's just not clicking...could you walk me through this code that you suggested? Additionally, could you suggest where to put this code? I'm assuming I would remove POSedge detection and use this instead...would it go all in one spot, above the logic portion of my code?
    You may ask why I'm using outb instead of e.g. temp. Special registers (like outb) can be addressed by bit, e.g. you can do if outb[20] to check the state of bit 20. Best thing - I think - is to get the sync issue sorted first.

    I also somewhat understand this, but need some clarification. Does the special register bout look at all the I/O pins, and bit 20 is pin 19? Or is it something more complicated than that? I'll read through the SPIN manual looking for info on this special register. If you have suggestions for where to look, I am all ears. I notice you're in Japan, so I'm trying to fight our time difference and ask questions I can look up during my tomorrow (hence my 1am pacific time post). What I mean is, I will do my own independent research but if I perchance get a message from you tomorrow before I start, it may be helpful instead of waiting a day for a response.

    Thanks so much for helping me with this, I greatly appreciate it!
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-02-24 00:59
    kuroneko wrote: »
    Can you guarantee that the comparator values are valid after 180 cycles (2.25us)?

    Do you mean, can I guarantee that my comparator values are past transition times and are steady high by 180 cycles? I believe I can, but I will fire up the oscilloscope tomorrow and verify that I can guarantee this. If this isnt' what you mean, please let me know what you mean and I'll figure it out. Thanks!
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-24 01:03
    I believe I can, but I will fire up the oscilloscope tomorrow and verify that I can guarantee this. If this isnt' what you mean, please let me know what you mean and I'll figure it out. Thanks!
    Easy answer first :) It's not a problem as such. As I said the current minimum duty cycle uses about 7k2 cycles for high. So if your h/w isn't fast enough you can put e.g. a waitcnt(1000+cnt) just in front of the sample which moves the sample point slightly more to the middle of the high part. No harm done.
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-24 01:19
    I somewhat understand what you're doing here, but I've been having one heck of a time figuring out whether waitpne and waitpeq are waiting until high or waiting until low. I've read the SPIN manual and it's just not clicking...could you walk me through this code that you suggested?
    OK, waitpxx(V, M, 0) reads ina performs a bit-wise AND with Mask and the compares it against Value. If the condition is true it continues (e.g. waitpne(0, 0, 0) blocks forever). The last parameter designates ina(0) or inb(1). The prop 1 only has the former implemented so 0 is effectively hardwired.
    waitp[COLOR="red"]ne[/COLOR](|<cpmon, |<cpmon, 0)
      waitp[COLOR="red"]eq[/COLOR](|<cpmon, |<cpmon, 0)
    
    The first line monitors bit 15 (by using bit masks, 1 << 15 or short |< 15), if it's 1 then the condition is false (V <> (M & |<15)), it blocks. When bit 15 goes south M & ina becomes 0 which is not equal to V, execution continues. So line 1 blocks until it sees 0, the second (opposite condition, eq vs ne) will now block until bit 15 is 1. Which is the low-high transition we are after.
    Additionally, could you suggest where to put this code? I'm assuming I would remove POSedge detection and use this instead...would it go all in one spot, above the logic portion of my code?
    Yes, it would effectively replace the if statement. As you get 1000 transitions per second and you want something like 10Hz updates the blocking nature shouldn't be an issue. You may want to slow down the loop artificially (e.g. with waitcnt).
    I also somewhat understand this, but need some clarification. Does the special register outb look at all the I/O pins, and bit 20 is pin 19? Or is it something more complicated than that?
    The prop has 32 I/O pins (0..31). By reading ina you get each pin assigned to a bit in that register. Accessing outb[20] (after assignment) is bit 20 (the 21st one) or for a DIP prop pin 25 (see data sheet). You can access outb[0]..outb[31]. Hope that's not too confusing.
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-24 05:25
    I'll attach an example of what I mean re: loop slow down. The main method could look like this:
    PUB main | granularity, base
    
      dira[17]~~                                            ' debug only
      
      granularity := clkfreq/10
      base        := cnt
      
      cognew(SquareWave(cpmon, clkfreq/11000, clkfreq/1000), @swStack{0})
    
      repeat
      ' main loop action
    
      ' check input(s)
        [COLOR="red"]waitpne(cpmon_m, cpmon_m, 0)                        ' |
        waitpeq(cpmon_m, cpmon_m, 0)                        ' wait for low-high edge[/COLOR]
    
        [COLOR="green"]waitcnt(1000+cnt)                                   ' shift sample point[/COLOR]
        outb := ina                                         ' sample 32 bit
        [COLOR="orange"]if outb[cpmon]                                      ' monitor pin
          !outa[17]                                         ' toggle pin if we read high[/COLOR]
        [COLOR="blue"]waitcnt(base += granularity)                        ' slow down[/COLOR]
    
    Update is defined as 10Hz (granularity/base). A fake square wave is started (7k2 cycles high). Inside the loop some main action happens (this may require granularity adjustments). We then wait for a low-high edge and slightly delay the sample point (try 7000 to see the difference). If the square wave input is high we toggle a diagnostic output (demoboard LED). Then we lock ourself to a 10Hz raster.

    Because the square wave can be switched off you want to guard the edge-detection by something like if wave_active which should cover all code up to but excluding the waitcnt(base += granularity).
  • defcon.klaxondefcon.klaxon Posts: 8
    edited 2011-03-08 16:42
    Thanks for the info kuroneko! I have been busy with other school work for the past few weeks but I am back to Propeller programming. I'll give this code a shot and see if I can get it to do what I want, and I'll let you know how it goes. Thanks for your time and the info!
Sign In or Register to comment.