KL25Z Comparator library

Dependents:   ComparatorIn_demo TEMT6200_demo 05_comparator_demo 05_comparator_demo ... more

KL25Z Comparator library

Comparator features

  • Operational over the entire supply range
  • Inputs may range from rail to rail
  • Programmable hysteresis control
  • Selectable interrupt on rising-edge, falling-edge, or both rising or falling edges of the comparator output
  • Selectable inversion on comparator output
  • Capability to produce a wide range of outputs such as:
    • Sampled
    • Windowed, which is ideal for certain PWM zero-crossing-detection applications
    • Digitally filtered:
      • Filter can be bypassed
      • Can be clocked via external SAMPLE signal or scaled bus clock
  • External hysteresis can be used at the same time that the output filter is used for internal functions
  • Two software selectable performance levels:
    • Shorter propagation delay at the expense of higher power
    • Low power, with longer propagation delay
  • DMA transfer support not yet implemented in this library
    • A comparison event can be selected to trigger a DMA transfer
  • Functional in all modes of operation
  • The window and filter functions are not available in the following modes:
    • Stop
    • VLPS
    • LLS
    • VLLSx

Block diagram

/media/uploads/frankvnk/kl25z_comparator_block_diagram.jpg

Introduction

This library allows us to create comparator objects between different inputs.
The comparator + and - inputs can be routed to one out of eight reference inputs (see table).
Input selection

Pin name#MUX inputCMP0Comment
PTC6000IN0CMP0_IN0
PTC7001IN1CMP0_IN1
PTC8010IN2CMP0_IN2
PTC9011IN3CMP0_IN3
PTE30100IN4CMP0_IN412-bit DAC0
PTE29101IN5CMP0_IN5
110IN61V internal Bandgap*
NC111IN7internal 6-bit DAC0
(table 1)

* Not yet implemented

Using the library

Selecting pins on initialisation
Upon initialisation, the comparator registers are set to following values:

    CMP0->CR0   = 0x00;  // Filter and digital hysteresis disabled
    CMP0->CR1   = 0x17;  // Continuous mode, high-speed compare, unfiltered output, output pin disabled
    CMP0->FPR   = 0x00;  // Filter disabled
    CMP0->SCR   = 0x06;  // Disable all interrupts and clear flags (flags are cleared by this write)
    CMP0->DACCR = 0xE0;  // DAC enabled, Vdd is 6bit reference, threshold set to 1/2 of full-scale (1.65V)

The library accepts two input parameters:
example:

ComparatorIn compi(PTC8, NC);
  • First parameter : + input pin.
  • Second parameter : - input pin.
    Every pin from the 'Pin name' column in (table 1) can be selected.

notes

  • IN6 (internal 1V bandgap reference) has no pin name and is not selectable on init.
    However, we can use the SwitchPlus and SwitchMin functions to change the corresponding input to IN6.
  • There are two special cases for the input parameters:
    • NC : Connect the internal 6-bit DAC0 to IN7.
    • PTE30 : configures PTE30 as 12-bit DAC0 output and connect to IN4.
      IMPORTANT: Make sure no external output is connected to PTE30 when you declare this pin, otherwise you WILL destroy the external device and/or the CPU.

Example
Following code demonstrates interrupt callback and polling mode.
Note: Polling the comparator this way won't always trigger the printf because of the wait() instructions (if we go above and below the threshold during the wait() time, then the polling cannot not see this change).

/***********************************************************
CODE EXAMPLE FOR AMBIENT LIGHT SENSOR ON KL25Z + Wi-Go BOARD
 ***********************************************************/
#include "ComparatorIn.h"
#include "mbed.h"

DigitalOut blinker(LED_BLUE);
DigitalOut cmpled(LED_GREEN);
DigitalOut cmp_en (PTD5);
AnalogIn cmp_lvl (PTB0);
ComparatorIn compi(PTC8, NC); // in+ = PTC8, in- = internal 6-bit DAC 

// Comparator callback functions
void cmp_rise_ISR(void)
{
    cmpled = 0;
}

void cmp_fall_ISR(void)
{
    cmpled = 1;
}

