Bar Logo 3.8/7.6 kw Totem pole Demonstration Application (Part-No. (not specified))
 
Content
     
Loading...
Searching...
No Matches
vac_monitor.c
Go to the documentation of this file.
1
11/*
12 (c) 2022 Microchip Technology Inc. and its subsidiaries. You may use this
13 software and any derivatives exclusively with Microchip products.
14
15 THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
16 EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
17 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
18 PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
19 WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
20
21 IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
22 INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
23 WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
24 BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
25 FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
26 ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
27 THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
28
29 MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
30 TERMS.
31 */
32
37#include <stdint.h>
38#include <xc.h>
39#include "vac_monitor.h"
40#include "vac_monitor_typedef.h"
41
42//------------------------------------------------------------------------------
43// #defines for thresholds
44//------------------------------------------------------------------------------
45#define VACM_DC_ACCEPTANCE_THRESHOLD (200)
46#define VACM_DC_REJECTION_THRESHOLD (100)
47#define VACM_AC_DROP_VOLTAGE_THRESHOLD (100)
48#define VACM_AC_DROP_PERSISTANCE_COUNT (2)
49#define VACM_POLARITY_HYSTERESIS (10)
50#define VCAM_ZERO_CROSS_THRESHOLD (50)
51#define VCAM_STARTUP_HALF_GRID_CYCLE_COUNT (20)
52
53//------------------------------------------------------------------------------
54// private function declarations
55//------------------------------------------------------------------------------
56void __attribute__((always_inline)) vacm_state_standby(struct VACM_s* vacm_obj);
57void __attribute__((always_inline)) vacm_state_dc_detect(struct VACM_s* vacm_obj);
58void __attribute__((always_inline)) vacm_state_dc_mode(struct VACM_s* vacm_obj);
59void __attribute__((always_inline)) vacm_state_wait_for_zc(struct VACM_s* vacm_obj);
60void __attribute__((always_inline)) vacm_state_ac_sync(struct VACM_s* vacm_obj);
61void __attribute__((always_inline)) vacm_state_online(struct VACM_s* vacm_obj);
62void __attribute__((always_inline)) vacm_state_ac_drop(struct VACM_s* vacm_obj);
63void __attribute__((always_inline)) vacm_vin_average(struct VACM_s* vacm_obj);
64void __attribute__((always_inline)) vacm_polarity_update(struct VACM_s* vacm_obj);
65void __attribute__((always_inline)) vacm_zerocross_detect(struct VACM_s* vacm_obj);
66void __attribute__((always_inline)) vacm_vloop_feedforward_update(struct VACM_s* vacm_obj);
67void __attribute__((always_inline)) vacm_acok_assert(struct VACM_s* vacm_obj);
68void __attribute__((always_inline)) vacm_capture_input(struct VACM_s* vacm_obj);
69
70void __attribute__((always_inline)) vacm_timebase_update(struct VACM_s* vacm_obj);
71bool __attribute__((always_inline)) vacm_dc_input_accept(struct VACM_s* vacm_obj);
72void __attribute__((always_inline)) vacm_uv_ov_test(struct VACM_s* vacm_obj);
73void __attribute__((always_inline)) vacm_reset_state_machine(struct VACM_s* vacm_obj);
74
75
86{
87 vacm_obj->avgcalc_buffer.acc = 0;
88 vacm_obj->avgcalc_buffer.counter = 0;
89 vacm_obj->vin.avg = 0;
90 vacm_obj->status.value = 0; // clear all flags
91 vacm_obj->timebase.ac_drop_timer = 0;
92 vacm_obj->timebase.half_cycle_timer = 0;
93 vacm_obj->timebase.startup_counter = 0;
94 vacm_obj->timebase.vin_present_counter = 0;
95 vacm_obj->timebase.zero_cross_timer = 0;
96 vacm_obj->timebase.dc_loss_counter = 0;
97 vacm_obj->timebase.dc_present_counter = 0;
98}
99
100
110void vacm_reset_state_machine(struct VACM_s* vacm_obj)
111{
112 vacm_obj->state = VACM_STATE_STANDBY;
113}
114
115
125void vacm_state_machine(struct VACM_s* vacm_obj)
126{
127 vacm_capture_input(vacm_obj);
129 switch (vacm_obj->state)
130 {
132 vacm_state_standby(vacm_obj);
133 break;
134
136 vacm_state_dc_detect(vacm_obj);
137 break;
138
140 vacm_state_dc_mode(vacm_obj);
141 break;
142
144 vacm_state_wait_for_zc(vacm_obj);
145 break;
146
148 vacm_state_ac_sync(vacm_obj);
149 break;
150
152 vacm_state_online(vacm_obj);
153 break;
154
156 vacm_state_ac_drop(vacm_obj);
157 break;
158
159 default:
160 vacm_obj->state = VACM_STATE_STANDBY;
161 break;
162 }
163}
164
165
174void __attribute__((always_inline)) vacm_state_standby(struct VACM_s* vacm_obj)
175{
176 vacm_vin_average(vacm_obj);
177 if ((vacm_obj->vin.avg) && (!vacm_obj->fault.bits.uv))
178 {
179 // there is some Vin present
180
181 // clear zc timeout flag, as re-starting zero cross detection
182 // also reset fmin and fmax flags, as will be re-measuring the line
183 // frequency.
184 vacm_obj->fault.bits.zc_timeout = false;
185 vacm_obj->fault.bits.fmax = false;
186 vacm_obj->fault.bits.fmin = false;
187
188 // proceed to next state
189 vacm_obj->state = VACM_STATE_DCDETECT;
190 }
191}
192
193
203void __attribute__((always_inline)) vacm_state_dc_detect(struct VACM_s* vacm_obj)
204{
205 vacm_vin_average(vacm_obj);
206 bool dc_detect_processing_complete = vacm_dc_input_accept(vacm_obj);
207
208 if (vacm_obj->fault.value)
209 {
210 // fault present, reset state machine
212 vacm_obj->state = VACM_STATE_STANDBY;
213 }
214 else if (dc_detect_processing_complete)
215 {
216 if (vacm_obj->status.bits.dc_mode)
217 {
218 // DC mode
219 vacm_obj->state = VACM_STATE_DCMODE;
220 }
221 else
222 {
223 // AC mode
224 vacm_obj->state = VACM_STATE_WAIT_ZC;
225 }
226 }
227}
228
229
242void __attribute__((always_inline)) vacm_state_dc_mode(struct VACM_s* vacm_obj)
243{
244 vacm_vin_average(vacm_obj);
245 if ((vacm_obj->fault.value) || (vacm_obj->vin.rectified < VACM_DC_REJECTION_THRESHOLD))
246 {
247 // fault, or signal looks like it could be AC, so reset state machine
249 vacm_obj->state = VACM_STATE_STANDBY;
250 }
251}
252
253
264void __attribute__((always_inline)) vacm_state_wait_for_zc(struct VACM_s* vacm_obj)
265{
266 // wait for next zero crossing
267 vacm_vin_average(vacm_obj);
268 vacm_zerocross_detect(vacm_obj);
269 vacm_polarity_update(vacm_obj);
270
271 if (vacm_obj->fault.value)
272 {
274 vacm_obj->state = VACM_STATE_STANDBY;
275 }
276 else if (vacm_obj->status.bits.end_of_cycle)
277 {
278 // zero crossing has been detected
279
280 // going to start to measure AC line cycle from this point
281 // so clear the cycle timer
282 vacm_obj->timebase.half_cycle_timer = 0;
283
284 vacm_obj->state = VACM_STATE_ACSYNC;
285 }
286}
287
288
301void __attribute__((always_inline)) vacm_state_ac_sync(struct VACM_s* vacm_obj)
302{
303 vacm_vin_average(vacm_obj);
304 vacm_zerocross_detect(vacm_obj);
305 vacm_polarity_update(vacm_obj);
306 vacm_timebase_update(vacm_obj);
307 vacm_acok_assert(vacm_obj);
308
309 if (vacm_obj->fault.value)
310 {
311 // some fault present. Go back to standby
313 vacm_obj->state = VACM_STATE_STANDBY;
314 }
315 else if (vacm_obj->status.bits.ac_ok)
316 {
317 // AC OK flag is set, go to next state
318 vacm_obj->state = VACM_STATE_ONLINE;
319 }
320}
321
322
335void __attribute__((always_inline)) vacm_state_online(struct VACM_s* vacm_obj)
336{
337 vacm_vin_average(vacm_obj);
338 vacm_zerocross_detect(vacm_obj);
339 vacm_polarity_update(vacm_obj);
340 vacm_timebase_update(vacm_obj);
341
342 if (vacm_obj->fault.value)
343 {
344 // some fault is set. if it is
345 // a) zero cross timeout
346 // b) fmax
347 // then it is potentially an AC drop
348 // otherwise, reset the state machine
349 if ((vacm_obj->fault.bits.fmax) || (vacm_obj->fault.bits.zc_timeout))
350 {
351 // potentially an AC drop
352 vacm_obj->status.bits.ac_drop = true;
353
354 if (vacm_obj->fault.bits.zc_timeout)
355 {
356 // AC drop has already been present for ZC_TIMEOUT seconds
357 // so preset ac drop timer accordingly
358 vacm_obj->timebase.ac_drop_timer = (ZC_TIMEOUT_TICKS + 1);
359 }
360 else
361 {
362 vacm_obj->timebase.ac_drop_timer = 0; // start at 0
363 }
364
365 // clear zero cross, as during AC drop
366 // even though in zero cross region, it is artificial
367 vacm_obj->status.bits.zero_cross = false;
368
369 // not running Vin average calculation in the next state
370 // as it will trigger a UV fault
371 // so clear the accumulator and counter used to calculate the average
372 vacm_obj->avgcalc_buffer.acc = 0;
373 vacm_obj->avgcalc_buffer.counter = 0;
374
375 vacm_obj->state = VACM_STATE_ACDROP; // measure length of AC drop
376 }
377 else
378 {
379 // OV, UV or fmin fault. Reset state machine
381 vacm_obj->state = VACM_STATE_STANDBY;
382 }
383 }
384}
385
386
399void __attribute__((always_inline)) vacm_state_ac_drop(struct VACM_s* vacm_obj)
400{
401 vacm_obj->timebase.ac_drop_timer++;
402
403 // if there is some voltage present, then clear flag
405 {
406 // some input voltage is present
408 {
409 vacm_obj->timebase.vin_present_counter = 0;
410
411 // AC drop condition no longer present, so clear flag and timer
412 vacm_obj->status.bits.ac_drop = false;
413 vacm_obj->timebase.ac_drop_timer = 0;
414
415 // reset cycle timer
416 vacm_obj->timebase.half_cycle_timer = 0;
417
418 // clear fault flags
419 vacm_obj->fault.bits.fmax = false;
420 vacm_obj->fault.bits.zc_timeout = false;
421
422 vacm_obj->state = VACM_STATE_WAIT_ZC; // next state
423 }
424 }
425 else
426 {
427 // AC drop still present
428 vacm_obj->timebase.vin_present_counter = 0;
429
431 {
432 // AC drop is present for too long, so reset state machine
434 vacm_obj->state = VACM_STATE_STANDBY;
435 }
436 }
437}
438
439
463void __attribute__((always_inline)) vacm_vin_average(struct VACM_s* vacm_obj)
464{
465 //----------------------------------------------------------------------------
466 // average (the rectified) ADC readings over a half line cycle
467 //----------------------------------------------------------------------------
468 vacm_obj->avgcalc_buffer.acc += vacm_obj->vin.rectified;
469 vacm_obj->avgcalc_buffer.counter++;
470
471 // check if a 1/2 line half cycle has elapsed
472 // vacm_obj->avgcalc_buffer.counter_reset should be equal to the length of a 1/2 line cycle
473 // as measured in IRQ ticks
474 if (vacm_obj->avgcalc_buffer.counter >= vacm_obj->avgcalc_buffer.counter_reset)
475 {
476 // compute the average of the rectified input voltage over a half line cycle
477 vacm_obj->vin.avg_prev = vacm_obj->vin.avg; // store old value
478 vacm_obj->vin.avg = (uint16_t) __builtin_divud(vacm_obj->avgcalc_buffer.acc, vacm_obj->avgcalc_buffer.counter);
479
480 vacm_obj->avgcalc_buffer.acc = 0;
481 vacm_obj->avgcalc_buffer.counter = 0;
482
483 // check UV and OV
484 vacm_uv_ov_test(vacm_obj);
485
486 //----------------------------------------------------------------------
487 // compute Vavg squared. This is used to compute Vin/Vavg^2
488 // this is feed-forward term for the voltage loop on the main controller
489 // note that vacm_obj->vin.avg is 11 bit (not 12-bit)
490 // because it is based on the rectified ADC measurement
491 //----------------------------------------------------------------------
492 uint32_t vin_avg_sqrd = __builtin_muluu(vacm_obj->vin.avg, vacm_obj->vin.avg); // 11bit * 11bit = 22bit;
493 vacm_obj->vin.avg_sqrd = (uint16_t) (vin_avg_sqrd >> 6); // 22bit / 6bit = 16bit
494 }
495}
496
497
507void __attribute__((always_inline)) vacm_polarity_update(struct VACM_s* vacm_obj)
508{
509 //----------------------------------------------------------------------------
510 // determine polarity of AC input signal
511 //----------------------------------------------------------------------------
512 // AC input = 180 degrees out of phase with sensed signals from op-amps
513 // so if
514 // >> sensed signal is < (raw AC - hysteresis): AC input is positive
515 // >> sensed signal is > (raw AC + hysteresis): AC input is negative
516 int16_t offset = (int16_t) * vacm_obj->vin.ptr_offset;
517 if (vacm_obj->vin.raw < (offset - VACM_POLARITY_HYSTERESIS))
518 {
519 vacm_obj->status.bits.polarity_pos = true;
520 }
521 else if (vacm_obj->vin.raw > (offset + VACM_POLARITY_HYSTERESIS))
522 {
523 vacm_obj->status.bits.polarity_pos = false;
524 }
525}
526
527
537void __attribute__((always_inline)) vacm_zerocross_detect(struct VACM_s* vacm_obj)
538{
539 // 1. coming into zero cross region from below
540 // -> slope = 1, polarity = 0
541 // 2. coming out of zero cross region from below
542 // -> slope = 1, polarity = 1
543 // 3. coming into zero cross region from above
544 // -> slope = 0, polarity = 1
545 // 4. coming out of zero cross region from above
546 // -> slope = 0, polarity = 0
547
548 // hence
549 // >> when coming into zero cross region: slope != polarity
550 // >> when coming out of zero cross region: slope = polarity
551
552 // check if coming into zero cross region
553 if ((vacm_obj->vin.rectified < VCAM_ZERO_CROSS_THRESHOLD) && // Vin < threshold
554 (vacm_obj->status.bits.slope_pos != vacm_obj->status.bits.polarity_pos) &&
555 (!vacm_obj->status.bits.zero_cross)) // haven't been in zero cross region
556 {
557 vacm_obj->status.bits.zero_cross = true; // in zero cross region
558 vacm_obj->status.bits.end_of_cycle = true; // end of cycle has occurred (should happen once per 1/2 period)
559 }
560 // check if coming out of zero cross region
561 else if ((vacm_obj->vin.rectified > VCAM_ZERO_CROSS_THRESHOLD) && // Vin > threshold
562 (vacm_obj->status.bits.slope_pos == vacm_obj->status.bits.polarity_pos) &&
563 (vacm_obj->status.bits.zero_cross)) // have been in zero cross region
564 {
565 vacm_obj->status.bits.end_of_cycle = false;
566 // stay in zero cross region for minimum amount of time
567 if (vacm_obj->timebase.zero_cross_timer >= ZC_TMIN_TICKS)
568 {
569 vacm_obj->status.bits.zero_cross = false; // no longer in zero cross region
570 }
571 }
572 else
573 {
574 vacm_obj->status.bits.end_of_cycle = false;
575 }
576
577 //----------------------------------------------------------------------------
578 // measure the length of time in zero cross range
579 //----------------------------------------------------------------------------
580 if (vacm_obj->status.bits.zero_cross)
581 {
582 vacm_obj->timebase.zero_cross_timer++;
584 {
585 vacm_obj->timebase.zero_cross_timer = 0;
586 vacm_obj->fault.bits.zc_timeout = true;
587 vacm_obj->status.bits.zero_cross = false; // reset zero cross flag
588 }
589 }
590 else
591 {
592 vacm_obj->timebase.zero_cross_timer = 0;
593 vacm_obj->fault.bits.zc_timeout = false;
594 }
595}
596
597
608void __attribute__((always_inline)) vacm_vloop_feedforward_update(struct VACM_s* vacm_obj)
609{
610 if (vacm_obj->vin.avg_sqrd > 0) // check against 0 as dividing by this number
611 {
612 // rectified_scaled: 11bit * 17bit = 28 bit
613 uint32_t rectified_scaled = ((uint32_t) vacm_obj->vin.rectified) << 17;
614
615 // vacm_obj->vin.vloop_ff: 28bit / 16bit = 12bit
616 vacm_obj->vin.vloop_ff = (uint16_t) (__builtin_divud(rectified_scaled, vacm_obj->vin.avg_sqrd));
617 }
618}
619
620
631void __attribute__((always_inline)) vacm_timebase_update(struct VACM_s* vacm_obj)
632{
633 vacm_obj->timebase.half_cycle_timer++;
634
635 if (vacm_obj->status.bits.end_of_cycle)
636 {
637 // "end_of_cycle" set on the pass where a zero crossing is detected
638 // so a "cycle" is defined actually a 1/2 of a AC line period
639 // store measured period (actually its a measured of a half of the line cycle)
640 vacm_obj->timebase.half_cycle = vacm_obj->timebase.half_cycle_timer;
641 vacm_obj->timebase.half_cycle_timer = 0;
642
643 // check against Fmax. Fmax = min period, so check if ticks < min period
644 // in ticks. Divide by 2 as measuring over 1/2 cycle instead of full cycle
645 if (vacm_obj->timebase.half_cycle < (FIN_MAX_TICKS >> 1))
646 {
647 vacm_obj->fault.bits.fmax = true;
648 vacm_obj->fault.bits.fmin = false;
649 }
650 else
651 {
652 // measured line frequency is within limits
653 // update reset value of timer used to calculate average of Vin rectified
654 // only update vin_average_counter_reset when get a valid period measurement
655 vacm_obj->avgcalc_buffer.counter_reset = vacm_obj->timebase.half_cycle;
656
657 // clear fault flags
658 vacm_obj->fault.bits.fmin = false;
659 vacm_obj->fault.bits.fmax = false;
660 }
661 }
662 else
663 {
664 // not end of cycle
665 // check against Fmin (max period)
666 // divide by 2 as measuring over a 1/2 AC line cycle
667 if (vacm_obj->timebase.half_cycle_timer > (FIN_MIN_TICKS >> 1))
668 {
669 vacm_obj->timebase.half_cycle_timer = 0; // reset timer
670 vacm_obj->fault.bits.fmin = true;
671 vacm_obj->fault.bits.fmax = false;
672 }
673 }
674}
675
676
685void __attribute__((always_inline)) vacm_acok_assert(struct VACM_s* vacm_obj)
686{
687 // set AC OK flag when Vin has been in a settled range for 10 consecutive AC line cycles
688 // can determine by checking if the average half period value doesn't move so much between periods
689 if (vacm_obj->status.bits.end_of_cycle)
690 {
691 if (!vacm_obj->status.bits.ac_ok)
692 {
693 // check how much Vin has changed from 1 half-period to the next
694 int16_t delta_vin = abs((int16_t) (vacm_obj->vin.avg) - (int16_t) (vacm_obj->vin.avg_prev));
695
696 if (delta_vin < ((vacm_obj->vin.avg) >> 4))
697 {
698 // average line voltage is stable
700 {
701 vacm_obj->status.bits.ac_ok = true;
702 vacm_obj->timebase.startup_counter = 0;
703 }
704 }
705 else
706 {
707 // Vin is moving by too much, so reset startup counter
708 vacm_obj->timebase.startup_counter = 0;
709 }
710 }
711 }
712}
713
714
725void __attribute__((always_inline)) vacm_capture_input(struct VACM_s* vacm_obj)
726{
727 // read the ADC result
728 vacm_obj->vin.raw_prev = vacm_obj->vin.raw; // store previous value
729
730 int16_t vac_buffer = (int16_t) * vacm_obj->vin.ptr_adcbuf;
731 vacm_obj->vin.raw = (uint16_t) vac_buffer;
732
733 // rectify
734 int16_t offset = (int16_t) * vacm_obj->vin.ptr_offset;
735 vacm_obj->vin.rectified = abs(vac_buffer - offset);
736
737 // clamp at 11 bit value
738 if (vacm_obj->vin.rectified > 2047)
739 {
740 vacm_obj->vin.rectified = 2047;
741 }
742
743 // determine slope of input
744 // used for zero crossing detection
745 // account for 180 degree phase shift between AC input and sensed voltage
746 if (vacm_obj->vin.raw < vacm_obj->vin.raw_prev)
747 {
748 // sensed signal is descending, so actual AC line is ascending
749 vacm_obj->status.bits.slope_pos = true;
750 }
751 else
752 {
753 // sensed signal is ascending, so actual AC line is descending
754 vacm_obj->status.bits.slope_pos = false;
755 }
756}
757
758
767bool __attribute__((always_inline)) vacm_dc_input_accept(struct VACM_s* vacm_obj)
768{
769 bool processing_complete = false; // return value
770
771 // Check if the input voltage is above the user-specified minimum threshold
772 // for a period of at least four maximum grid periods
774 {
775 vacm_obj->timebase.dc_loss_counter = 0;
776 vacm_obj->timebase.dc_present_counter++;
777 }
778
779 // If input voltage disappears, set time-out and clear DC Mode flag bits
780 // To indicate potential AC input voltage or grid loss
781 else if (vacm_obj->vin.rectified < VACM_DC_REJECTION_THRESHOLD)
782 {
783 vacm_obj->timebase.dc_loss_counter++;
784 vacm_obj->timebase.dc_present_counter = 0;
785 }
786
787 // If the time-base counter exceeds the limit of at least four half periods, Accept DC mode
789 {
790 // signal looks like DC
791 vacm_obj->timebase.dc_present_counter = 0;
792
793 vacm_obj->status.bits.dc_mode = true; // Set DC Mode flag bit
794
795 // set other status flags appropriately
796 vacm_obj->status.bits.ac_ok = true;
797 vacm_obj->status.bits.ac_drop = false;
798 vacm_obj->status.bits.end_of_cycle = false;
799 vacm_obj->status.bits.polarity_pos = true;
800 vacm_obj->status.bits.slope_pos = false;
801 vacm_obj->status.bits.zero_cross = false;
802
803 // tell calling function that a decision has been made
804 processing_complete = true;
805 }
806
807 // if voltage drops below detection threshold more that 1/2 of
808 // the min zero cross time, then signal must be considered as AC
809 else if (vacm_obj->timebase.dc_loss_counter > (max((ZC_TMIN_TICKS >> 1), 1)))
810 {
811 // signal looks like it might be AC
812 vacm_obj->timebase.dc_loss_counter = 0;
813 vacm_obj->status.bits.dc_mode = false; // clear DC Mode flag bit
814
815 // tell calling function that a decision has been made
816 processing_complete = true;
817 }
818
819 // While test is on-going, keep DC mode and period time-base timeout flag bits cleared
820 else
821 {
822 vacm_obj->status.bits.dc_mode = false;
823 processing_complete = false; // tell calling function that a decision has been made
824 }
825
826 return (processing_complete);
827}
828
829
838void __attribute__((always_inline)) vacm_uv_ov_test(struct VACM_s* vacm_obj)
839{
840 // check Vin against UV thresholds
841 if (!vacm_obj->fault.bits.uv)
842 {
843 // Vin not UV
844 // if Vin drops below trigger threshold, set UV flag
845 if (vacm_obj->vin.avg < UV_TRIG_ADC)
846 {
847 vacm_obj->fault.bits.uv = true;
848 }
849 }
850 else
851 {
852 // Vin in UV
853 // if Vin goes above clear threshold, clear UV flag
854 if (vacm_obj->vin.avg > UV_CLR_ADC)
855 {
856 vacm_obj->fault.bits.uv = false;
857 }
858 }
859
860 // check against OV thresholds
861 if (!vacm_obj->fault.bits.ov)
862 {
863 // not in OV
864 // if Vin > OV trigger threshold, set OV fault flag
865 if (vacm_obj->vin.avg > OV_TRIG_ADC)
866 {
867 vacm_obj->fault.bits.ov = true;
868 }
869 }
870 else
871 {
872 // in OV
873 // if Vin < OV clear threshold, clear OV fault flag
874 if (vacm_obj->vin.avg < OV_CLR_ADC)
875 {
876 vacm_obj->fault.bits.ov = false;
877 }
878 }
879}
void vacm_polarity_update(struct VACM_s *vacm_obj)
bool vacm_dc_input_accept(struct VACM_s *vacm_obj)
#define VACM_DC_ACCEPTANCE_THRESHOLD
Definition vac_monitor.c:45
void vacm_state_standby(struct VACM_s *vacm_obj)
#define VCAM_ZERO_CROSS_THRESHOLD
Definition vac_monitor.c:50
void vacm_vloop_feedforward_update(struct VACM_s *vacm_obj)
void vacm_state_machine(struct VACM_s *vacm_obj)
void vacm_state_dc_detect(struct VACM_s *vacm_obj)
void vacm_vin_average(struct VACM_s *vacm_obj)
void vacm_state_wait_for_zc(struct VACM_s *vacm_obj)
#define VCAM_STARTUP_HALF_GRID_CYCLE_COUNT
Definition vac_monitor.c:51
void vacm_acok_assert(struct VACM_s *vacm_obj)
void vacm_capture_input(struct VACM_s *vacm_obj)
void vacm_reset_phase_monitor_object(struct VACM_s *vacm_obj)
Definition vac_monitor.c:85
void vacm_state_ac_sync(struct VACM_s *vacm_obj)
void vacm_state_dc_mode(struct VACM_s *vacm_obj)
void vacm_state_ac_drop(struct VACM_s *vacm_obj)
#define VACM_DC_REJECTION_THRESHOLD
Definition vac_monitor.c:46
void vacm_timebase_update(struct VACM_s *vacm_obj)
void vacm_reset_state_machine(struct VACM_s *vacm_obj)
#define VACM_POLARITY_HYSTERESIS
Definition vac_monitor.c:49
#define VACM_AC_DROP_VOLTAGE_THRESHOLD
Definition vac_monitor.c:47
#define VACM_AC_DROP_PERSISTANCE_COUNT
Definition vac_monitor.c:48
void vacm_zerocross_detect(struct VACM_s *vacm_obj)
void vacm_uv_ov_test(struct VACM_s *vacm_obj)
void vacm_state_online(struct VACM_s *vacm_obj)
header of the VAC
#define max(a, b)
max of 2 integers
Definition vac_monitor.h:69
VAC Types define.
@ VACM_STATE_ACDROP
state #6: AC drop detected
@ VACM_STATE_WAIT_ZC
state #3: wait for first zero crossing
@ VACM_STATE_STANDBY
state #0: wait for launch trigger
@ VACM_STATE_DCMODE
state #2: catch-up state in DC mode, bypassing any further AC analysis of the input voltage
@ VACM_STATE_ONLINE
state #5: normal AC input operation
@ VACM_STATE_DCDETECT
state #1: check if input votlage is DC or AC
@ VACM_STATE_ACSYNC
state #4: startup-step synchronization on first few zero crossings after AC detected
#define UV_CLR_ADC
UV clear threshold converted from Volts to ADC codes.
#define AC_DROP_TIMEOUT_TICKS
AC_DROP_TIMEOUT (seconds) converted to ticks for software timer.
#define DC_ACCEPTANCE_PERIOD_TICKS
DC acceptance period in ticks.
#define FIN_MAX_TICKS
FIN_MAX (Hertz) converted to ticks for software timer.
#define OV_CLR_ADC
OV clear threshold converted from Volts to ADC codes.
#define UV_TRIG_ADC
UV_TRIG (UV trigger threshold) converted from Volts to ADC codes.
#define FIN_MIN_TICKS
FIN_MIN (Hertz) converted to ticks for software timer.
#define ZC_TMIN_TICKS
ZC_TMIN (seconds) converted to ticks for software timer.
#define OV_TRIG_ADC
OV_TRIG_ADC (OV trigger threshold) converted from Volts to ADC codes.
#define ZC_TIMEOUT_TICKS
ZC_TIMEOUT (seconds) converted to ticks for software timer.
bool ac_ok
Bit #2: flag indicating the status of the line voltage
bool zero_cross
Bit #3: flag indicating that we are in the zero cross region.
volatile uint16_t value
bool slope_pos
Bit #6: flag = 1 when ac line slope is positive, 0 when negative
bool polarity_pos
Bit #4: flag = 1 when polarity is positive, 0 when negative.
struct VACM_STATUS_s::@15::@17 bits
bool end_of_cycle
Bit #5: flag indicating that the end of cycle has just occured
bool dc_mode
Bit #1: 1 when Vin = DC, 0 when Vin = AC.
bool ac_drop
Bit #0: flag indicating that an ac drop may have occurred.
struct VACM_FAULT_s::@18::@20 bits
bool zc_timeout
Bit #4: flag indicating that have spent too long in zero cross region
bool fmin
Bit #2: flag indicating that frequency of line voltage < min.
bool uv
Bit #1: flag indicating that magnitude of line voltage > OV threshold.
bool ov
Bit #0: flag indicating that magnitude of line voltage < UV threshold.
bool fmax
Bit #3: flag indicating that frequency of line voltage > max.
uint16_t vloop_ff
‍square of the average input voltage
int16_t * ptr_offset
‍rectified input voltage
uint16_t * ptr_adcbuf
Pointer to register or variable where the value is read from (e.g. ADCBUFx) or written to (e....
uint16_t avg_prev
‍average of the rectified input voltage over 1/2 line cycle
uint16_t raw_prev
‍raw ADC reading of input voltage, before offset removed and rectified
uint16_t avg_sqrd
‍previous reading of average (over 1/2 line cycle)
uint16_t avg
‍pointer to offset upon which sensed input voltage sits before it is digitized by the ADC
uint16_t rectified
‍previous reading of raw input voltage
uint16_t counter_reset
‍counter used for computing the average of the rectified input voltage
uint32_t acc
‍when avg_counter reaches this value, compute average
uint16_t ac_drop_timer
‍used to time duration of zero cross
uint16_t vin_present_counter
‍used to time duration of AC drop event
uint16_t startup_counter
‍used to time duration of half cycle
uint16_t dc_loss_counter
‍TODO: add comment
uint16_t dc_present_counter
‍used to confirm that some input voltage is present
uint16_t zero_cross_timer
‍used to count periods at startup
uint16_t half_cycle_timer
‍measurement of half line cycle in IRQ ticks
Main AC Monitor data object data type declaration.
VACM_TIMEBASE_t timebase
information related to line cycle and zero cross timing
VACM_STATUS_t status
AC monitor status flags.
VACM_FAULT_t fault
AC monitor fault flags.
VACM_STATES_t state
state machine operating state ID
VACM_AVGCALC_BUFFER_t avgcalc_buffer
used for store information needed at runtime for calculation of average of rectified input voltage
VACM_VIN_t vin
information related to input voltage