Simple Latency Measurement Application for Head Mounted Display. This project handles LED and light sensor to measure the latency from blinking to showing on the display.
main.cpp@2:4ec0fc856963, 2014-09-23 (annotated)
- Committer:
- mfurukawa
- Date:
- Tue Sep 23 08:55:58 2014 +0000
- Revision:
- 2:4ec0fc856963
- Parent:
- 0:f6d58666cdc3
typo corected
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mfurukawa | 0:f6d58666cdc3 | 1 | // |
mfurukawa | 0:f6d58666cdc3 | 2 | // Latency Checker rev 0.1 |
mfurukawa | 0:f6d58666cdc3 | 3 | // |
mfurukawa | 0:f6d58666cdc3 | 4 | // Author : Masahiro Furukawa |
mfurukawa | 0:f6d58666cdc3 | 5 | // Mail : m.furukawa@ist.osaka-u.ac.jp |
mfurukawa | 0:f6d58666cdc3 | 6 | // Created : Sept 22, 2014 |
mfurukawa | 0:f6d58666cdc3 | 7 | // Updated : Sept 23, 2014 |
mfurukawa | 0:f6d58666cdc3 | 8 | // |
mfurukawa | 0:f6d58666cdc3 | 9 | // Purpose : Latency Measurement between Camera and Display (HMD) |
mfurukawa | 0:f6d58666cdc3 | 10 | // Requirement : Serial Terminal to show result |
mfurukawa | 0:f6d58666cdc3 | 11 | // |
mfurukawa | 0:f6d58666cdc3 | 12 | // Pin Assign : P16 --- LED Anode |
mfurukawa | 0:f6d58666cdc3 | 13 | // P18 --- Cross point btwn AD in (PT600T) and register |
mfurukawa | 0:f6d58666cdc3 | 14 | |
mfurukawa | 0:f6d58666cdc3 | 15 | #include "mbed.h" |
mfurukawa | 0:f6d58666cdc3 | 16 | #include "dsp.h" |
mfurukawa | 0:f6d58666cdc3 | 17 | |
mfurukawa | 0:f6d58666cdc3 | 18 | #define BUF_SIZE 2000 |
mfurukawa | 0:f6d58666cdc3 | 19 | #define H_TO_L 1 |
mfurukawa | 0:f6d58666cdc3 | 20 | #define L_TO_H -1 |
mfurukawa | 0:f6d58666cdc3 | 21 | |
mfurukawa | 0:f6d58666cdc3 | 22 | InterruptIn button(p5); |
mfurukawa | 0:f6d58666cdc3 | 23 | AnalogIn adc_in(p18); |
mfurukawa | 0:f6d58666cdc3 | 24 | DigitalOut led(LED1); |
mfurukawa | 0:f6d58666cdc3 | 25 | DigitalOut flash(p16); |
mfurukawa | 0:f6d58666cdc3 | 26 | |
mfurukawa | 0:f6d58666cdc3 | 27 | float32_t threshold = 0.0; |
mfurukawa | 0:f6d58666cdc3 | 28 | float32_t ad[BUF_SIZE]; |
mfurukawa | 0:f6d58666cdc3 | 29 | int cycle = 0; |
mfurukawa | 0:f6d58666cdc3 | 30 | |
mfurukawa | 0:f6d58666cdc3 | 31 | Ticker adc_grabber; |
mfurukawa | 0:f6d58666cdc3 | 32 | |
mfurukawa | 0:f6d58666cdc3 | 33 | void show_credit() |
mfurukawa | 0:f6d58666cdc3 | 34 | { |
mfurukawa | 0:f6d58666cdc3 | 35 | printf("\n\r Latency Checker rev 0.1\n\r\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 36 | printf(" Author : Masahiro Furukawa\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 37 | printf(" Mail : m.furukawa@ist.osaka-u.ac.jp\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 38 | printf(" Created : Sept 22, 2014\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 39 | printf(" Updated : \n\r\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 40 | } |
mfurukawa | 0:f6d58666cdc3 | 41 | |
mfurukawa | 0:f6d58666cdc3 | 42 | void show_menu() |
mfurukawa | 0:f6d58666cdc3 | 43 | { |
mfurukawa | 0:f6d58666cdc3 | 44 | printf("[a] start AUTO mode\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 45 | //printf("[s] start\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 46 | |
mfurukawa | 0:f6d58666cdc3 | 47 | //printf("\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 48 | //printf("\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 49 | } |
mfurukawa | 0:f6d58666cdc3 | 50 | |
mfurukawa | 0:f6d58666cdc3 | 51 | void init_cnt() |
mfurukawa | 0:f6d58666cdc3 | 52 | { |
mfurukawa | 0:f6d58666cdc3 | 53 | cycle = 0; |
mfurukawa | 0:f6d58666cdc3 | 54 | } |
mfurukawa | 0:f6d58666cdc3 | 55 | void init() |
mfurukawa | 0:f6d58666cdc3 | 56 | { |
mfurukawa | 0:f6d58666cdc3 | 57 | threshold = 0.0; |
mfurukawa | 0:f6d58666cdc3 | 58 | init_cnt(); |
mfurukawa | 0:f6d58666cdc3 | 59 | } |
mfurukawa | 0:f6d58666cdc3 | 60 | void get_ad() |
mfurukawa | 0:f6d58666cdc3 | 61 | { |
mfurukawa | 0:f6d58666cdc3 | 62 | ad[cycle] = 0; |
mfurukawa | 0:f6d58666cdc3 | 63 | ad[cycle] = adc_in.read(); |
mfurukawa | 0:f6d58666cdc3 | 64 | cycle ++; |
mfurukawa | 0:f6d58666cdc3 | 65 | } |
mfurukawa | 0:f6d58666cdc3 | 66 | void get_mean_stdev(float32_t *mean, float32_t *stdev) |
mfurukawa | 0:f6d58666cdc3 | 67 | { |
mfurukawa | 0:f6d58666cdc3 | 68 | // clear counter : cycle |
mfurukawa | 0:f6d58666cdc3 | 69 | init_cnt(); |
mfurukawa | 0:f6d58666cdc3 | 70 | |
mfurukawa | 0:f6d58666cdc3 | 71 | // blocking sequence to grab adc result per 500 micro-second |
mfurukawa | 0:f6d58666cdc3 | 72 | adc_grabber.attach_us(&get_ad, 500); // 500 us |
mfurukawa | 0:f6d58666cdc3 | 73 | wait(0.5); // = 500 ms = 500,000 us = 1000 cycle |
mfurukawa | 0:f6d58666cdc3 | 74 | adc_grabber.detach(); |
mfurukawa | 0:f6d58666cdc3 | 75 | |
mfurukawa | 0:f6d58666cdc3 | 76 | arm_mean_f32( ad , cycle , mean ); |
mfurukawa | 0:f6d58666cdc3 | 77 | arm_std_f32 ( ad , cycle , stdev ); |
mfurukawa | 0:f6d58666cdc3 | 78 | } |
mfurukawa | 0:f6d58666cdc3 | 79 | |
mfurukawa | 0:f6d58666cdc3 | 80 | void count_up() |
mfurukawa | 0:f6d58666cdc3 | 81 | { |
mfurukawa | 0:f6d58666cdc3 | 82 | cycle ++; |
mfurukawa | 0:f6d58666cdc3 | 83 | } |
mfurukawa | 0:f6d58666cdc3 | 84 | void get_edge_us(float32_t *edge_us, int direction) |
mfurukawa | 0:f6d58666cdc3 | 85 | { |
mfurukawa | 0:f6d58666cdc3 | 86 | // clear counter : cycle |
mfurukawa | 0:f6d58666cdc3 | 87 | init_cnt(); |
mfurukawa | 0:f6d58666cdc3 | 88 | |
mfurukawa | 0:f6d58666cdc3 | 89 | // toggle LED |
mfurukawa | 0:f6d58666cdc3 | 90 | if(direction == H_TO_L){ flash = 1; wait(1); flash = 0; } |
mfurukawa | 0:f6d58666cdc3 | 91 | else |
mfurukawa | 0:f6d58666cdc3 | 92 | if(direction == L_TO_H){ flash = 0; wait(1); flash = 1; } |
mfurukawa | 0:f6d58666cdc3 | 93 | |
mfurukawa | 0:f6d58666cdc3 | 94 | // start grabbing adc result per 500 micro-second |
mfurukawa | 0:f6d58666cdc3 | 95 | adc_grabber.attach_us(&count_up, 500); // 500 us |
mfurukawa | 0:f6d58666cdc3 | 96 | |
mfurukawa | 0:f6d58666cdc3 | 97 | // wait for over threshold |
mfurukawa | 0:f6d58666cdc3 | 98 | if(direction == H_TO_L) while( adc_in.read() > threshold ){} |
mfurukawa | 0:f6d58666cdc3 | 99 | else |
mfurukawa | 0:f6d58666cdc3 | 100 | if(direction == L_TO_H) while( adc_in.read() < threshold ){} |
mfurukawa | 0:f6d58666cdc3 | 101 | |
mfurukawa | 0:f6d58666cdc3 | 102 | // stop timer |
mfurukawa | 0:f6d58666cdc3 | 103 | adc_grabber.detach(); |
mfurukawa | 0:f6d58666cdc3 | 104 | |
mfurukawa | 0:f6d58666cdc3 | 105 | *edge_us = cycle * 500.0; |
mfurukawa | 0:f6d58666cdc3 | 106 | // printf("cycle (%d)",cycle); |
mfurukawa | 0:f6d58666cdc3 | 107 | } |
mfurukawa | 0:f6d58666cdc3 | 108 | |
mfurukawa | 0:f6d58666cdc3 | 109 | struct result{ |
mfurukawa | 0:f6d58666cdc3 | 110 | float32_t mean; |
mfurukawa | 0:f6d58666cdc3 | 111 | float32_t stdev; |
mfurukawa | 0:f6d58666cdc3 | 112 | } ; |
mfurukawa | 0:f6d58666cdc3 | 113 | |
mfurukawa | 0:f6d58666cdc3 | 114 | int get_threshold() |
mfurukawa | 0:f6d58666cdc3 | 115 | { |
mfurukawa | 2:4ec0fc856963 | 116 | struct result dark, bright; |
mfurukawa | 0:f6d58666cdc3 | 117 | int ret; |
mfurukawa | 0:f6d58666cdc3 | 118 | |
mfurukawa | 0:f6d58666cdc3 | 119 | // LED OFF |
mfurukawa | 0:f6d58666cdc3 | 120 | flash = 0; |
mfurukawa | 0:f6d58666cdc3 | 121 | wait(1); |
mfurukawa | 0:f6d58666cdc3 | 122 | |
mfurukawa | 0:f6d58666cdc3 | 123 | // get adc |
mfurukawa | 0:f6d58666cdc3 | 124 | get_mean_stdev( &dark.mean, &dark.stdev ); |
mfurukawa | 0:f6d58666cdc3 | 125 | |
mfurukawa | 0:f6d58666cdc3 | 126 | // LED ON |
mfurukawa | 0:f6d58666cdc3 | 127 | flash = 1; |
mfurukawa | 0:f6d58666cdc3 | 128 | wait(1); |
mfurukawa | 0:f6d58666cdc3 | 129 | |
mfurukawa | 0:f6d58666cdc3 | 130 | // get adc |
mfurukawa | 2:4ec0fc856963 | 131 | get_mean_stdev( &bright.mean, &bright.stdev ); |
mfurukawa | 0:f6d58666cdc3 | 132 | |
mfurukawa | 0:f6d58666cdc3 | 133 | // show fractuation notice |
mfurukawa | 2:4ec0fc856963 | 134 | if(dark.stdev * 3.3 > 0.1 || bright.stdev * 3.3 > 0.1 ) |
mfurukawa | 0:f6d58666cdc3 | 135 | { |
mfurukawa | 2:4ec0fc856963 | 136 | printf("*** CAUTION *** : LCD Backlight Flicker Detected(stdev > 0.1V). brightness shuold be max. \n\r"); |
mfurukawa | 0:f6d58666cdc3 | 137 | ret = -2; |
mfurukawa | 0:f6d58666cdc3 | 138 | threshold = -1; |
mfurukawa | 0:f6d58666cdc3 | 139 | } |
mfurukawa | 2:4ec0fc856963 | 140 | else if(dark.stdev * 3.3 > 0.01 || bright.stdev * 3.3 > 0.01 ) |
mfurukawa | 0:f6d58666cdc3 | 141 | { |
mfurukawa | 2:4ec0fc856963 | 142 | printf("(NOTICE) : LCD Backlight Flicker Detected (stdev > 0.01V). brightness shuold be max.\n\r"); |
mfurukawa | 0:f6d58666cdc3 | 143 | ret = -1; |
mfurukawa | 0:f6d58666cdc3 | 144 | threshold = -1; |
mfurukawa | 0:f6d58666cdc3 | 145 | }else |
mfurukawa | 0:f6d58666cdc3 | 146 | { |
mfurukawa | 0:f6d58666cdc3 | 147 | printf(" great! "); |
mfurukawa | 0:f6d58666cdc3 | 148 | ret = 0; |
mfurukawa | 0:f6d58666cdc3 | 149 | |
mfurukawa | 0:f6d58666cdc3 | 150 | // 50% threshold |
mfurukawa | 2:4ec0fc856963 | 151 | threshold = (bright.mean - dark.mean) / 2.0 ; |
mfurukawa | 0:f6d58666cdc3 | 152 | } |
mfurukawa | 0:f6d58666cdc3 | 153 | |
mfurukawa | 0:f6d58666cdc3 | 154 | // show result |
mfurukawa | 0:f6d58666cdc3 | 155 | printf("Drk avg %1.5lf (SD %1.5lf) / ", dark.mean * 3.3 , dark.stdev * 3.3); |
mfurukawa | 2:4ec0fc856963 | 156 | printf("Brght avg %1.5lf (SD %1.5lf)\r\n", bright.mean * 3.3 , bright.stdev * 3.3); |
mfurukawa | 0:f6d58666cdc3 | 157 | |
mfurukawa | 0:f6d58666cdc3 | 158 | return ret; |
mfurukawa | 0:f6d58666cdc3 | 159 | } |
mfurukawa | 0:f6d58666cdc3 | 160 | |
mfurukawa | 0:f6d58666cdc3 | 161 | #define CHECK_TIMES 5 |
mfurukawa | 0:f6d58666cdc3 | 162 | void get_latency() |
mfurukawa | 0:f6d58666cdc3 | 163 | { |
mfurukawa | 0:f6d58666cdc3 | 164 | float32_t latency_us_up[CHECK_TIMES], latency_us_down[CHECK_TIMES]; |
mfurukawa | 0:f6d58666cdc3 | 165 | struct result up, down; |
mfurukawa | 0:f6d58666cdc3 | 166 | |
mfurukawa | 0:f6d58666cdc3 | 167 | if( threshold == -1 ) |
mfurukawa | 0:f6d58666cdc3 | 168 | { |
mfurukawa | 0:f6d58666cdc3 | 169 | printf(" Thredhold value error(-1). Latency measurement fault. \n\r "); |
mfurukawa | 0:f6d58666cdc3 | 170 | }else |
mfurukawa | 0:f6d58666cdc3 | 171 | { |
mfurukawa | 0:f6d58666cdc3 | 172 | //printf(" latency check started ! wait a while ");wait(0.5); |
mfurukawa | 0:f6d58666cdc3 | 173 | } |
mfurukawa | 0:f6d58666cdc3 | 174 | |
mfurukawa | 0:f6d58666cdc3 | 175 | // measure latency |
mfurukawa | 0:f6d58666cdc3 | 176 | for(int i=0; i<CHECK_TIMES; i++) |
mfurukawa | 0:f6d58666cdc3 | 177 | { |
mfurukawa | 0:f6d58666cdc3 | 178 | //printf("."); |
mfurukawa | 0:f6d58666cdc3 | 179 | get_edge_us(&latency_us_down[i], H_TO_L ); |
mfurukawa | 0:f6d58666cdc3 | 180 | get_edge_us(&latency_us_up[i], L_TO_H ); |
mfurukawa | 0:f6d58666cdc3 | 181 | } |
mfurukawa | 0:f6d58666cdc3 | 182 | |
mfurukawa | 0:f6d58666cdc3 | 183 | arm_mean_f32( latency_us_down , CHECK_TIMES , &down.mean ); |
mfurukawa | 0:f6d58666cdc3 | 184 | arm_mean_f32( latency_us_up , CHECK_TIMES , &up.mean ); |
mfurukawa | 0:f6d58666cdc3 | 185 | arm_std_f32 ( latency_us_down , CHECK_TIMES , &down.stdev ); |
mfurukawa | 0:f6d58666cdc3 | 186 | arm_std_f32 ( latency_us_up , CHECK_TIMES , &up.stdev ); |
mfurukawa | 0:f6d58666cdc3 | 187 | |
mfurukawa | 0:f6d58666cdc3 | 188 | // show result |
mfurukawa | 0:f6d58666cdc3 | 189 | printf("\n\r\n\r [RESULT] "); |
mfurukawa | 0:f6d58666cdc3 | 190 | printf("H to L avg %3.2lf ms (SD %3.2lf) / ", down.mean / 1000.0, down.stdev / 1000.0); |
mfurukawa | 0:f6d58666cdc3 | 191 | printf("L to H avg %3.2lf ms (SD %3.2lf)", up.mean / 1000.0, up.stdev / 1000.0); |
mfurukawa | 0:f6d58666cdc3 | 192 | printf(" / Threshold %1.5lf V\r\n\r\n", threshold * 3.3 ); |
mfurukawa | 0:f6d58666cdc3 | 193 | } |
mfurukawa | 0:f6d58666cdc3 | 194 | |
mfurukawa | 0:f6d58666cdc3 | 195 | |
mfurukawa | 0:f6d58666cdc3 | 196 | int main() |
mfurukawa | 0:f6d58666cdc3 | 197 | { |
mfurukawa | 0:f6d58666cdc3 | 198 | show_credit(); |
mfurukawa | 0:f6d58666cdc3 | 199 | get_threshold(); |
mfurukawa | 0:f6d58666cdc3 | 200 | |
mfurukawa | 0:f6d58666cdc3 | 201 | while(1) |
mfurukawa | 0:f6d58666cdc3 | 202 | { |
mfurukawa | 0:f6d58666cdc3 | 203 | while( get_threshold() != 0 ){} |
mfurukawa | 0:f6d58666cdc3 | 204 | |
mfurukawa | 0:f6d58666cdc3 | 205 | get_latency(); |
mfurukawa | 0:f6d58666cdc3 | 206 | |
mfurukawa | 0:f6d58666cdc3 | 207 | } |
mfurukawa | 0:f6d58666cdc3 | 208 | } |