int main()
{
    cmp_en = 1;
    cmpled = 1;

    compi.rising(&cmp_rise_ISR);                // Set pointer to rising interrupt function
    compi.falling(&cmp_fall_ISR);               // Set pointer to falling interrupt function
    compi.treshold(0.5);                        // Set comparator threshold to 1.65V = 32 * 3.3V / 64

    while(1)
    {
        printf("Light sensor : %7.5f Volt\n",cmp_lvl*3.3);
        blinker = 1;
        wait(1);
        blinker = 0;
        wait(0.2);
        if (compi.status() == 0x01)
        {
            printf("*** Treshold reached : %7.5f\n",cmp_lvl*3.3);
        }
    }
}


Notes

  • When we enable the comparator interrupt, we need to declare user callback function(s) (rising and/or falling interrupt) AND initialise the function pointer(s).
    example:

compi.rising(&cmp_rise_ISR);
compi.falling(&cmp_fall_ISR);
  • Currently, following functions are not yet implemented:
    • On the fly MUX switching for + input (SwitchPlus function).
    • On the fly MUX switching for - input (SwitchMin function).
    • DMA transfer.
Committer:
frankvnk
Date:
Fri Jun 07 05:27:24 2013 +0000
Revision:
9:7886deada2bd
Parent:
6:9b1268dd1d16
Child:
10:1b9ac2b8c788
init - code cleanup

Who changed what in which revision?

