This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to synchronize PWM with external event

As for dimmer applications neccessary, a pwm signal with variable duty-cycle must be generated to drive a triac. But to be synchronized with the mains' zero crossing, the pwm cycle must be started by a GPIO event from a zero-crossing sensor (optocoupler). What would be the best approach to solve this problem? Has anybody done a similar thing before?

Parents
  • I've done exactly this and went through quite a few iterations to get something which worked reliably.

    First thing - if you want to use full half-cycles - using a triac with a zero cross turn-on circuit saves a lot of problems. You have plenty of time during one cycle to work out whether you want to turn on for the next one, you don't have to try and get the GPIO on event dead right. Doing this gives you very accurate power with the caveat that you are limited to a resolution of 2x mains frequency. I wish I'd started there because that's actually more than the resolution I needed for my application.

    Secondly, if you want to get an event trigger close to the actual zero cross you need a sensor which produces an on pulse fairly towards the start of the cycle and importantly produces a fast-rising one, else the GPIO line bounces. I use one PPI to turn off the GPIOTE as soon as the pulse is registered to stop any bouncing at all, it's turned on again during an interrupt service routine before the next one. For me, an FOD817 (C or D) with about 150k current limiting resistors on the mains side and a 100k pullup on the nRF side gives a good pulse with at least 48% duty cycle. That's for 240v and the resistors get warm! Increasing resistance too much made the edges of the pulse too wide, duty cycle fell closer to 40% and the bouncing was horrible.

    I found it best to work 1/2 a cycle ahead, setting up everything to be triggered by the next GPIOTE event using PPI during the interrupt service routine from the last one, then letting PPI actually do the job for me later. Obviously turning things off is easier, you just turn it off at any point and the triac will actually shut down at the next zero cross.

Reply
  • I've done exactly this and went through quite a few iterations to get something which worked reliably.

    First thing - if you want to use full half-cycles - using a triac with a zero cross turn-on circuit saves a lot of problems. You have plenty of time during one cycle to work out whether you want to turn on for the next one, you don't have to try and get the GPIO on event dead right. Doing this gives you very accurate power with the caveat that you are limited to a resolution of 2x mains frequency. I wish I'd started there because that's actually more than the resolution I needed for my application.

    Secondly, if you want to get an event trigger close to the actual zero cross you need a sensor which produces an on pulse fairly towards the start of the cycle and importantly produces a fast-rising one, else the GPIO line bounces. I use one PPI to turn off the GPIOTE as soon as the pulse is registered to stop any bouncing at all, it's turned on again during an interrupt service routine before the next one. For me, an FOD817 (C or D) with about 150k current limiting resistors on the mains side and a 100k pullup on the nRF side gives a good pulse with at least 48% duty cycle. That's for 240v and the resistors get warm! Increasing resistance too much made the edges of the pulse too wide, duty cycle fell closer to 40% and the bouncing was horrible.

    I found it best to work 1/2 a cycle ahead, setting up everything to be triggered by the next GPIOTE event using PPI during the interrupt service routine from the last one, then letting PPI actually do the job for me later. Obviously turning things off is easier, you just turn it off at any point and the triac will actually shut down at the next zero cross.

Children
  • I tried it with pwm and while shifting the duty cycle from 1 to 99% to delay the triac firing in order to phase-cut the half-wave. The problem is that the 50Hz from the mains is not as stable as the pwm and I need to restart the pwm from time to time. As the pwm needs a complete cycle to restart, flickering appears at output. Could you share some code with me showing your solution in detail? I would appreciate this very much. I am using the VOL628A, 33K half watt at both 230V inputs to get the zero crossing, no warming so far. Could not see bounces at the GPIO.

  • Not sure you're going to hit perfection on this. I found the harder I tried to stay perfectly synched all the time, the worse the effects of a small error was. if I made the detector less-sensitive, I had issues, if I made it more sensitive, I had different issues. For me (I'm using it to control an oven) the oven going on and off put enough spike in the mains to break it.

    Where I ended up was deciding the mains was really pretty stable over even a fairly long period, so I ended up making the controlling timer run independently just on its own and then use another PPI off the detector to slowly (over the course of seconds) change the period of the main timer to keep it basically in sync I started trying to control the thing perfectly on every 1/2 cycle, but I don't need to (you do I think) and eventually moved to running full 1/2 cycles in trains to keep a running average of power ..

  • .. correct. Eg if I want 50% power I can run the triac for 32 on cycles and then 32 off cycles, it's an oven, it really doesn't care that much, if you're trying to get a flicker-free light, you do care.

    So the closest I got to 'perfect' control was separating the timer which controlled the triac from the one which measured the zero cross and slewing the former slowly as the latter changed. Slowly enough to filter out transients, fast enough to actually follow real changes. I suspect if I hooked that up to a light, as good as I ever got it, I'd see some flicker. Oh and I totally avoided anything under about 10% duty, it was too easy to be a little late with the off control signal and end up with full-on cycles randomly, it was a mess.

Related