UserRevisionLine numberNew contents of line
frankvnk 1:ccac56d8f1cb 1 /**************************************************************************************************
frankvnk 1:ccac56d8f1cb 2 ***** *****
frankvnk 1:ccac56d8f1cb 3 ***** Name: ComparatorIn.cpp *****
frankvnk 1:ccac56d8f1cb 4 ***** Ver.: 1.0 *****
frankvnk 1:ccac56d8f1cb 5 ***** Date: 05/06/2013 *****
frankvnk 1:ccac56d8f1cb 6 ***** Auth: Frank Vannieuwkerke *****
frankvnk 1:ccac56d8f1cb 7 ***** Func: library for KL25Z Comparator *****
frankvnk 1:ccac56d8f1cb 8 ***** *****
frankvnk 1:ccac56d8f1cb 9 **************************************************************************************************/
frankvnk 1:ccac56d8f1cb 10
frankvnk 0:e742ad3d7dac 11 #include "ComparatorIn.h"
frankvnk 0:e742ad3d7dac 12
frankvnk 0:e742ad3d7dac 13 void (*user_fptr)(unsigned int); // Pointer to user function - called after IRQ assertion.
frankvnk 0:e742ad3d7dac 14
frankvnk 0:e742ad3d7dac 15 const PinMap ComparatorIn::PinMap_CMP[] = {
frankvnk 0:e742ad3d7dac 16 {PTC6, CMP0_IN0, 0},
frankvnk 0:e742ad3d7dac 17 {PTC7, CMP0_IN1, 0},
frankvnk 0:e742ad3d7dac 18 {PTC8, CMP0_IN2, 0},
frankvnk 0:e742ad3d7dac 19 {PTC9, CMP0_IN3, 0},
frankvnk 0:e742ad3d7dac 20 {PTE30, CMP0_IN4, 0}, // ADC0_SE23
frankvnk 0:e742ad3d7dac 21 {PTE29, CMP0_IN5, 0}, // ADC0_SE4b
frankvnk 0:e742ad3d7dac 22 {NC, NC, 0}
frankvnk 0:e742ad3d7dac 23 };
frankvnk 0:e742ad3d7dac 24
frankvnk 0:e742ad3d7dac 25 ComparatorIn::ComparatorIn(PinName pinP, PinName pinM)
frankvnk 0:e742ad3d7dac 26 {
frankvnk 0:e742ad3d7dac 27 user_fptr = NULL;
frankvnk 0:e742ad3d7dac 28 CMPnumberP = (CMPName)pinmap_peripheral(pinP, PinMap_CMP);
frankvnk 0:e742ad3d7dac 29 if (CMPnumberP == (uint32_t)NC) // When NC, use DAC0
frankvnk 0:e742ad3d7dac 30 CMPnumberP = 0x07;
frankvnk 0:e742ad3d7dac 31 CMPnumberM = (CMPName)pinmap_peripheral(pinM, PinMap_CMP);
frankvnk 0:e742ad3d7dac 32 if (CMPnumberM == (uint32_t)NC) // When NC, use DAC0
frankvnk 0:e742ad3d7dac 33 CMPnumberM = 0x07;
frankvnk 0:e742ad3d7dac 34
frankvnk 0:e742ad3d7dac 35 SIM->SCGC4 |=SIM_SCGC4_CMP_MASK; // Enable HSCMP module clock
frankvnk 0:e742ad3d7dac 36
frankvnk 0:e742ad3d7dac 37 hscmp_clear();
frankvnk 0:e742ad3d7dac 38 CMP0->CR0 = 0x00; // Filter and digital hysteresis disabled
frankvnk 0:e742ad3d7dac 39 CMP0->CR1 = 0x17; // Continuous mode, high-speed compare, unfiltered output, output pin disabled
frankvnk 0:e742ad3d7dac 40 CMP0->FPR = 0x00; // Filter disabled
frankvnk 0:e742ad3d7dac 41 CMP0->SCR = 0x16; // Enable rising edge interrupt and flag (flags are cleared by this write)
frankvnk 6:9b1268dd1d16 42 CMP0->DACCR = 0xE0; // DAC enabled, Vdd is 6bit reference, threshold set to 1/2 of full-scale (1.65V)
frankvnk 0:e742ad3d7dac 43 CMP0->MUXCR = (CMPnumberP << 3) | (CMPnumberM & 0x07); // P-input/M-input are ext.channels defined by CMPnumberP/CMPnumberN
frankvnk 0:e742ad3d7dac 44
frankvnk 0:e742ad3d7dac 45 if(CMPnumberP < 6) pinmap_pinout(pinP, PinMap_CMP); //Map pins
frankvnk 0:e742ad3d7dac 46 if(CMPnumberM < 6) pinmap_pinout(pinM, PinMap_CMP); //Map pins
frankvnk 0:e742ad3d7dac 47 };
frankvnk 0:e742ad3d7dac 48
frankvnk 0:e742ad3d7dac 49 void ComparatorIn::filter_count(unsigned char fico)
frankvnk 0:e742ad3d7dac 50 {
frankvnk 0:e742ad3d7dac 51 if((fico > 0) && (fico < 8))
frankvnk 0:e742ad3d7dac 52 {
frankvnk 0:e742ad3d7dac 53 unsigned char tmp;
frankvnk 0:e742ad3d7dac 54 tmp = (CMP0->CR0 & 0x70) | fico; // Mask old value
frankvnk 0:e742ad3d7dac 55 CMP0->CR0 = tmp; // Set filter count
frankvnk 0:e742ad3d7dac 56 }
frankvnk 0:e742ad3d7dac 57 }
frankvnk 0:e742ad3d7dac 58
frankvnk 0:e742ad3d7dac 59 void ComparatorIn::hysteresis(unsigned char hyst)
frankvnk 0:e742ad3d7dac 60 {
frankvnk 0:e742ad3d7dac 61 if(hyst < 4)
frankvnk 0:e742ad3d7dac 62 {
frankvnk 0:e742ad3d7dac 63 unsigned char tmp;
frankvnk 0:e742ad3d7dac 64 tmp = (CMP0->CR0 & 0x03) | hyst; // Mask old value
frankvnk 0:e742ad3d7dac 65 CMP0->CR0 = tmp; // Set hysteresis
frankvnk 0:e742ad3d7dac 66 }
frankvnk 0:e742ad3d7dac 67 }
frankvnk 0:e742ad3d7dac 68
frankvnk 0:e742ad3d7dac 69 void ComparatorIn::sample_mode(unsigned char samp_en)
frankvnk 0:e742ad3d7dac 70 {
frankvnk 0:e742ad3d7dac 71 if((CMP0->CR1 & CMP_CR1_WE_MASK) == 0) // Only allow change when window mode is inactive
frankvnk 0:e742ad3d7dac 72 {
frankvnk 0:e742ad3d7dac 73 if(samp_en == 1) CMP0->CR1 |= CMP_CR1_SE_MASK; // Enable
frankvnk 0:e742ad3d7dac 74 else CMP0->CR1 &= ~CMP_CR1_SE_MASK; // Disable
frankvnk 0:e742ad3d7dac 75 }
frankvnk 0:e742ad3d7dac 76 }
frankvnk 0:e742ad3d7dac 77
frankvnk 0:e742ad3d7dac 78 void ComparatorIn::window_mode(unsigned char win_en)
frankvnk 0:e742ad3d7dac 79 {
frankvnk 0:e742ad3d7dac 80 if((CMP0->CR1 & CMP_CR1_SE_MASK) == 0) // Only allow change when sample mode is inactive
frankvnk 0:e742ad3d7dac 81 {
frankvnk 0:e742ad3d7dac 82 if(win_en == 1) CMP0->CR1 |= CMP_CR1_WE_MASK; // Enable
frankvnk 0:e742ad3d7dac 83 else CMP0->CR1 &= ~CMP_CR1_WE_MASK; // Disable
frankvnk 0:e742ad3d7dac 84 }
frankvnk 0:e742ad3d7dac 85 }
frankvnk 0:e742ad3d7dac 86
frankvnk 0:e742ad3d7dac 87 void ComparatorIn::trig_mode(unsigned char trig_en)
frankvnk 0:e742ad3d7dac 88 {
frankvnk 0:e742ad3d7dac 89 if(trig_en == 1) CMP0->CR1 |= CMP_CR1_TRIGM_MASK; // Enable
frankvnk 0:e742ad3d7dac 90 else CMP0->CR1 &= ~CMP_CR1_TRIGM_MASK; // Disable
frankvnk 0:e742ad3d7dac 91 }
frankvnk 0:e742ad3d7dac 92
frankvnk 0:e742ad3d7dac 93 void ComparatorIn::power_mode(unsigned char pmode)
frankvnk 0:e742ad3d7dac 94 {
frankvnk 0:e742ad3d7dac 95 if(pmode == 1) CMP0->CR1 |= CMP_CR1_PMODE_MASK; // Set high speed
frankvnk 0:e742ad3d7dac 96 else CMP0->CR1 &= ~CMP_CR1_PMODE_MASK; // Set low speed
frankvnk 0:e742ad3d7dac 97 }
frankvnk 0:e742ad3d7dac 98
frankvnk 0:e742ad3d7dac 99 void ComparatorIn::invert(unsigned char inv)
frankvnk 0:e742ad3d7dac 100 {
frankvnk 0:e742ad3d7dac 101 if(inv == 1) CMP0->CR1 |= CMP_CR1_INV_MASK; // Enable
frankvnk 0:e742ad3d7dac 102 else CMP0->CR1 &= ~CMP_CR1_INV_MASK; // Disable
frankvnk 0:e742ad3d7dac 103 }
frankvnk 0:e742ad3d7dac 104
frankvnk 0:e742ad3d7dac 105 void ComparatorIn::output_select(unsigned char cos)
frankvnk 0:e742ad3d7dac 106 {
frankvnk 0:e742ad3d7dac 107 if(cos == 1) CMP0->CR1 |= CMP_CR1_COS_MASK; // Enable
frankvnk 0:e742ad3d7dac 108 else CMP0->CR1 &= ~CMP_CR1_COS_MASK; // Disable
frankvnk 0:e742ad3d7dac 109 }
frankvnk 0:e742ad3d7dac 110
frankvnk 0:e742ad3d7dac 111 void ComparatorIn::output_pin_en(unsigned char ope)
frankvnk 0:e742ad3d7dac 112 {
frankvnk 0:e742ad3d7dac 113 if(ope == 1) CMP0->CR1 |= CMP_CR1_OPE_MASK; // Enable
frankvnk 0:e742ad3d7dac 114 else CMP0->CR1 &= ~CMP_CR1_OPE_MASK; // Disable
frankvnk 0:e742ad3d7dac 115 }
frankvnk 0:e742ad3d7dac 116
frankvnk 0:e742ad3d7dac 117 void ComparatorIn::enable(unsigned char en)
frankvnk 0:e742ad3d7dac 118 {
frankvnk 0:e742ad3d7dac 119 if(en == 1) CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable
frankvnk 0:e742ad3d7dac 120 else CMP0->CR1 &= ~CMP_CR1_EN_MASK; // Disable
frankvnk 0:e742ad3d7dac 121 }
frankvnk 0:e742ad3d7dac 122
frankvnk 0:e742ad3d7dac 123 void ComparatorIn::filter_period(unsigned char fipe)
frankvnk 0:e742ad3d7dac 124 {
frankvnk 0:e742ad3d7dac 125 CMP0->FPR = CMP_FPR_FILT_PER(fipe);
frankvnk 0:e742ad3d7dac 126 }
frankvnk 0:e742ad3d7dac 127
frankvnk 0:e742ad3d7dac 128 void ComparatorIn::dma_en(unsigned char dmaen)
frankvnk 0:e742ad3d7dac 129 {
frankvnk 0:e742ad3d7dac 130 if(dmaen == 1) CMP0->SCR |= CMP_SCR_DMAEN_MASK; // Enable
frankvnk 0:e742ad3d7dac 131 else CMP0->SCR &= ~CMP_SCR_DMAEN_MASK; // Disable
frankvnk 0:e742ad3d7dac 132 }
frankvnk 0:e742ad3d7dac 133
frankvnk 0:e742ad3d7dac 134 void ComparatorIn::int_en_rising(unsigned char ier)
frankvnk 0:e742ad3d7dac 135 {
frankvnk 0:e742ad3d7dac 136 if(ier == 1) CMP0->SCR |= CMP_SCR_IER_MASK; // Enable
frankvnk 0:e742ad3d7dac 137 else CMP0->SCR &= ~CMP_SCR_IER_MASK; // Disable
frankvnk 0:e742ad3d7dac 138 }
frankvnk 0:e742ad3d7dac 139
frankvnk 0:e742ad3d7dac 140 void ComparatorIn::int_en_falling(unsigned char ief)
frankvnk 0:e742ad3d7dac 141 {
frankvnk 0:e742ad3d7dac 142 if(ief == 1) CMP0->SCR |= CMP_SCR_IEF_MASK; // Enable
frankvnk 0:e742ad3d7dac 143 else CMP0->SCR &= ~CMP_SCR_IEF_MASK; // Disable
frankvnk 0:e742ad3d7dac 144 }
frankvnk 0:e742ad3d7dac 145
frankvnk 0:e742ad3d7dac 146 unsigned char ComparatorIn::status(void)
frankvnk 0:e742ad3d7dac 147 {
frankvnk 0:e742ad3d7dac 148 return (CMP0->SCR & 0x01);
frankvnk 0:e742ad3d7dac 149 }
frankvnk 0:e742ad3d7dac 150
frankvnk 0:e742ad3d7dac 151 void ComparatorIn::dac_en(unsigned char den)
frankvnk 0:e742ad3d7dac 152 {
frankvnk 0:e742ad3d7dac 153 if(den == 1) CMP0->DACCR |= CMP_DACCR_DACEN_MASK; // Enable
frankvnk 0:e742ad3d7dac 154 else CMP0->DACCR &= ~CMP_DACCR_DACEN_MASK; // Disable
frankvnk 0:e742ad3d7dac 155 }
frankvnk 0:e742ad3d7dac 156
frankvnk 0:e742ad3d7dac 157 void ComparatorIn::ref_source(unsigned char res)
frankvnk 0:e742ad3d7dac 158 {
frankvnk 0:e742ad3d7dac 159 if(res == 1) CMP0->DACCR |= CMP_DACCR_VRSEL_MASK; // Enable
frankvnk 0:e742ad3d7dac 160 else CMP0->DACCR &= ~CMP_DACCR_VRSEL_MASK; // Disable
frankvnk 0:e742ad3d7dac 161 }
frankvnk 0:e742ad3d7dac 162
frankvnk 0:e742ad3d7dac 163 void ComparatorIn::treshold(unsigned char vo_sel)
frankvnk 0:e742ad3d7dac 164 {
frankvnk 0:e742ad3d7dac 165 if(vo_sel < 64)
frankvnk 0:e742ad3d7dac 166 {
frankvnk 0:e742ad3d7dac 167 unsigned char tmp;
frankvnk 0:e742ad3d7dac 168 tmp = (CMP0->DACCR & 0xC0) | vo_sel; // Mask old value
frankvnk 0:e742ad3d7dac 169 CMP0->DACCR = tmp; // Set Vout DAC to vo_sel
frankvnk 0:e742ad3d7dac 170 }
frankvnk 0:e742ad3d7dac 171 }
frankvnk 0:e742ad3d7dac 172
frankvnk 0:e742ad3d7dac 173 void ComparatorIn::pass_through(unsigned char ptm)
frankvnk 0:e742ad3d7dac 174 {
frankvnk 0:e742ad3d7dac 175 if(ptm == 1) CMP0->MUXCR |= CMP_MUXCR_MSEL_MASK; // Enable
frankvnk 0:e742ad3d7dac 176 else CMP0->MUXCR &= ~CMP_MUXCR_MSEL_MASK; // Disable
frankvnk 0:e742ad3d7dac 177 }
frankvnk 0:e742ad3d7dac 178
frankvnk 0:e742ad3d7dac 179 void ComparatorIn::switch_plus(unsigned char pinP)
frankvnk 0:e742ad3d7dac 180 {
frankvnk 0:e742ad3d7dac 181 }
frankvnk 0:e742ad3d7dac 182
frankvnk 0:e742ad3d7dac 183 void ComparatorIn::switch_min(unsigned char pinM)
frankvnk 0:e742ad3d7dac 184 {
frankvnk 0:e742ad3d7dac 185 }
frankvnk 0:e742ad3d7dac 186
frankvnk 0:e742ad3d7dac 187 void ComparatorIn::hscmp_clear(void)
frankvnk 0:e742ad3d7dac 188 {
frankvnk 0:e742ad3d7dac 189 CMP0->CR0 = 0;
frankvnk 0:e742ad3d7dac 190 CMP0->CR1 = 0;
frankvnk 0:e742ad3d7dac 191 CMP0->FPR = 0;
frankvnk 0:e742ad3d7dac 192 CMP0->SCR = 0x06; // Clear flags if set.
frankvnk 0:e742ad3d7dac 193 CMP0->DACCR = 0;
frankvnk 0:e742ad3d7dac 194 CMP0->MUXCR = 0;
frankvnk 0:e742ad3d7dac 195 }
frankvnk 0:e742ad3d7dac 196
frankvnk 0:e742ad3d7dac 197 void ComparatorIn::_callbackISR(void(*fptr)(unsigned int))
frankvnk 0:e742ad3d7dac 198 {
frankvnk 0:e742ad3d7dac 199 NVIC_SetVector(CMP0_IRQn, (uint32_t)&_cmpISR); // Set comparator ISR to _cmpISR routine
frankvnk 0:e742ad3d7dac 200 NVIC_EnableIRQ(CMP0_IRQn); // Enable comparator ISR
frankvnk 0:e742ad3d7dac 201 user_fptr = fptr;
frankvnk 0:e742ad3d7dac 202 }
frankvnk 0:e742ad3d7dac 203
frankvnk 0:e742ad3d7dac 204 void ComparatorIn::_cmpISR(void)
frankvnk 0:e742ad3d7dac 205 {
frankvnk 0:e742ad3d7dac 206 // clear interrupt flags by reading them
frankvnk 0:e742ad3d7dac 207 //If rising edge
frankvnk 0:e742ad3d7dac 208 if (((CMP0->SCR & CMP_SCR_IER_MASK)==CMP_SCR_IER_MASK) && ((CMP0->SCR & CMP_SCR_CFR_MASK)==CMP_SCR_CFR_MASK))
frankvnk 0:e742ad3d7dac 209 {
frankvnk 0:e742ad3d7dac 210 CMP0->SCR |= CMP_SCR_CFR_MASK; // Clear the flag
frankvnk 0:e742ad3d7dac 211 if (user_fptr != NULL) user_fptr(CMP_SCR_CFR_MASK);
frankvnk 0:e742ad3d7dac 212 }
frankvnk 0:e742ad3d7dac 213
frankvnk 0:e742ad3d7dac 214 //If falling edge
frankvnk 0:e742ad3d7dac 215 if (((CMP0->SCR & CMP_SCR_IEF_MASK)==CMP_SCR_IEF_MASK) && ((CMP0->SCR & CMP_SCR_CFF_MASK)==CMP_SCR_CFF_MASK))
frankvnk 0:e742ad3d7dac 216 {
frankvnk 0:e742ad3d7dac 217 CMP0->SCR |= CMP_SCR_CFF_MASK; // Clear the flag
frankvnk 0:e742ad3d7dac 218 if (user_fptr != NULL) user_fptr(CMP_SCR_CFF_MASK);
frankvnk 0:e742ad3d7dac 219 }
frankvnk 0:e742ad3d7dac 220 // call user function
frankvnk 0:e742ad3d7dac 221 }
frankvnk 0:e742ad3d7dac 222
frankvnk 0:e742ad3d7dac 223
frankvnk 1:ccac56d8f1cb 224