Browse Source

KTL test version

Youngbin Kim 1 year ago
parent
commit
a64731c419
80 changed files with 8889 additions and 294 deletions
  1. 1 0
      .gitignore
  2. 5 1
      CMakeLists.txt
  3. 36 1
      Core/Inc/ImC/imc_extension.h
  4. 4 1
      Core/Inc/ImC/imc_kernel.h
  5. 2 0
      Core/Inc/benchmarks/benchmark_driver.h
  6. 1 1
      Core/Inc/stm32l5xx_hal_conf.h
  7. 2 1
      Core/Src/ImC/imc_api.c
  8. 276 44
      Core/Src/ImC/imc_extension.c
  9. 23 1
      Core/Src/ImC/imc_kernel.c
  10. 24 2
      Core/Src/benchmarks/adc_demo/adc_demo.c
  11. 32 8
      Core/Src/benchmarks/benchmark_driver.c
  12. 3 0
      Core/Src/benchmarks/conv2d/conv2d.c
  13. 82 0
      Core/Src/benchmarks/fmc_expr/fmc_expr.c
  14. 0 0
      Core/Src/benchmarks/sha/sha.c
  15. 43 0
      Core/Src/benchmarks/vrefint_expr/vrefint_expr.c
  16. 130 11
      Core/Src/main.c
  17. 108 53
      Core/Src/stm32l5xx_hal_msp.c
  18. 40 0
      Core/Src/stm32l5xx_it.c
  19. 3 0
      Core/Startup/startup_stm32l552zetx.s
  20. 758 0
      Drivers/STM32L5xx_HAL_Driver/Inc/stm32l5xx_hal_comp.h
  21. 1019 0
      Drivers/STM32L5xx_HAL_Driver/Src/stm32l5xx_hal_comp.c
  22. 2 2
      Middlewares/Third_Party/FreeRTOS/Source/include/task.h
  23. 23 0
      Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM33_NTZ/non_secure/port.c
  24. 95 0
      Middlewares/Third_Party/FreeRTOS/Source/tasks.c
  25. 39 0
      imc/exprs/dac2025/1_measure_timings/draw_graph_expr_1.ipynb
  26. 94 0
      imc/exprs/dac2025/1_measure_timings/draw_graph_expr_1.py
  27. 55 0
      imc/exprs/dac2025/1_measure_timings/run_expr_1.py
  28. 42 0
      imc/exprs/dac2025/2_error_low_voltage/draw_graph_expr_2.ipynb
  29. 59 0
      imc/exprs/dac2025/2_error_low_voltage/draw_graph_expr_2.py
  30. 171 0
      imc/exprs/dac2025/2_error_low_voltage/run_expr_2.py
  31. 88 0
      imc/exprs/dac2025/3_fmc_error/draw_graph_expr_3.ipynb
  32. 78 0
      imc/exprs/dac2025/3_fmc_error/draw_graph_expr_3.py
  33. 170 0
      imc/exprs/dac2025/3_fmc_error/run_expr_3.py
  34. 66 0
      imc/exprs/dac2025/4_energy_efficiency/draw_graph_expr_4.ipynb
  35. 152 0
      imc/exprs/dac2025/4_energy_efficiency/draw_graph_expr_4.py
  36. 189 0
      imc/exprs/dac2025/4_energy_efficiency/run_expr_4.py
  37. 55 0
      imc/exprs/dac2025/build_and_program.py
  38. 5 0
      imc/exprs/dac2025/set_smu_current.py
  39. 8 11
      imc/exprs/date2025/1_overhead_stable_power/draw_graph_expr_1.ipynb
  40. 81 36
      imc/exprs/date2025/1_overhead_stable_power/draw_graph_expr_1.py
  41. 63 32
      imc/exprs/date2025/1_overhead_stable_power/run_expr_1.py
  42. 52 0
      imc/exprs/date2025/3_adaptive/debug_output.py
  43. 72 4
      imc/exprs/date2025/3_adaptive/draw_graph_expr_3.ipynb
  44. 121 45
      imc/exprs/date2025/3_adaptive/draw_graph_expr_3.py
  45. 37 13
      imc/exprs/date2025/3_adaptive/run_expr_3.py
  46. 106 0
      imc/exprs/date2025/4_decide_pass_count/measure_current.py
  47. 5 2
      imc/exprs/date2025/4_decide_pass_count/run_expr_4.py
  48. 66 11
      imc/exprs/date2025/5_size_overhead/draw_graph_expr_5.py
  49. 55 8
      imc/exprs/date2025/5_size_overhead/run_expr_5.py
  50. 807 0
      imc/exprs/date2025/6_varying_power/data/2015-04-22-Sacramento.csv
  51. 809 0
      imc/exprs/date2025/6_varying_power/data/2015-04-23-Sacramento.csv
  52. 41 0
      imc/exprs/date2025/6_varying_power/draw_graph_expr_6.ipynb
  53. 350 0
      imc/exprs/date2025/6_varying_power/draw_graph_expr_6.py
  54. 198 0
      imc/exprs/date2025/6_varying_power/run_expr_6.py
  55. 62 0
      imc/exprs/date2025/7_latency_overhead/draw_graph_7.ipynb
  56. 123 0
      imc/exprs/date2025/7_latency_overhead/draw_graph_7.py
  57. 111 0
      imc/exprs/date2025/7_latency_overhead/run_expr_7.py
  58. 13 0
      imc/exprs/etc/measure_init_time/measure_init_time.py
  59. 28 0
      imc/exprs/etc/test/scope_test.ipynb
  60. 17 0
      imc/exprs/etc/test/scope_test.py
  61. 12 0
      imc/reports/2024_ktl/draw_graph_test_1.py
  62. 29 0
      imc/reports/2024_ktl/test_1.ipynb
  63. 143 0
      imc/reports/2024_ktl/test_1.py
  64. 52 0
      imc/reports/2024_ktl/test_1_analysis.py
  65. 111 0
      imc/reports/2024_ktl/test_1_current_measure.py
  66. 122 0
      imc/reports/2024_ktl/test_2.py
  67. 70 0
      imc/reports/2024_ktl/test_2_analysis.py
  68. 141 0
      imc/reports/2024_ktl/test_2_new.py
  69. 134 0
      imc/reports/2024_ktl/test_3.py
  70. 57 0
      imc/reports/2024_ktl/test_3_analysis.py
  71. 144 0
      imc/reports/2024_ktl/test_3_new.py
  72. 143 0
      imc/reports/2024_ktl_export/test_1.py
  73. 52 0
      imc/reports/2024_ktl_export/test_1_analysis.py
  74. 144 0
      imc/reports/2024_ktl_export/test_2.py
  75. 70 0
      imc/reports/2024_ktl_export/test_2_analysis.py
  76. 144 0
      imc/reports/2024_ktl_export/test_3.py
  77. 57 0
      imc/reports/2024_ktl_export/test_3_analysis.py
  78. 20 0
      imc/utils/set_smu.py
  79. 39 3
      imc_extension.cmake
  80. 5 3
      setup_build_dir.py

+ 1 - 0
.gitignore

@@ -8,5 +8,6 @@ imc_freertos_app_m33.launch
 build/
 build.sh
 imc/exprs/**/output**
+imc/reports/**/output**
 __pycache__
 imc/exprs/**/*.pdf

+ 5 - 1
CMakeLists.txt

@@ -76,6 +76,7 @@ set(SRC_FILES
     Drivers/STM32L5xx_HAL_Driver/Src/stm32l5xx_hal_uart_ex.c
     Drivers/STM32L5xx_HAL_Driver/Src/stm32l5xx_ll_fmc.c
     Drivers/STM32L5xx_HAL_Driver/Src/stm32l5xx_ll_usb.c
+    Drivers/STM32L5xx_HAL_Driver/Src/stm32l5xx_hal_comp.c
     Core/Startup/startup_stm32l552zetx.s
     Core/Src/sc03mpd/sc03mpd.c
     Core/Src/ImC/decoder.c
@@ -204,6 +205,9 @@ else()
             set(IMC_FLAGS ${IMC_BASE})
             # set(TARGET_TRIPPLE "--target=armv7em-none-eabi --sysroot=${CMAKE_SYSROOT}")
 
+            # set(IMC_OPT_FLAGS "-disable-loop-unrolling")
+            set(IMC_OPT_FLAGS "")
+
             foreach(APP_SRC ${IMC_APP_FILES})
                 add_custom_command(
                     OUTPUT ${PROJECT_BINARY_DIR}/${APP_SRC}.s
@@ -211,7 +215,7 @@ else()
                     # COMMAND ${CLANG_BIN} --target=armv8m-none-eabi --sysroot=${CMAKE_SYSROOT} -g ${C_FLAGS} -O0 -Xclang -disable-O0-optnone ${INCLUDE_DIRS} -D USE_HAL_DRIVER -D STM32L552xx -c -emit-llvm ${PROJECT_SOURCE_DIR}/${APP_SRC} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
                     COMMAND ${CMAKE_C_COMPILER} -g ${C_FLAGS} -O0 -Xclang -disable-O0-optnone ${INCLUDE_DIRS} -D USE_HAL_DRIVER -D STM32L552xx -c -emit-llvm ${PROJECT_SOURCE_DIR}/${APP_SRC} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
                     COMMAND ${OPT_BIN} -o ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc -load-pass-plugin=${LLVM_OPT_PLUGIN} -passes=${BASIC_OPT_PASSES},${IMC_OPT_PASSES} ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
-                    COMMAND ${OPT_BIN} ${OPT} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc
+                    COMMAND ${OPT_BIN} ${OPT} ${IMC_OPT_FLAGS} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc
                     COMMAND ${LLC_BIN} ${IMC_FLAGS} ${CPU} ${OPT} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.s ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc
                 )
                 list(APPEND APP_OPTS ${PROJECT_BINARY_DIR}/${APP_SRC}.s)

+ 36 - 1
Core/Inc/ImC/imc_extension.h

@@ -37,10 +37,22 @@
     #define imcPRINT_STATS 0
 #endif
 
+#ifndef imcPRINT_INIT_TIME
+    #define imcPRINT_INIT_TIME 0
+#endif
+
+#ifndef imcPRINT_LATENCY_OVERHEAD
+    #define imcPRINT_LATENCY_OVERHEAD 0
+#endif
+
 #ifndef imcCUSTOM_UNROLL
     #define imcCUSTOM_UNROLL 0 
 #endif
 
+#ifndef imcENABLE_DYNAMIC_CHECKPOINT
+    #define imcENABLE_DYNAMIC_CHECKPOINT 0
+#endif
+
 #define IMC_KERNEL_NVM __attribute__((section(".kernel_nvm")))
 
 #define imcCAP_VOL_HIGH 4800
@@ -53,7 +65,7 @@
 #define IMC_UNROLL(x) DO_PRAGMA( clang loop unroll_count(x+1) )
 #define IMC_UNROLL_FULL() DO_PRAGMA( clang loop unroll(full) )
 #else
-#define IMC_UNROLL(x) 
+#define IMC_UNROLL(x)
 #define IMC_UNROLL_FULL()
 #endif
 
@@ -63,9 +75,32 @@ void __imc_finish_loop_skipping();
 void imc_init_energy_estimation();
 void imc_recover_estimations();
 void imc_backup_estimations();
+void imc_print_estimations();
 
+#if (imcPRINT_STATS)
 extern int imc_is_passing_loops;
 extern int imc_checkpoint_triggered;
 extern int imc_checkpoint_executed;
+void imc_backup_stats();
+void imc_recover_stats();
+extern int first_checkpoint;
+extern int no_forward_progress;
+#endif
+
+#if (imcPRINT_LATENCY_OVERHEAD)
+extern unsigned int imc_ticks_init;
+extern unsigned int imc_ticks_getCSC;
+extern unsigned int imc_ticks_adjust;
+extern unsigned int imc_ticks_total;
+extern unsigned int imc_last_tick;
+void imc_backup_latency_overhead();
+void imc_recover_latency_overhead();
+#endif
+
+#ifndef imcLOOP_OPT_DEBUG
+    #define imcLOOP_OPT_DEBUG 0
+#endif
+
+void ckptTask();
 
 #endif

+ 4 - 1
Core/Inc/ImC/imc_kernel.h

@@ -18,7 +18,7 @@
 #endif
 
 #ifndef imcCHECKPOINT_VOLTAGE
-    #define imcCHECKPOINT_VOLTAGE 3600 //in mV
+    #define imcCHECKPOINT_VOLTAGE 3620 //in mV
 #endif
 
 #define imcSTM32_CUBE_IDE 0
@@ -30,6 +30,8 @@
 
 #define portSVC_IMC_REQUEST_CHECKPOINT 6
 
+#define portSVC_IMC_CHECKPOINT_ALL_TASKS 7
+
 #define imcREQUEST_CHECKPOINT() \
     {                           \
         __asm("  svc #6");      \
@@ -43,6 +45,7 @@ osThreadId_t imcOsThreadNew(osThreadFunc_t func, void *argument, const osThreadA
 void vImcInvalidateRecovery();
 int needCheckpointExecution();
 
+
 extern int checkpointCounter;
 extern const int checkpoint_pass_count;
 

+ 2 - 0
Core/Inc/benchmarks/benchmark_driver.h

@@ -14,6 +14,8 @@ void vMatMul();
 void vConv2d();
 void adc_demo();
 void vAes();
+void fmc_expr();
+void vrefint_expr();
 
 void vBenchmarkDriver(void *_benchmark);
 

+ 1 - 1
Core/Inc/stm32l5xx_hal_conf.h

@@ -35,7 +35,7 @@
   */
 #define HAL_MODULE_ENABLED
 #define HAL_ADC_MODULE_ENABLED
-/*#define HAL_COMP_MODULE_ENABLED   */
+#define HAL_COMP_MODULE_ENABLED 
 /*#define HAL_CRC_MODULE_ENABLED   */
 /*#define HAL_CRYP_MODULE_ENABLED   */
 /*#define HAL_DAC_MODULE_ENABLED   */

+ 2 - 1
Core/Src/ImC/imc_api.c

@@ -263,7 +263,8 @@ int medianCalc(int* input, int arr_size){
 
 // uint16_t MEAS_COEF[2] = {812, 782};	// for EPS CAP ch0 and ch1
 // uint16_t MEAS_COEF[2] = {700, 782};	// imc, 10mF
-uint16_t MEAS_COEF[2] = {770, 782};	// imc, 4.7mF, voltage divider
+// uint16_t MEAS_COEF[2] = {765, 782};	// imc, 4.7mF, voltage divider
+uint16_t MEAS_COEF[2] = {771, 782};	// imc, 4.7mF, voltage divider
 int measure_voltage(ADC_HandleTypeDef hadc, uint8_t ch){
 	int val;
 	// for(int i=0; i<100; i++) { __ASM(" nop"); }

+ 276 - 44
Core/Src/ImC/imc_extension.c

@@ -7,53 +7,150 @@
 
 extern ADC_HandleTypeDef ADC_HANDLER_SBC;
 
-// int loop_pass_estimation_backup[imcMAX_LOOP_IDS] IMC_KERNEL_NVM;
-int loop_pass_estimation[imcMAX_LOOP_IDS];
+float loop_pass_estimation[imcMAX_LOOP_IDS];
 int imc_is_passing_loops_backup IMC_KERNEL_NVM;
 int imc_is_passing_loops;
 int imc_energy_at_start;
 
-int estimation_backup[2][imcMAX_LOOP_IDS] IMC_KERNEL_NVM;
+float estimation_backup[2][imcMAX_LOOP_IDS] IMC_KERNEL_NVM;
 int imc_energy_estimation_initialized IMC_KERNEL_NVM;
 int latest_buffer_index IMC_KERNEL_NVM;
 int last_loop_skip_count;
 int pass_due_to_low_energy;
 
+#define imcLOOP_OPT_DEBUG_VERBOSE 0
+
 #if(imcPRINT_STATS)
-    int imc_checkpoint_triggered IMC_KERNEL_NVM;
-    int imc_checkpoint_executed IMC_KERNEL_NVM;
+    int imc_checkpoint_triggered;
+    int imc_checkpoint_executed;
+    int imc_checkpoint_triggered_backup[2] IMC_KERNEL_NVM;
+    int imc_checkpoint_executed_backup[2] IMC_KERNEL_NVM;
+    int stat_buffer_index IMC_KERNEL_NVM;
+
+    int first_checkpoint IMC_KERNEL_NVM;
+    int no_forward_progress;
+    int imc_no_forward_progress_backup[2] IMC_KERNEL_NVM;
+
+    void imc_recover_stats() {
+        imc_checkpoint_triggered = imc_checkpoint_triggered_backup[stat_buffer_index];
+        imc_checkpoint_executed = imc_checkpoint_executed_backup[stat_buffer_index];
+        no_forward_progress = imc_no_forward_progress_backup[stat_buffer_index];
+    }
+
+    void imc_backup_stats() {
+        int nextBufferIndex = stat_buffer_index == 0 ? 1: 0;
+        imc_checkpoint_triggered_backup[nextBufferIndex] = imc_checkpoint_triggered;
+        imc_checkpoint_executed_backup[nextBufferIndex] = imc_checkpoint_executed;
+        imc_no_forward_progress_backup[nextBufferIndex] = no_forward_progress;
+        stat_buffer_index = nextBufferIndex;
+    }
+#endif
+
+#if (imcPRINT_LATENCY_OVERHEAD)
+    unsigned int imc_ticks_init;
+    unsigned int imc_ticks_getCSC;
+    unsigned int imc_ticks_adjust;
+    unsigned int imc_ticks_total;
+    int imc_latency_overhead_buffer_index IMC_KERNEL_NVM;
+
+    unsigned int imc_last_tick;
+
+    unsigned int imc_ticks_init_backup[2] IMC_KERNEL_NVM;
+    unsigned int imc_ticks_getCSC_backup[2] IMC_KERNEL_NVM;
+    unsigned int imc_ticks_adjust_backup[2] IMC_KERNEL_NVM;
+    unsigned int imc_ticks_total_backup[2] IMC_KERNEL_NVM;
+
+    void imc_recover_latency_overhead() {
+        int index = imc_latency_overhead_buffer_index;
+        imc_ticks_init = imc_ticks_init_backup[index];
+        imc_ticks_getCSC = imc_ticks_getCSC_backup[index];
+        imc_ticks_adjust = imc_ticks_adjust_backup[index];
+        imc_ticks_total = imc_ticks_total_backup[index];
+    }
+
+    void imc_backup_latency_overhead() {
+        unsigned int tick = DWT->CYCCNT;
+        imc_ticks_total += tick - imc_last_tick;
+        imc_last_tick = tick;
+
+        int next_buffer_index = imc_latency_overhead_buffer_index == 0 ? 1 : 0;
+        imc_ticks_init_backup[next_buffer_index] = imc_ticks_init;
+        imc_ticks_getCSC_backup[next_buffer_index] = imc_ticks_getCSC;
+        imc_ticks_adjust_backup[next_buffer_index] = imc_ticks_adjust;
+        imc_ticks_total_backup[next_buffer_index] = imc_ticks_total;
+        imc_latency_overhead_buffer_index = next_buffer_index;
+    }
 #endif
 
-void imc_recover_estimations() {
-    memcpy(loop_pass_estimation, estimation_backup[latest_buffer_index], sizeof(int) * imcMAX_LOOP_IDS);
+    void imc_recover_estimations()
+    {
+    #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
+        printf("(DEBUG) recover estimation table from buffer %d\r\n", latest_buffer_index);
+    #endif
+    memcpy(loop_pass_estimation, estimation_backup[latest_buffer_index], sizeof(float) * imcMAX_LOOP_IDS);
     __DSB();
 }
 
 void imc_backup_estimations() {
     int nextBufferIndex = latest_buffer_index == 0 ? 1 : 0;
-    memcpy(estimation_backup[nextBufferIndex], loop_pass_estimation, sizeof(int) * imcMAX_LOOP_IDS);
-    __DSB();
+    #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
+        printf("(DEBUG) backup estimation table to buffer %d\r\n", nextBufferIndex);
+    #endif
+    memcpy(estimation_backup[nextBufferIndex], loop_pass_estimation, sizeof(float) * imcMAX_LOOP_IDS);
     latest_buffer_index = nextBufferIndex;
     __DSB();
 }
 
+void imc_print_estimations() {
+    portDISABLE_INTERRUPTS();
+    for(int i=0; i<imcMAX_LOOP_IDS; i++) {
+        printf("(DEBUG) loop_#%d: %f\r\n", i, loop_pass_estimation[i]);
+    }
+    portENABLE_INTERRUPTS();
+}
+
 void imc_init_energy_estimation() {
+    #if (imcPRINT_LATENCY_OVERHEAD)
+        unsigned int start_tick = DWT->CYCCNT;
+    #endif
+
     if(!imc_energy_estimation_initialized) {
+        #if(imcLOOP_OPT_DEBUG)
+            printf("(DEBUG) initialize estimation table\r\n");
+        #endif
         for(int i=0; i<imcMAX_LOOP_IDS; i++) {
-            loop_pass_estimation[i] = 1;
+            loop_pass_estimation[i] = 2;
         }
         latest_buffer_index = 0;
+        #if(imcPRINT_STATS)
+            stat_buffer_index = 0;
+        #endif
         imc_backup_estimations();
     } else {
         imc_recover_estimations();
     }
 
+    #if (imcPRINT_LATENCY_OVERHEAD)
+        unsigned int end_tick = DWT->CYCCNT;
+        imc_ticks_init += end_tick - start_tick;
+    #endif
+
     if(imc_energy_estimation_initialized && imc_is_passing_loops_backup != -1) {
         int loop_id = imc_is_passing_loops_backup;
-        int new_estimation = loop_pass_estimation[loop_id] / 2;
+        float new_estimation = loop_pass_estimation[loop_id] / 3;
+        // int new_estimation = loop_pass_estimation[loop_id];
+        // if(new_estimation >= 20) new_estimation /= 10;
+        // else if(new_estimation < 20 && new_estimation > 2) new_estimation = 2;
+        // else if(new_estimation == 2) new_estimation = 1;
+        // else new_estimation = 0;
+
         loop_pass_estimation[loop_id] = new_estimation;
         estimation_backup[latest_buffer_index][loop_id] = new_estimation;
-        // printf("(recovery) estimation for loop %d is updated to %d\r\n", loop_id, loop_pass_estimation[loop_id]);
+        #if (imcLOOP_OPT_DEBUG)
+            portDISABLE_INTERRUPTS();
+            printf("(DEBUG) (recovery) estimation for loop %d is updated to %f\r\n", loop_id, loop_pass_estimation[loop_id]);
+            portENABLE_INTERRUPTS();
+        #endif
     }
     imc_energy_estimation_initialized = 1;
     imc_is_passing_loops_backup = -1;
@@ -61,90 +158,205 @@ void imc_init_energy_estimation() {
     __DSB();
 }
 
-void __imc_unflag_loop_skipping()
+
+int get_current_energy() {
+    int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
+    int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
+    return energy;
+}
+
+
+void update_estimation(int loop_id, int counter, int current_energy, int energy_at_start) {
+    float current_estimation = (float)loop_pass_estimation[loop_id];
+    if(current_estimation > 1e6) return;
+    const float error_margin = imcENERGY_TOTAL * 0.03;
+    float max_consumed = energy_at_start + error_margin - (current_energy - error_margin);
+    float min_consumed = energy_at_start - error_margin - (current_energy + error_margin);
+    if(max_consumed <= 0) max_consumed = 1e-3;
+    if(min_consumed <= 0) {
+        min_consumed = 1e-3;
+    }
+
+    float measured_min = ((float)(imcENERGY_TOTAL)) / max_consumed * counter;
+    // measured_min *= 2.5;
+    float measured_max = ((float)(imcENERGY_TOTAL)) / min_consumed * counter;
+    // measured_max *= 2;
+
+    // float measured_iterations = ((float)(imcENERGY_TOTAL)) / energy_consumed * counter;
+    // float variance_margin = 1;
+    // float outlier_factor = 5;
+    // int too_large_measured = measured_iterations > outlier_factor * current_estimation;
+    // int too_small_measured = outlier_factor * measured_iterations < current_estimation;
+
+    // printf("(DEBUG) lood_id:%d, counter:%d, consumed: %d, measured: %f, current: %f\r\n", loop_id, counter, energy_consumed, measured_iterations, current_estimation);
+
+    // if(too_large_measured || too_small_measured) return;
+
+    float new_estimation;
+
+    if(measured_max < current_estimation) {
+        float factor = measured_max / current_estimation;
+        float factor_max = 0.25;
+        factor = factor < factor_max ? factor_max : factor;
+        new_estimation = current_estimation * factor;
+        loop_pass_estimation[loop_id] = new_estimation;
+    } else if (measured_min > current_estimation) {
+        float factor = measured_min / current_estimation;
+        float factor_max = 3;
+        factor = factor > factor_max ? factor_max : factor;
+        new_estimation = current_estimation * factor;
+        loop_pass_estimation[loop_id] = new_estimation;
+    }
+    else return;
+
+    #if(imcLOOP_OPT_DEBUG)
+    portDISABLE_INTERRUPTS();
+    printf("(DEBUG) estimation for loop %d is updated to %f\r\n", loop_id, new_estimation);
+    portENABLE_INTERRUPTS();
+    #endif
+
+    imc_backup_estimations();
+}
+
+
+void __imc_unflag_loop_skipping(int loop_id, int counter)
 {
+    if(loop_id != imc_is_passing_loops) return;
+
+    #if (imcPRINT_LATENCY_OVERHEAD)
+        unsigned int start_tick = DWT->CYCCNT;
+    #endif
+
+    int energy = get_current_energy();
+    int energy_consumed = imc_energy_at_start - energy;
+    // printf("(DEBUG) energy consumed: %d\r\n", energy_consumed);
+
+    update_estimation(loop_id, counter, energy, imc_energy_at_start);
+    // float measured_iterations = ((float)(imcENERGY_TOTAL)) / energy_consumed * counter;
+    // float current_estimation = (float)loop_pass_estimation[loop_id];
+
+    // printf("(DEBUG) loop_id:%d, counter:%d, measured: %f, estimation: %f\r\n", loop_id, counter, measured_iterations, current_estimation);
+
     imc_is_passing_loops_backup = -1;
     imc_is_passing_loops = -1;
     __DSB();
+
+    #if (imcPRINT_LATENCY_OVERHEAD)
+        unsigned int end_tick = DWT->CYCCNT;
+        imc_ticks_adjust += end_tick - start_tick;
+    #endif
 }
 
+
 void __imc_finish_loop_skipping() {
     int loop_id = imc_is_passing_loops;
+
+    #if (imcPRINT_LATENCY_OVERHEAD)
+        unsigned int start_tick = DWT->CYCCNT;
+    #endif
+
     if(loop_id == 0) {
-        printf("imc_is_passing_loop is 0\r\n");
+        printf("(DEBUG) imc_is_passing_loop is 0\r\n");
         while(1) { __ASM("  nop"); }
     }
     if(loop_id > 0) {
-        int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
-        // printf("imc_finish_loop_skipping() called with loopId = %d\r\n", loop_id);
-        int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
-        // int ratio = energy * 100 / imcENERGY_TOTAL;
-
+        // int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
+        // int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
+        #if(imcLOOP_OPT_DEBUG)
+            printf("(DEBUG) loop %d is not perfectly skipped\r\n", loop_id);
+        #endif
+        int energy = get_current_energy();
         int energy_consumed = imc_energy_at_start - energy;
-        // int consumed_ratio = energy_consumed * 100 / imcENERGY_TOTAL;
 
-        // if(ratio > 5) {
-        // printf("last loop skip count: %d\r\n", last_loop_skip_count);
         int last_skip_is_zero = last_loop_skip_count == 0;
-        int energy_per_iteration = energy_consumed / last_loop_skip_count;
-        int underestimated = energy_per_iteration * 10 < energy;
-        // if(energy_consumed / last_loop_skip_count < 2 * energy) {
+        if(!last_skip_is_zero) {
+            update_estimation(loop_id, last_loop_skip_count, energy, imc_energy_at_start);
+        }
+
+        /*
+        float possible_iterations_estimated = 0;
+        int underestimated = 0;
+        if(!last_skip_is_zero) {
+            float energy_per_iteration = (float)energy_consumed / last_loop_skip_count;
+            possible_iterations_estimated = (float)energy / energy_per_iteration;
+            underestimated = possible_iterations_estimated > 3;
+        }
         if(!last_skip_is_zero && underestimated) {
             int current_estimation = loop_pass_estimation[loop_id];
-            // printf("current estimation for loop_%d: %d\r\n", loop_id, current_estimation);
-            double inc_factor = 2;
+            // double inc_factor = 2.5;
+            double inc_factor = possible_iterations_estimated > 3 ? 3 : possible_iterations_estimated;
             if (current_estimation * inc_factor > (double)INT32_MAX)
             {
-                // printf("remaining energy: %d\r\n", remaining_energy);
                 current_estimation = INT32_MAX/2-1;
             }
             else
             {
                 current_estimation = (int)(current_estimation * inc_factor);
-                // printf("remaining energy: %d\r\n", remaining_energy);
             }
+            
             if (current_estimation < 1) {
                 current_estimation = 1;
             }
             loop_pass_estimation[loop_id] = current_estimation;
-            // loop_pass_estimation_backup[loop_id] = current_estimation;
-            portDISABLE_INTERRUPTS();
-            // printf("estimation for loop %d is updated to %d\r\n", loop_id, current_estimation);
-            portENABLE_INTERRUPTS();
+            #if (imcLOOP_OPT_DEBUG)
+                portDISABLE_INTERRUPTS();
+                printf("(DEBUG) estimation for loop %d is updated to %d\r\n", loop_id, current_estimation);
+                portENABLE_INTERRUPTS();
+            #endif
+        imc_backup_estimations();
+        } else {
+            #if (imcLOOP_OPT_DEBUG)
+                portDISABLE_INTERRUPTS();
+                printf("(DEBUG) estimation for loop %d is not updated (%d)\r\n", loop_id, loop_pass_estimation[loop_id]);
+                portENABLE_INTERRUPTS();
+            #endif
         }
+        */
     }
     imc_is_passing_loops_backup = -1;
     imc_is_passing_loops = -1;
     __DSB();
+
+    #if (imcPRINT_LATENCY_OVERHEAD)
+        unsigned int end_tick = DWT->CYCCNT;
+        imc_ticks_adjust += end_tick - start_tick;
+    #endif
 }
 
 int __imc_get_loop_pass_count(int loop_id) {
     #if(imcENABLE_STATIC_LOOP_PASS_COUNT)
         return imcLOOP_PASS_COUNT;
     #elif(imcENABLE_ADAPTIVE_LOOP_PASS_COUNT)
+        if(imc_is_passing_loops != -1) return INT32_MAX;
+        #if (imcPRINT_LATENCY_OVERHEAD)
+            unsigned int start_tick = DWT->CYCCNT;
+        #endif
+
         int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
-        // if(volt < imcCHECKPOINT_VOLTAGE) {
-        //     imcREQUEST_CHECKPOINT();
-        // }
         int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
         int ratio = energy * 100 / imcENERGY_TOTAL;
-        // float energy_available = (float)(volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW) / imcENERGY_TOTAL;
+
         imc_is_passing_loops = loop_id;
         imc_is_passing_loops_backup = loop_id;
         __DSB();
         imc_energy_at_start = energy;
-        // printf("write %d to imc_is_passing_loops\r\n", imc_is_passing_loops);
-        // printf("energy available: %f\r\n", energy_available);
-        // if(energy_available > 1) return (int)(energy_available / loop_energy_estimation[loop_id]);
-        // else if(energy_available < 0) return 0;
-        // else return (int)(energy_available / loop_energy_estimation[loop_id]);
-        int current_estimation = loop_pass_estimation[loop_id];
+
+        #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
+            printf("(DEBUG) ratio: %d\r\n", ratio);
+        #endif
+
+        float current_estimation = loop_pass_estimation[loop_id];
         if(ratio > 100) {
             last_loop_skip_count = current_estimation;
         }
-        else if(ratio < 0) {
+        else if(ratio < 5) {
             last_loop_skip_count = 0;
+            imc_is_passing_loops = -1;
+            imc_is_passing_loops_backup = -1;
             // imc_sbc_power_off();
+            #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
+                printf("(DEBUG) ratio: %d\r\n", ratio);
+            #endif
             // while(1) { __ASM(" nop"); }
             // printf("__imc_get_loop_pass_count(%d) called; %d returned\r\n", loop_id, last_loop_skip_count);
         }
@@ -154,8 +366,28 @@ int __imc_get_loop_pass_count(int loop_id) {
             // last_loop_skip_count = loop_pass_estimation[loop_id] * ((double)(ratio) / 100.0);
         }
         // printf("loopId: %d, volt: %d, energy: %d, total: %d, ratio: %d, est:%d, count:%d\r\n", loop_id, volt, energy, imcENERGY_TOTAL, ratio, current_estimation, last_loop_skip_count);
+        #if (imcPRINT_LATENCY_OVERHEAD)
+            unsigned int end_tick = DWT->CYCCNT;
+            imc_ticks_getCSC += end_tick - start_tick;
+        #endif
         return last_loop_skip_count;
     #else
         return 0;
     #endif
+}
+
+void ckptTask() {
+    while(1) {
+    int volt = measure_voltage(ADC_HANDLER_SBC, 0);
+        // __asm(" svc 7");
+    if(volt < 3660) {
+        HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+        __asm(" svc 7");
+        imc_sbc_power_off();
+        while(1) __asm(" nop");
+    }
+    // printf("volt: %d\r\n", volt);
+    const TickType_t xDelay = 25 / portTICK_PERIOD_MS;
+    osDelay(xDelay);
+    }
 }

+ 23 - 1
Core/Src/ImC/imc_kernel.c

@@ -23,6 +23,13 @@ void imcInit()
     FPU->FPCCR &= ~(FPU_FPCCR_LSPEN_Msk); // turn off lazy stacking
     #if(imcUSE_IMC_EXTENSION)
         imc_init_energy_estimation();
+        #if(imcPRINT_STATS)
+            if(first_checkpoint == -1) {
+                no_forward_progress += 1;
+                imc_backup_stats();
+            }
+            first_checkpoint = -1;
+        #endif
     #endif
 }
 
@@ -51,4 +58,19 @@ int needCheckpointExecution() {
     #if(!imcUSE_CHECKPOINT_VOLTAGE_CHECK && !imcUSE_CHECKPOINT_PASS_COUNTER)
         return 1;
     #endif
-}
+}
+
+void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) {
+    // if(GPIO_Pin == GPIO_PIN_9 || GPIO_Pin == GPIO_PIN_3) {
+    //     HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+    //     printf("interrupt (falling)\r\n");
+    // }
+    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+}
+
+// void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin) {
+//     if(GPIO_Pin == GPIO_PIN_9 || GPIO_Pin == GPIO_PIN_3) {
+//         HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+//         printf("interrupt (rising)\r\n");
+//     }
+// }

+ 24 - 2
Core/Src/benchmarks/adc_demo/adc_demo.c

@@ -2,19 +2,41 @@
 
 #include "cmsis_os.h"
 #include "ImC/imc_api.h"
+#include "stm32l5xx_hal.h"
 
 extern ADC_HandleTypeDef ADC_HANDLER_SBC;
 
 void adc_demo()
 {
+    // while(1) {
+    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+    DWT->CYCCNT = 0;
+    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+    // HAL_Delay(2);
+    // }
     while(1) {
+        int eps_on = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_10);
         int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
+
+        // HAL_ADC_Start(&ADC_HANDLER_SBC);
+        // Poll ADC Peripheral & TimeOut = 1mSec
+        // HAL_ADC_PollForConversion(&ADC_HANDLER_SBC, 1);
+        // int val = HAL_ADC_GetValue(&ADC_HANDLER_SBC);
+        // HAL_ADC_Stop(&ADC_HANDLER_SBC);
+
+        // int vdda_milli_volt = (VREFINT_CAL_VREF * (*VREFINT_CAL_ADDR)) / val;
+        // int volt = vdda_milli_volt;
+
+        // uint32_t tick = HAL_GetTick();
+        uint32_t tick = DWT->CYCCNT;
         // HAL_ADC_Start(&ADC_HANDLER_SBC);
         // HAL_ADC_PollForConversion(&ADC_HANDLER_SBC, HAL_MAX_DELAY);
         // int volt = HAL_ADC_GetValue(&ADC_HANDLER_SBC);
         // printf("capacitor voltage: %d\r\n", volt);
         // HAL_ADC_Stop(&ADC_HANDLER_SBC);
-        printf("capacitor voltage: %d.%03d\r\n", volt/1000, volt%1000);
-        osDelay(200);
+        // printf("capacitor voltage: %d.%03d\r\n", volt/1000, volt%1000);
+        printf("%d %d %d.%03d\r\n", tick, eps_on, volt/1000, volt%1000);
+        osDelay(4);
     }
 }

+ 32 - 8
Core/Src/benchmarks/benchmark_driver.c

@@ -1,18 +1,21 @@
 #include "cmsis_os.h"
 #include "ImC/imc_kernel.h"
 #include "ImC/imc_extension.h"
+#include "stm32l5xx_hal.h"
 
 #include <stdio.h>
 
 void vBenchmarkDriver(void *_benchmark)
 {
     void (*benchmark)(void) = _benchmark;
+    int i = 0;
     #if (imcBENCH_INFINITE_LOOP)
     while(1) {
     #endif
     portDISABLE_INTERRUPTS();
-    printf("Start benchmark\r\n");
+    printf("Start benchmark (%d)\r\n", i);
     portENABLE_INTERRUPTS();
+    // HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
 
     benchmark();
 
@@ -20,22 +23,43 @@ void vBenchmarkDriver(void *_benchmark)
         portDISABLE_INTERRUPTS();
         printf("(STAT) checkpoint triggered: %d\r\n", imc_checkpoint_triggered);
         printf("(STAT) checkpoint executed: %d\r\n", imc_checkpoint_executed);
+        printf("(STAT) no forward progress: %d\r\n", no_forward_progress);
         portENABLE_INTERRUPTS();
         imc_checkpoint_triggered = 0;
         imc_checkpoint_executed = 0;
+        no_forward_progress = 0;
+    #endif
+
+    #if(imcENABLE_ADAPTIVE_LOOP_PASS_COUNT && imcPRINT_LATENCY_OVERHEAD)
+        unsigned int tick = DWT->CYCCNT;
+        imc_ticks_total += tick - imc_last_tick;
+        imc_last_tick = tick;
+        portDISABLE_INTERRUPTS();
+        printf("(STAT) cycles in init(): %d\r\n", imc_ticks_init);
+        printf("(STAT) cycles in getCSC(): %d\r\n", imc_ticks_getCSC);
+        printf("(STAT) cycles in adjust(): %d\r\n", imc_ticks_adjust);
+        printf("(STAT) total cycles: %d\r\n", imc_ticks_total);
+        portENABLE_INTERRUPTS();
+        imc_ticks_init = 0;
+        imc_ticks_getCSC = 0;
+        imc_ticks_adjust = 0;
+        imc_ticks_total = 0;
     #endif
 
     portDISABLE_INTERRUPTS();
-    printf("End benchmark\r\n");
+    printf("End benchmark (%d)\r\n", i++);
     portENABLE_INTERRUPTS();
 
-    imcREQUEST_CHECKPOINT();
+    #if (imcUSE_IMC_KERNEL == 1)
+        vImcInvalidateRecovery();
+    #endif
+
+    // imcREQUEST_CHECKPOINT();
+
+
     #if (imcBENCH_INFINITE_LOOP)
-    // osDelay(10);
     }
     #endif
 
-    #if (imcUSE_IMC_KERNEL == 1)
-        vImcInvalidateRecovery();
-    #endif
-}
+
+}

+ 3 - 0
Core/Src/benchmarks/conv2d/conv2d.c

@@ -37,10 +37,13 @@ void vConv2d()
                     int input_i = i + ii;
                     int input_j = j + jj;
                     sum += input[input_i][input_j] * kernel[ii][jj];
+                    __asm(" nop");
                 }
+                __asm(" nop");
             }
             // output[i * OUTPUT_SIZE + j] = sum;
             output[_i] = sum;
+            __asm(" nop");
         }
         // }
     }

+ 82 - 0
Core/Src/benchmarks/fmc_expr/fmc_expr.c

@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+#include "ImC/imc_api.h"
+#include "stm32l5xx_hal.h"
+
+extern ADC_HandleTypeDef ADC_HANDLER_SBC;
+
+#define FRAM_MEM_SIZE (0x100000) // 1 MiB = 2 * 512 * 1024 bytes
+#define MEM_TEST_ADDR (0x68000000U)
+#define MEMORY_SIZE (FRAM_MEM_SIZE)
+
+void fmc_expr()
+{
+    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+    DWT->CYCCNT = 0;
+    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+
+    int counter = 0;
+
+    int *fmc_base_addr = (void *)0x68000000;
+
+    while(1) {
+        // uint32_t tick = DWT->CYCCNT;
+
+        // printf("%d %d %d\r\n", tick, correct, counter);
+
+        register int errors = 0;
+        register int expval = 0x55555555;
+        register int tmpval = 0;
+        register int count = MEMORY_SIZE / sizeof(int);
+
+        volatile int *accs = (volatile int *)MEM_TEST_ADDR;
+        for (int i = 0; i < count; i++, accs++, expval ^= 0xFFFFFFFF)
+        {
+            *accs = i;
+            tmpval = *(accs + 1);
+            if (*accs != i)
+            {
+                // printf("[%p] exp=%08X, act=%08X (NOT EQUAL!!!!!!!!)\r\n", accs, expval, *accs);
+                // HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_11);
+                errors++;
+            }
+            if (i % 500 == 0) {
+                printf("%d %d %d\r\n", DWT->CYCCNT, errors, i);
+            }
+        }
+
+        printf("-- %d errors occurred. (@%p)\r\n", errors, accs);
+        printf("\r\n");
+    }
+}
+
+void test_case_1_s4(int seq, unsigned int baseaddr, int length)
+{
+    register int errors = 0;
+    register int expval = 0x55555555;
+    register int tmpval = 0;
+    register int count = length / sizeof(int);
+
+    printf("\r\n");
+    printf("==========================================\r\n");
+    printf(" [%04d] TEST CASE #1 - S4\r\n", seq);
+    printf("==========================================\r\n");
+
+    volatile int *accs = (volatile int *)baseaddr;
+    for (int i = 0; i < count; i++, accs++, expval ^= 0xFFFFFFFF)
+    {
+        *accs = expval;
+        tmpval = *(accs + 1);
+        if (*accs != expval)
+        {
+            printf("[%p] exp=%08X, act=%08X (NOT EQUAL!!!!!!!!)\r\n", accs, expval, *accs);
+            errors++;
+        }
+    }
+
+    printf("-- %d errors occurred. (@%p)\r\n", errors, accs);
+    printf("\r\n");
+}

File diff suppressed because it is too large
+ 0 - 0
Core/Src/benchmarks/sha/sha.c


+ 43 - 0
Core/Src/benchmarks/vrefint_expr/vrefint_expr.c

@@ -0,0 +1,43 @@
+#include <stdio.h>
+
+#include "cmsis_os.h"
+#include "ImC/imc_api.h"
+#include "stm32l5xx_hal.h"
+
+extern ADC_HandleTypeDef ADC_HANDLER_SBC;
+
+void vrefint_expr() {
+    LL_ADC_EnableInternalRegulator(ADC1);
+    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
+    int vref_enabled = ADC_VREFINT_INSTANCE(&hadc1);
+    printf("vref enabled: %d\r\n", vref_enabled);
+    while(1) {
+        continue;
+        // int eps_on = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_10);
+        // int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
+
+        HAL_ADC_Start(&hadc1);
+        // Poll ADC Peripheral & TimeOut = 1mSec
+        while(HAL_ADC_PollForConversion(&hadc1, 1000) != HAL_OK);
+        int val = HAL_ADC_GetValue(&hadc1);
+        // HAL_ADC_Stop(&ADC_HANDLER_SBC);
+
+
+        // int vdda_milli_volt = (VREFINT_CAL_VREF * (*VREFINT_CAL_ADDR)) / val;
+        // int volt = vdda_milli_volt;
+        int volt = val * 0.61274014;
+
+        printf("ADC val: %d, volt: %d\r\n", val, volt);
+
+        // uint32_t tick = HAL_GetTick();
+        // uint32_t tick = DWT->CYCCNT;
+        // HAL_ADC_Start(&ADC_HANDLER_SBC);
+        // HAL_ADC_PollForConversion(&ADC_HANDLER_SBC, HAL_MAX_DELAY);
+        // int volt = HAL_ADC_GetValue(&ADC_HANDLER_SBC);
+        // printf("capacitor voltage: %d\r\n", volt);
+        // HAL_ADC_Stop(&ADC_HANDLER_SBC);
+        // printf("capacitor voltage: %d.%03d\r\n", volt/1000, volt%1000);
+        // printf("%d %d %d.%03d\r\n", tick, eps_on, volt/1000, volt%1000);
+        osDelay(50);
+    }
+}

+ 130 - 11
Core/Src/main.c

@@ -109,6 +109,8 @@ SRAM_HandleTypeDef hsram2;
 SRAM_HandleTypeDef hsram3;
 SRAM_HandleTypeDef hsram4;
 
+COMP_HandleTypeDef hcomp1;
+
 /* Definitions for taskSnap */
 osThreadId_t taskSnapHandle;
 uint32_t taskSnapBuffer[ imcSTACK_SIZE ];
@@ -122,6 +124,19 @@ const osThreadAttr_t taskSnap_attributes = {
   .priority = (osPriority_t) osPriorityRealtime,
 };
 
+/* Definitions for taskSnap */
+osThreadId_t taskCkptHandle;
+uint32_t taskCkptBuffer[ imcSTACK_SIZE ];
+osStaticThreadDef_t taskCkptControlBlock;
+const osThreadAttr_t taskCkpt_attributes = {
+  .name = "taskCkpt",
+  .stack_mem = &taskCkptBuffer[0],
+  .stack_size = sizeof(taskCkptBuffer),
+  .cb_mem = &taskCkptControlBlock,
+  .cb_size = sizeof(taskCkptControlBlock),
+  .priority = (osPriority_t) osPriorityRealtime,
+};
+
 /* USER CODE BEGIN PV */
 
 /* USER CODE END PV */
@@ -145,6 +160,7 @@ static void MX_USART3_UART_Init(void);
 static void MX_ICACHE_Init(void);
 static void MX_GTZC_Init(void);
 static void MX_ADC2_Init(void);
+void MX_COMP1_Init(void);
 void taskEPSRunner(void *argument);
 void taskSnapRunner(void *argument);
 void taskAIRunner(void *argument);
@@ -219,10 +235,17 @@ int main(void)
 
   /* USER CODE BEGIN SysInit */
 
+  #if(imcPRINT_INIT_TIME || imcPRINT_LATENCY_OVERHEAD)
+  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+  DWT->CYCCNT = 0;
+  DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+  #endif
+
   /* USER CODE END SysInit */
 
   /* Initialize all configured peripherals */
   MX_GPIO_Init();
+    // HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
   MX_ADC1_Init();
   MX_FDCAN1_Init();
   MX_FMC_Init();
@@ -236,15 +259,23 @@ int main(void)
   MX_USART2_UART_Init();
   MX_USART3_UART_Init();
   MX_ICACHE_Init();
-  MX_USB_Device_Init();
-  MX_ADC2_Init();
+  // MX_COMP1_Init();
+
+  // HAL_ICACHE_Disable();
+  // MX_USB_Device_Init();
+  // MX_ADC2_Init();
   /* USER CODE BEGIN 2 */
 
   #if (imcUSE_IMC_KERNEL == 1)
     HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
     imcInit();
     MPU_RegionConfig();
-#endif
+  #endif
+
+  #if (imcENABLE_DYNAMIC_CHECKPOINT == 1)
+  // printf("dynamic checkpoint enabled\r\n");
+  #endif
+
 
   // printf("\r\n\r\n\r\n");
   // printf("**************************\r\n");
@@ -270,11 +301,22 @@ int main(void)
     // taskSnapHandle = imcOsThreadNew(taskEPSRunner, NULL, &taskSnap_attributes);
     taskSnapHandle = imcOsThreadNew(vConv2d, NULL, &taskSnap_attributes);
     #endif
+
+    #if (imcENABLE_DYNAMIC_CHECKPOINT == 1)
+    taskCkptHandle = osThreadNew(ckptTask, NULL, &taskCkpt_attributes);
+    #endif
   #else
   taskSnapHandle = osThreadNew(vBenchmarkDriver, imcBENCH_NAME, &taskSnap_attributes);
   #endif
 
   /* Start scheduler */
+  // HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
+  // HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_RESET);
+  // HAL_COMP_Start(&hcomp1);
+
+  #if(imcPRINT_INIT_TIME)
+  printf("(DEBUG) cycle: %d\r\n", DWT->CYCCNT);
+  #endif
   osKernelStart();
 
   /* We should never get here as control is now taken by the scheduler */
@@ -400,11 +442,13 @@ static void MX_ADC1_Init(void)
   */
   hadc1.Instance = ADC1;
   hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
+  // hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
   hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
   hadc1.Init.LowPowerAutoWait = DISABLE;
+  // hadc1.Init.LowPowerAutoWait = ENABLE;
   hadc1.Init.ContinuousConvMode = DISABLE;
   hadc1.Init.NbrOfConversion = 1;
   hadc1.Init.DiscontinuousConvMode = DISABLE;
@@ -425,19 +469,21 @@ static void MX_ADC1_Init(void)
 
   /** Configure the ADC multi-mode
   */
-  multimode.Mode = ADC_MODE_INDEPENDENT;
-  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
-  {
-    Error_Handler();
-  }
+  // multimode.Mode = ADC_MODE_INDEPENDENT;
+  // if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
+  // {
+  //   Error_Handler();
+  // }
 
   /** Configure Regular Channel
   */
   sConfig.Channel = ADC_CHANNEL_1;
+  // sConfig.Channel = ADC_CHANNEL_VREFINT;
   sConfig.Rank = ADC_REGULAR_RANK_1;
   sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
   // sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
   // sConfig.SamplingTime = ADC_SAMPLETIME_24CYCLES_5;
+  // sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5;
   sConfig.SingleDiff = ADC_SINGLE_ENDED;
   sConfig.OffsetNumber = ADC_OFFSET_NONE;
   sConfig.Offset = 0;
@@ -1251,7 +1297,7 @@ static void MX_GPIO_Init(void)
   HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11, GPIO_PIN_RESET);
 
   /*Configure GPIO pin Output Level */
-  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
+  // HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
 
   /*Configure GPIO pin Output Level */
   HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_11|GPIO_PIN_15, GPIO_PIN_RESET);
@@ -1260,7 +1306,7 @@ static void MX_GPIO_Init(void)
   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
 
   /*Configure GPIO pin Output Level */
-  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
+  // HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
 
   /*Configure GPIO pins : PC13 PC6 */
   GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_6;
@@ -1277,7 +1323,8 @@ static void MX_GPIO_Init(void)
   HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
 
   /*Configure GPIO pins : PF8 PF9 PF10 */
-  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
+  // GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
+  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_10;
   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
@@ -1332,6 +1379,41 @@ static void MX_GPIO_Init(void)
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
   HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
 
+  // PF11 and 10
+  GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_10;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
+
+  #if(imcENABLE_DYNAMIC_CHECKPOINT == 1)
+  // PF9
+  // GPIO_InitStruct.Pin = GPIO_PIN_9;
+  // GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+  // GPIO_InitStruct.Pull = GPIO_NOPULL;
+  // HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PD3 */
+  // GPIO_InitStruct.Pin = GPIO_PIN_3;
+  // GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
+  // GPIO_InitStruct.Pull = GPIO_PULLUP;
+  // HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+  /* EXTI interrupt init*/
+  // HAL_NVIC_SetPriority(EXTI9_IRQn, 5, 0);
+  // HAL_NVIC_EnableIRQ(EXTI9_IRQn);
+
+  /* EXTI interrupt init*/
+  // HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);
+  // HAL_NVIC_EnableIRQ(EXTI3_IRQn);
+#endif
+
+  // PF10
+  // GPIO_InitStruct.Pin = GPIO_PIN_10;
+  // GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+  // GPIO_InitStruct.Pull = GPIO_NOPULL;
+  // HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
+
 /* USER CODE BEGIN MX_GPIO_Init_2 */
 /* USER CODE END MX_GPIO_Init_2 */
 }
@@ -1362,6 +1444,38 @@ void MPU_RegionConfig(void)
   HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
 }
 
+void MX_COMP1_Init(void)
+{
+
+  /* USER CODE BEGIN COMP1_Init 0 */
+
+  /* USER CODE END COMP1_Init 0 */
+
+  /* USER CODE BEGIN COMP1_Init 1 */
+
+  /* USER CODE END COMP1_Init 1 */
+  hcomp1.Instance = COMP1;
+  // hcomp1.Init.InputMinus = COMP_INPUT_MINUS_VREFINT;
+  hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT;
+  hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO2;
+  // hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
+  hcomp1.Init.OutputPol = COMP_OUTPUTPOL_INVERTED;
+  hcomp1.Init.Hysteresis = COMP_HYSTERESIS_NONE;
+  // hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH;
+  hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE;
+  hcomp1.Init.Mode = COMP_POWERMODE_HIGHSPEED;
+  hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
+  hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_FALLING;
+  // hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING;
+  if (HAL_COMP_Init(&hcomp1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /* USER CODE BEGIN COMP1_Init 2 */
+
+  /* USER CODE END COMP1_Init 2 */
+}
+
 /* USER CODE BEGIN 4 */
 
 /* USER CODE END 4 */
@@ -1608,6 +1722,11 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
   /* USER CODE END Callback 1 */
 }
 
+void HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp) {
+  // printf("comparator triggered\r\n");
+  HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_SET);
+}
+
 /**
   * @brief  This function is executed in case of error occurrence.
   * @retval None

+ 108 - 53
Core/Src/stm32l5xx_hal_msp.c

@@ -84,25 +84,21 @@ void HAL_MspInit(void)
   /* USER CODE END MspInit 1 */
 }
 
-static uint32_t HAL_RCC_ADC_CLK_ENABLED=0;
+static uint32_t HAL_RCC_ADC_CLK_ENABLED = 0;
 
-/**
-* @brief ADC MSP Initialization
-* This function configures the hardware resources used in this example
-* @param hadc: ADC handle pointer
-* @retval None
-*/
-void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
+void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
 {
+
   GPIO_InitTypeDef GPIO_InitStruct = {0};
-  if(hadc->Instance==ADC1)
+  if (adcHandle->Instance == ADC1)
   {
-  /* USER CODE BEGIN ADC1_MspInit 0 */
+    /* USER CODE BEGIN ADC1_MspInit 0 */
 
-  /* USER CODE END ADC1_MspInit 0 */
-    /* Peripheral clock enable */
+    /* USER CODE END ADC1_MspInit 0 */
+    /* ADC1 clock enable */
     HAL_RCC_ADC_CLK_ENABLED++;
-    if(HAL_RCC_ADC_CLK_ENABLED==1){
+    if (HAL_RCC_ADC_CLK_ENABLED == 1)
+    {
       __HAL_RCC_ADC_CLK_ENABLE();
     }
 
@@ -115,12 +111,9 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
     PC2     ------> ADC1_IN3
     PC3     ------> ADC1_IN4
     PA7     ------> ADC1_IN12
-    PC4     ------> ADC1_IN13
-    PB0     ------> ADC1_IN15
     PB1     ------> ADC1_IN16
     */
-    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
-                          |GPIO_PIN_4;
+    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
@@ -130,23 +123,24 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
-    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
+    GPIO_InitStruct.Pin = GPIO_PIN_1;
     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
-  /* USER CODE BEGIN ADC1_MspInit 1 */
+    /* USER CODE BEGIN ADC1_MspInit 1 */
 
-  /* USER CODE END ADC1_MspInit 1 */
+    /* USER CODE END ADC1_MspInit 1 */
   }
-  else if(hadc->Instance==ADC2)
+  else if (adcHandle->Instance == ADC2)
   {
-  /* USER CODE BEGIN ADC2_MspInit 0 */
+    /* USER CODE BEGIN ADC2_MspInit 0 */
 
-  /* USER CODE END ADC2_MspInit 0 */
-    /* Peripheral clock enable */
+    /* USER CODE END ADC2_MspInit 0 */
+    /* ADC2 clock enable */
     HAL_RCC_ADC_CLK_ENABLED++;
-    if(HAL_RCC_ADC_CLK_ENABLED==1){
+    if (HAL_RCC_ADC_CLK_ENABLED == 1)
+    {
       __HAL_RCC_ADC_CLK_ENABLE();
     }
 
@@ -159,29 +153,24 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
-  /* USER CODE BEGIN ADC2_MspInit 1 */
+    /* USER CODE BEGIN ADC2_MspInit 1 */
 
-  /* USER CODE END ADC2_MspInit 1 */
+    /* USER CODE END ADC2_MspInit 1 */
   }
-
 }
 
-/**
-* @brief ADC MSP De-Initialization
-* This function freeze the hardware resources used in this example
-* @param hadc: ADC handle pointer
-* @retval None
-*/
-void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
+void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
 {
-  if(hadc->Instance==ADC1)
+
+  if (adcHandle->Instance == ADC1)
   {
-  /* USER CODE BEGIN ADC1_MspDeInit 0 */
+    /* USER CODE BEGIN ADC1_MspDeInit 0 */
 
-  /* USER CODE END ADC1_MspDeInit 0 */
+    /* USER CODE END ADC1_MspDeInit 0 */
     /* Peripheral clock disable */
     HAL_RCC_ADC_CLK_ENABLED--;
-    if(HAL_RCC_ADC_CLK_ENABLED==0){
+    if (HAL_RCC_ADC_CLK_ENABLED == 0)
+    {
       __HAL_RCC_ADC_CLK_DISABLE();
     }
 
@@ -191,29 +180,27 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
     PC2     ------> ADC1_IN3
     PC3     ------> ADC1_IN4
     PA7     ------> ADC1_IN12
-    PC4     ------> ADC1_IN13
-    PB0     ------> ADC1_IN15
     PB1     ------> ADC1_IN16
     */
-    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
-                          |GPIO_PIN_4);
+    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
 
     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7);
 
-    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0|GPIO_PIN_1);
+    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_1);
 
-  /* USER CODE BEGIN ADC1_MspDeInit 1 */
+    /* USER CODE BEGIN ADC1_MspDeInit 1 */
 
-  /* USER CODE END ADC1_MspDeInit 1 */
+    /* USER CODE END ADC1_MspDeInit 1 */
   }
-  else if(hadc->Instance==ADC2)
+  else if (adcHandle->Instance == ADC2)
   {
-  /* USER CODE BEGIN ADC2_MspDeInit 0 */
+    /* USER CODE BEGIN ADC2_MspDeInit 0 */
 
-  /* USER CODE END ADC2_MspDeInit 0 */
+    /* USER CODE END ADC2_MspDeInit 0 */
     /* Peripheral clock disable */
     HAL_RCC_ADC_CLK_ENABLED--;
-    if(HAL_RCC_ADC_CLK_ENABLED==0){
+    if (HAL_RCC_ADC_CLK_ENABLED == 0)
+    {
       __HAL_RCC_ADC_CLK_DISABLE();
     }
 
@@ -222,11 +209,10 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
     */
     HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
 
-  /* USER CODE BEGIN ADC2_MspDeInit 1 */
+    /* USER CODE BEGIN ADC2_MspDeInit 1 */
 
-  /* USER CODE END ADC2_MspDeInit 1 */
+    /* USER CODE END ADC2_MspDeInit 1 */
   }
-
 }
 
 /**
@@ -1065,6 +1051,75 @@ void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* hsram){
   /* USER CODE END SRAM_MspDeInit 1 */
 }
 
+void HAL_COMP_MspInit(COMP_HandleTypeDef *compHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if (compHandle->Instance == COMP1)
+  {
+    /* USER CODE BEGIN COMP1_MspInit 0 */
+
+    /* USER CODE END COMP1_MspInit 0 */
+
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**COMP1 GPIO Configuration
+    PC4     ------> COMP1_INM
+    PB0     ------> COMP1_OUT
+    PB2     ------> COMP1_INP
+    */
+    // GPIO_InitStruct.Pin = GPIO_PIN_4;
+    // GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    // GPIO_InitStruct.Pull = GPIO_NOPULL;
+    // HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = GPIO_PIN_0;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF12_COMP1;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = GPIO_PIN_2;
+    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+    /* COMP1 interrupt Init */
+    HAL_NVIC_SetPriority(COMP_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(COMP_IRQn);
+    /* USER CODE BEGIN COMP1_MspInit 1 */
+
+    /* USER CODE END COMP1_MspInit 1 */
+  }
+}
+
+void HAL_COMP_MspDeInit(COMP_HandleTypeDef *compHandle)
+{
+
+  if (compHandle->Instance == COMP1)
+  {
+    /* USER CODE BEGIN COMP1_MspDeInit 0 */
+
+    /* USER CODE END COMP1_MspDeInit 0 */
+
+    /**COMP1 GPIO Configuration
+    PC4     ------> COMP1_INM
+    PB0     ------> COMP1_OUT
+    PB2     ------> COMP1_INP
+    */
+    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_4);
+
+    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0 | GPIO_PIN_2);
+
+    /* COMP1 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(COMP_IRQn);
+    /* USER CODE BEGIN COMP1_MspDeInit 1 */
+
+    /* USER CODE END COMP1_MspDeInit 1 */
+  }
+}
+
 /* USER CODE BEGIN 1 */
 
 /* USER CODE END 1 */

+ 40 - 0
Core/Src/stm32l5xx_it.c

@@ -57,6 +57,7 @@
 /* External variables --------------------------------------------------------*/
 extern PCD_HandleTypeDef hpcd_USB_FS;
 extern TIM_HandleTypeDef htim2;
+extern COMP_HandleTypeDef hcomp1;
 
 /* USER CODE BEGIN EV */
 
@@ -188,6 +189,45 @@ void USB_FS_IRQHandler(void)
   /* USER CODE END USB_FS_IRQn 1 */
 }
 
+/**
+ * @brief This function handles COMP1 and COMP2 interrupts through EXTI lines 21 and 22.
+ */
+void COMP_IRQHandler(void)
+{
+  /* USER CODE BEGIN COMP_IRQn 0 */
+
+  /* USER CODE END COMP_IRQn 0 */
+  HAL_COMP_IRQHandler(&hcomp1);
+  /* USER CODE BEGIN COMP_IRQn 1 */
+
+  /* USER CODE END COMP_IRQn 1 */
+}
+
+/**
+ * @brief This function handles EXTI line9 interrupt.
+ */
+void EXTI9_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI9_IRQn 0 */
+
+  /* USER CODE END EXTI9_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
+  /* USER CODE BEGIN EXTI9_IRQn 1 */
+
+  /* USER CODE END EXTI9_IRQn 1 */
+}
+
+void EXTI3_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI3_IRQn 0 */
+
+  /* USER CODE END EXTI3_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
+  /* USER CODE BEGIN EXTI3_IRQn 1 */
+
+  /* USER CODE END EXTI3_IRQn 1 */
+}
+
 /* USER CODE BEGIN 1 */
 
 /* USER CODE END 1 */

+ 3 - 0
Core/Startup/startup_stm32l552zetx.s

@@ -83,6 +83,7 @@ LoopCopyDataInit:
 	bcc	CopyDataInit
 	ldr	r2, =_sbss
 	b	LoopFillZerobss
+	/* b SkipLoopFillZerobss */
 /* Zero fill the bss segment. */
 FillZerobss:
 	movs	r3, #0
@@ -93,6 +94,8 @@ LoopFillZerobss:
 	cmp	r2, r3
 	bcc	FillZerobss
 
+SkipLoopFillZerobss:
+
 /* Call static constructors */
   bl __libc_init_array
 /* Call the application's entry point.*/

+ 758 - 0
Drivers/STM32L5xx_HAL_Driver/Inc/stm32l5xx_hal_comp.h

@@ -0,0 +1,758 @@
+/**
+  ******************************************************************************
+  * @file    stm32l5xx_hal_comp.h
+  * @author  MCD Application Team
+  * @brief   Header file of COMP HAL module.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2019 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef STM32L5xx_HAL_COMP_H
+#define STM32L5xx_HAL_COMP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l5xx_hal_def.h"
+#include "stm32l5xx_ll_exti.h"
+
+/** @addtogroup STM32L5xx_HAL_Driver
+  * @{
+  */
+#if defined (COMP1) || defined (COMP2)
+
+/** @addtogroup COMP
+  * @{
+  */
+
+/* Exported types ------------------------------------------------------------*/
+/** @defgroup COMP_Exported_Types COMP Exported Types
+  * @{
+  */
+
+/**
+  * @brief  COMP Init structure definition
+  */
+typedef struct
+{
+
+  uint32_t WindowMode;         /*!< Set window mode of a pair of comparators instances
+                                    (2 consecutive instances odd and even COMP<x> and COMP<x+1>).
+                                    Note: HAL COMP driver allows to set window mode from any COMP
+                                    instance of the pair of COMP instances composing window mode.
+                                    This parameter can be a value of @ref COMP_WindowMode */
+
+  uint32_t Mode;               /*!< Set comparator operating mode to adjust power and speed.
+                                    Note: For the characteristics of comparator power modes
+                                          (propagation delay and power consumption), refer to device datasheet.
+                                    This parameter can be a value of @ref COMP_PowerMode */
+
+  uint32_t InputPlus;          /*!< Set comparator input plus (non-inverting input).
+                                    This parameter can be a value of @ref COMP_InputPlus */
+
+  uint32_t InputMinus;         /*!< Set comparator input minus (inverting input).
+                                    This parameter can be a value of @ref COMP_InputMinus */
+
+  uint32_t Hysteresis;         /*!< Set comparator hysteresis mode of the input minus.
+                                    This parameter can be a value of @ref COMP_Hysteresis */
+
+  uint32_t OutputPol;          /*!< Set comparator output polarity.
+                                    This parameter can be a value of @ref COMP_OutputPolarity */
+
+  uint32_t BlankingSrce;       /*!< Set comparator blanking source.
+                                    This parameter can be a value of @ref COMP_BlankingSrce */
+
+  uint32_t TriggerMode;        /*!< Set the comparator output triggering External Interrupt Line (EXTI).
+                                    This parameter can be a value of @ref COMP_EXTI_TriggerMode */
+
+} COMP_InitTypeDef;
+
+/**
+  * @brief  HAL COMP state machine: HAL COMP states definition
+  */
+#define COMP_STATE_BITFIELD_LOCK  (0x10U)
+typedef enum
+{
+  HAL_COMP_STATE_RESET             = 0x00U,                                             /*!< COMP not yet initialized                             */
+  HAL_COMP_STATE_RESET_LOCKED      = (HAL_COMP_STATE_RESET | COMP_STATE_BITFIELD_LOCK), /*!< COMP not yet initialized and configuration is locked */
+  HAL_COMP_STATE_READY             = 0x01U,                                             /*!< COMP initialized and ready for use                   */
+  HAL_COMP_STATE_READY_LOCKED      = (HAL_COMP_STATE_READY | COMP_STATE_BITFIELD_LOCK), /*!< COMP initialized but configuration is locked         */
+  HAL_COMP_STATE_BUSY              = 0x02U,                                             /*!< COMP is running                                      */
+  HAL_COMP_STATE_BUSY_LOCKED       = (HAL_COMP_STATE_BUSY | COMP_STATE_BITFIELD_LOCK)   /*!< COMP is running and configuration is locked          */
+} HAL_COMP_StateTypeDef;
+
+/**
+  * @brief  COMP Handle Structure definition
+  */
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+typedef struct __COMP_HandleTypeDef
+#else
+typedef struct
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+{
+  COMP_TypeDef       *Instance;       /*!< Register base address    */
+  COMP_InitTypeDef   Init;            /*!< COMP required parameters */
+  HAL_LockTypeDef    Lock;            /*!< Locking object           */
+  __IO HAL_COMP_StateTypeDef  State;  /*!< COMP communication state */
+  __IO uint32_t      ErrorCode;       /*!< COMP error code */
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+  void (* TriggerCallback)(struct __COMP_HandleTypeDef *hcomp);   /*!< COMP trigger callback */
+  void (* MspInitCallback)(struct __COMP_HandleTypeDef *hcomp);   /*!< COMP Msp Init callback */
+  void (* MspDeInitCallback)(struct __COMP_HandleTypeDef *hcomp); /*!< COMP Msp DeInit callback */
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+} COMP_HandleTypeDef;
+
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+/**
+  * @brief  HAL COMP Callback ID enumeration definition
+  */
+typedef enum
+{
+  HAL_COMP_TRIGGER_CB_ID                = 0x00U,  /*!< COMP trigger callback ID */
+  HAL_COMP_MSPINIT_CB_ID                = 0x01U,  /*!< COMP Msp Init callback ID */
+  HAL_COMP_MSPDEINIT_CB_ID              = 0x02U   /*!< COMP Msp DeInit callback ID */
+} HAL_COMP_CallbackIDTypeDef;
+
+/**
+  * @brief  HAL COMP Callback pointer definition
+  */
+typedef  void (*pCOMP_CallbackTypeDef)(COMP_HandleTypeDef *hcomp); /*!< pointer to a COMP callback function */
+
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+
+/**
+  * @}
+  */
+
+/* Exported constants --------------------------------------------------------*/
+/** @defgroup COMP_Exported_Constants COMP Exported Constants
+  * @{
+  */
+
+/** @defgroup COMP_Error_Code COMP Error Code
+  * @{
+  */
+#define HAL_COMP_ERROR_NONE             (0x00UL)  /*!< No error */
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+#define HAL_COMP_ERROR_INVALID_CALLBACK (0x01UL)  /*!< Invalid Callback error */
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+/**
+  * @}
+  */
+
+
+/** @defgroup COMP_WindowMode COMP Window Mode
+  * @{
+  */
+#define COMP_WINDOWMODE_DISABLE                 (0x00000000UL)            /*!< Window mode disable: Comparators
+                                                                               instances pair COMP1 and COMP2 are
+                                                                               independent */
+#define COMP_WINDOWMODE_COMP1_INPUT_PLUS_COMMON (COMP_CSR_WINMODE)        /*!< Window mode enable: Comparators instances
+                                                                               pair COMP1 and COMP2 have their input
+                                                                               plus connected together.
+                                                                               The common input is COMP1 input plus
+                                                                               (COMP2 input plus is no more accessible).
+                                                                               */
+/**
+  * @}
+  */
+
+
+
+/** @defgroup COMP_PowerMode COMP power mode
+  * @{
+  */
+/* Note: For the characteristics of comparator power modes                    */
+/*       (propagation delay and power consumption),                           */
+/*       refer to device datasheet.                                           */
+#define COMP_POWERMODE_HIGHSPEED       (0x00000000UL)         /*!< High Speed */
+#define COMP_POWERMODE_MEDIUMSPEED     (COMP_CSR_PWRMODE_0)   /*!< Medium Speed */
+#define COMP_POWERMODE_ULTRALOWPOWER   (COMP_CSR_PWRMODE)     /*!< Ultra-low power mode */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_InputPlus COMP input plus (non-inverting input)
+  * @{
+  */
+#define COMP_INPUT_PLUS_IO1            (0x00000000UL)         /*!< Comparator input plus connected to IO1 (pin PC5 for COMP1, pin PB4 for COMP2) */
+#define COMP_INPUT_PLUS_IO2            (COMP_CSR_INPSEL_0)    /*!< Comparator input plus connected to IO2 (pin PB2 for COMP1, pin PB6 for COMP2) */
+#define COMP_INPUT_PLUS_IO3            (COMP_CSR_INPSEL_1)    /*!< Comparator input plus connected to IO3 (pin PA2 for COMP1, not available for COMP2) */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_InputMinus COMP input minus (inverting input)
+  * @{
+  */
+#define COMP_INPUT_MINUS_1_4VREFINT    (                                                            COMP_CSR_SCALEN | COMP_CSR_BRGEN)        /*!< Comparator input minus connected to 1/4 VrefInt */
+#define COMP_INPUT_MINUS_1_2VREFINT    (                                        COMP_CSR_INMSEL_0 | COMP_CSR_SCALEN | COMP_CSR_BRGEN)        /*!< Comparator input minus connected to 1/2 VrefInt */
+#define COMP_INPUT_MINUS_3_4VREFINT    (                    COMP_CSR_INMSEL_1                     | COMP_CSR_SCALEN | COMP_CSR_BRGEN)        /*!< Comparator input minus connected to 3/4 VrefInt */
+#define COMP_INPUT_MINUS_VREFINT       (                    COMP_CSR_INMSEL_1 | COMP_CSR_INMSEL_0 | COMP_CSR_SCALEN                 )        /*!< Comparator input minus connected to VrefInt */
+#define COMP_INPUT_MINUS_DAC1_CH1      (COMP_CSR_INMSEL_2                                        )                                           /*!< Comparator input minus connected to DAC1 channel 1 (DAC_OUT1) */
+#define COMP_INPUT_MINUS_DAC1_CH2      (COMP_CSR_INMSEL_2                     | COMP_CSR_INMSEL_0)                                           /*!< Comparator input minus connected to DAC1 channel 2 (DAC_OUT2) */
+#define COMP_INPUT_MINUS_IO1           (COMP_CSR_INMSEL_2 | COMP_CSR_INMSEL_1                    )                                           /*!< Comparator input minus connected to IO1 (pin PB1 for COMP1, pin PB3 for COMP2) */
+#define COMP_INPUT_MINUS_IO2           (COMP_CSR_INMSEL_2 | COMP_CSR_INMSEL_1 | COMP_CSR_INMSEL_0)                                           /*!< Comparator input minus connected to IO2 (pin PC4 for COMP1, pin PB7 for COMP2) */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_Hysteresis COMP hysteresis
+  * @{
+  */
+#define COMP_HYSTERESIS_NONE           (0x00000000UL)                       /*!< No hysteresis */
+#define COMP_HYSTERESIS_LOW            (                  COMP_CSR_HYST_0)  /*!< Hysteresis level low */
+#define COMP_HYSTERESIS_MEDIUM         (COMP_CSR_HYST_1                  )  /*!< Hysteresis level medium */
+#define COMP_HYSTERESIS_HIGH           (COMP_CSR_HYST_1 | COMP_CSR_HYST_0)  /*!< Hysteresis level high */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_OutputPolarity COMP output Polarity
+  * @{
+  */
+#define COMP_OUTPUTPOL_NONINVERTED     (0x00000000UL)         /*!< COMP output level is not inverted (comparator output is high when the input plus is at a higher voltage than the input minus) */
+#define COMP_OUTPUTPOL_INVERTED        (COMP_CSR_POLARITY)    /*!< COMP output level is inverted     (comparator output is low  when the input plus is at a higher voltage than the input minus) */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_BlankingSrce  COMP blanking source
+  * @{
+  */
+#define COMP_BLANKINGSRC_NONE            (0x00000000UL)          /*!<Comparator output without blanking */
+#define COMP_BLANKINGSRC_TIM1_OC5_COMP1  (COMP_CSR_BLANKING_0)   /*!< Comparator output blanking source TIM1 OC5 (specific to COMP instance: COMP1) */
+#define COMP_BLANKINGSRC_TIM2_OC3_COMP1  (COMP_CSR_BLANKING_1)   /*!< Comparator output blanking source TIM2 OC3 (specific to COMP instance: COMP1) */
+#define COMP_BLANKINGSRC_TIM3_OC3_COMP1  (COMP_CSR_BLANKING_2)   /*!< Comparator output blanking source TIM3 OC3 (specific to COMP instance: COMP1) */
+#define COMP_BLANKINGSRC_TIM3_OC4_COMP2  (COMP_CSR_BLANKING_0)   /*!< Comparator output blanking source TIM3 OC4 (specific to COMP instance: COMP2) */
+#define COMP_BLANKINGSRC_TIM8_OC5_COMP2  (COMP_CSR_BLANKING_1)   /*!< Comparator output blanking source TIM8 OC5 (specific to COMP instance: COMP2) */
+#define COMP_BLANKINGSRC_TIM15_OC1_COMP2 (COMP_CSR_BLANKING_2)   /*!< Comparator output blanking source TIM15 OC1 (specific to COMP instance: COMP2) */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_OutputLevel COMP Output Level
+  * @{
+  */
+/* Note: Comparator output level values are fixed to "0" and "1",             */
+/* corresponding COMP register bit is managed by HAL function to match        */
+/* with these values (independently of bit position in register).             */
+
+/* When output polarity is not inverted, comparator output is low when
+   the input plus is at a lower voltage than the input minus */
+#define COMP_OUTPUT_LEVEL_LOW              (0x00000000UL)
+/* When output polarity is not inverted, comparator output is high when
+   the input plus is at a higher voltage than the input minus */
+#define COMP_OUTPUT_LEVEL_HIGH             (0x00000001UL)
+/**
+  * @}
+  */
+
+/** @defgroup COMP_EXTI_TriggerMode COMP output to EXTI
+  * @{
+  */
+#define COMP_TRIGGERMODE_NONE                 (0x00000000UL)                                            /*!< Comparator output triggering no External Interrupt Line */
+#define COMP_TRIGGERMODE_IT_RISING            (COMP_EXTI_IT | COMP_EXTI_RISING)                         /*!< Comparator output triggering External Interrupt Line event with interruption, on rising edge */
+#define COMP_TRIGGERMODE_IT_FALLING           (COMP_EXTI_IT | COMP_EXTI_FALLING)                        /*!< Comparator output triggering External Interrupt Line event with interruption, on falling edge */
+#define COMP_TRIGGERMODE_IT_RISING_FALLING    (COMP_EXTI_IT | COMP_EXTI_RISING | COMP_EXTI_FALLING)     /*!< Comparator output triggering External Interrupt Line event with interruption, on both rising and falling edges */
+#define COMP_TRIGGERMODE_EVENT_RISING         (COMP_EXTI_EVENT | COMP_EXTI_RISING)                      /*!< Comparator output triggering External Interrupt Line event only (without interruption), on rising edge */
+#define COMP_TRIGGERMODE_EVENT_FALLING        (COMP_EXTI_EVENT | COMP_EXTI_FALLING)                     /*!< Comparator output triggering External Interrupt Line event only (without interruption), on falling edge */
+#define COMP_TRIGGERMODE_EVENT_RISING_FALLING (COMP_EXTI_EVENT | COMP_EXTI_RISING | COMP_EXTI_FALLING)  /*!< Comparator output triggering External Interrupt Line event only (without interruption), on both rising and falling edges */
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/* Exported macro ------------------------------------------------------------*/
+/** @defgroup COMP_Exported_Macros COMP Exported Macros
+  * @{
+  */
+
+/** @defgroup COMP_Handle_Management  COMP Handle Management
+  * @{
+  */
+
+/** @brief  Reset COMP handle state.
+  * @param  __HANDLE__  COMP handle
+  * @retval None
+  */
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+#define __HAL_COMP_RESET_HANDLE_STATE(__HANDLE__) do{                                                  \
+                                                      (__HANDLE__)->State = HAL_COMP_STATE_RESET;      \
+                                                      (__HANDLE__)->MspInitCallback = NULL;            \
+                                                      (__HANDLE__)->MspDeInitCallback = NULL;          \
+                                                    } while(0)
+#else
+#define __HAL_COMP_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_COMP_STATE_RESET)
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+
+/**
+  * @brief Clear COMP error code (set it to no error code "HAL_COMP_ERROR_NONE").
+  * @param __HANDLE__ COMP handle
+  * @retval None
+  */
+#define COMP_CLEAR_ERRORCODE(__HANDLE__) ((__HANDLE__)->ErrorCode = HAL_COMP_ERROR_NONE)
+
+/**
+  * @brief  Enable the specified comparator.
+  * @param  __HANDLE__  COMP handle
+  * @retval None
+  */
+#define __HAL_COMP_ENABLE(__HANDLE__)       SET_BIT((__HANDLE__)->Instance->CSR, COMP_CSR_EN)
+
+/**
+  * @brief  Disable the specified comparator.
+  * @param  __HANDLE__  COMP handle
+  * @retval None
+  */
+#define __HAL_COMP_DISABLE(__HANDLE__)      CLEAR_BIT((__HANDLE__)->Instance->CSR, COMP_CSR_EN)
+
+/**
+  * @brief  Lock the specified comparator configuration.
+  * @note   Using this macro induce HAL COMP handle state machine being no
+  *         more in line with COMP instance state.
+  *         To keep HAL COMP handle state machine updated, it is recommended
+  *         to use function "HAL_COMP_Lock')".
+  * @param  __HANDLE__  COMP handle
+  * @retval None
+  */
+#define __HAL_COMP_LOCK(__HANDLE__)         SET_BIT((__HANDLE__)->Instance->CSR, COMP_CSR_LOCK)
+
+/**
+  * @brief  Check whether the specified comparator is locked.
+  * @param  __HANDLE__  COMP handle
+  * @retval Value 0 if COMP instance is not locked, value 1 if COMP instance is locked
+  */
+#define __HAL_COMP_IS_LOCKED(__HANDLE__)    (READ_BIT((__HANDLE__)->Instance->CSR, COMP_CSR_LOCK) == COMP_CSR_LOCK)
+
+/**
+  * @}
+  */
+
+/** @defgroup COMP_Exti_Management  COMP external interrupt line management
+  * @{
+  */
+/**
+  * @brief  Enable the COMP1 EXTI line rising edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_ENABLE_RISING_EDGE()    LL_EXTI_EnableRisingTrig_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Disable the COMP1 EXTI line rising edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_DISABLE_RISING_EDGE()   LL_EXTI_DisableRisingTrig_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Enable the COMP1 EXTI line falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_ENABLE_FALLING_EDGE()   LL_EXTI_EnableFallingTrig_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Disable the COMP1 EXTI line falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_DISABLE_FALLING_EDGE()  LL_EXTI_DisableFallingTrig_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Enable the COMP1 EXTI line rising & falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_ENABLE_RISING_FALLING_EDGE() do {                                                        \
+                                                                LL_EXTI_EnableRisingTrig_0_31(COMP_EXTI_LINE_COMP1);   \
+                                                                LL_EXTI_EnableFallingTrig_0_31(COMP_EXTI_LINE_COMP1);  \
+                                                              } while(0)
+
+/**
+  * @brief  Disable the COMP1 EXTI line rising & falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_DISABLE_RISING_FALLING_EDGE() do {                                                       \
+                                                                 LL_EXTI_DisableRisingTrig_0_31(COMP_EXTI_LINE_COMP1); \
+                                                                 LL_EXTI_DisableFallingTrig_0_31(COMP_EXTI_LINE_COMP1);\
+                                                               } while(0)
+
+/**
+  * @brief  Enable the COMP1 EXTI line in interrupt mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_ENABLE_IT()             LL_EXTI_EnableIT_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Disable the COMP1 EXTI line in interrupt mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_DISABLE_IT()            LL_EXTI_DisableIT_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Generate a software interrupt on the COMP1 EXTI line.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_GENERATE_SWIT()         LL_EXTI_GenerateSWI_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Enable the COMP1 EXTI line in event mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_ENABLE_EVENT()          LL_EXTI_EnableEvent_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Disable the COMP1 EXTI line in event mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_DISABLE_EVENT()         LL_EXTI_DisableEvent_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Check whether the COMP1 EXTI line rising flag is set.
+  * @retval RESET or SET
+  */
+#define __HAL_COMP_COMP1_EXTI_GET_RISING_FLAG()       LL_EXTI_IsActiveRisingFlag_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Clear the COMP1 EXTI rising flag.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_CLEAR_RISING_FLAG()     LL_EXTI_ClearRisingFlag_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Check whether the COMP1 EXTI line falling flag is set.
+  * @retval RESET or SET
+  */
+#define __HAL_COMP_COMP1_EXTI_GET_FALLING_FLAG()      LL_EXTI_IsActiveFallingFlag_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Clear the COMP1 EXTI falling flag.
+  * @retval None
+  */
+#define __HAL_COMP_COMP1_EXTI_CLEAR_FALLING_FLAG()    LL_EXTI_ClearFallingFlag_0_31(COMP_EXTI_LINE_COMP1)
+
+/**
+  * @brief  Enable the COMP2 EXTI line rising edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_ENABLE_RISING_EDGE()    LL_EXTI_EnableRisingTrig_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Disable the COMP2 EXTI line rising edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_DISABLE_RISING_EDGE()   LL_EXTI_DisableRisingTrig_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Enable the COMP2 EXTI line falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_ENABLE_FALLING_EDGE()   LL_EXTI_EnableFallingTrig_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Disable the COMP2 EXTI line falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_DISABLE_FALLING_EDGE()  LL_EXTI_DisableFallingTrig_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Enable the COMP2 EXTI line rising & falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_ENABLE_RISING_FALLING_EDGE() do {                                                        \
+                                                                LL_EXTI_EnableRisingTrig_0_31(COMP_EXTI_LINE_COMP2);   \
+                                                                LL_EXTI_EnableFallingTrig_0_31(COMP_EXTI_LINE_COMP2);  \
+                                                              } while(0)
+
+/**
+  * @brief  Disable the COMP2 EXTI line rising & falling edge trigger.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_DISABLE_RISING_FALLING_EDGE() do {                                                       \
+                                                                 LL_EXTI_DisableRisingTrig_0_31(COMP_EXTI_LINE_COMP2); \
+                                                                 LL_EXTI_DisableFallingTrig_0_31(COMP_EXTI_LINE_COMP2);\
+                                                               } while(0)
+
+/**
+  * @brief  Enable the COMP2 EXTI line in interrupt mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_ENABLE_IT()             LL_EXTI_EnableIT_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Disable the COMP2 EXTI line in interrupt mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_DISABLE_IT()            LL_EXTI_DisableIT_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Generate a software interrupt on the COMP2 EXTI line.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_GENERATE_SWIT()         LL_EXTI_GenerateSWI_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Enable the COMP2 EXTI line in event mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_ENABLE_EVENT()          LL_EXTI_EnableEvent_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Disable the COMP2 EXTI line in event mode.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_DISABLE_EVENT()         LL_EXTI_DisableEvent_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Check whether the COMP2 EXTI line rising flag is set.
+  * @retval RESET or SET
+  */
+#define __HAL_COMP_COMP2_EXTI_GET_RISING_FLAG()       LL_EXTI_IsActiveRisingFlag_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Clear the COMP2 EXTI rising flag.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_CLEAR_RISING_FLAG()     LL_EXTI_ClearRisingFlag_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Check whether the COMP2 EXTI line falling flag is set.
+  * @retval RESET or SET
+  */
+#define __HAL_COMP_COMP2_EXTI_GET_FALLING_FLAG()      LL_EXTI_IsActiveFallingFlag_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @brief  Clear the COMP2 EXTI falling flag.
+  * @retval None
+  */
+#define __HAL_COMP_COMP2_EXTI_CLEAR_FALLING_FLAG()    LL_EXTI_ClearFallingFlag_0_31(COMP_EXTI_LINE_COMP2)
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+
+/* Private types -------------------------------------------------------------*/
+/* Private constants ---------------------------------------------------------*/
+/** @defgroup COMP_Private_Constants COMP Private Constants
+  * @{
+  */
+
+/** @defgroup COMP_ExtiLine COMP EXTI Lines
+  * @{
+  */
+#define COMP_EXTI_LINE_COMP1           (LL_EXTI_LINE_21)  /*!< EXTI line 21 connected to COMP1 output */
+#define COMP_EXTI_LINE_COMP2           (LL_EXTI_LINE_22)  /*!< EXTI line 22 connected to COMP2 output */
+/**
+  * @}
+  */
+
+/** @defgroup COMP_ExtiLine COMP EXTI Lines
+  * @{
+  */
+#define COMP_EXTI_IT                        (0x00000001UL)  /*!< EXTI line event with interruption */
+#define COMP_EXTI_EVENT                     (0x00000002UL)  /*!< EXTI line event only (without interruption) */
+#define COMP_EXTI_RISING                    (0x00000010UL)  /*!< EXTI line event on rising edge */
+#define COMP_EXTI_FALLING                   (0x00000020UL)  /*!< EXTI line event on falling edge */
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/* Private macros ------------------------------------------------------------*/
+/** @defgroup COMP_Private_Macros COMP Private Macros
+  * @{
+  */
+
+/** @defgroup COMP_GET_EXTI_LINE COMP private macros to get EXTI line associated with comparators
+  * @{
+  */
+/**
+  * @brief  Get the specified EXTI line for a comparator instance.
+  * @param  __INSTANCE__  specifies the COMP instance.
+  * @retval value of @ref COMP_ExtiLine
+  */
+#define COMP_GET_EXTI_LINE(__INSTANCE__)    (((__INSTANCE__) == COMP1) ? COMP_EXTI_LINE_COMP1  \
+                                             : COMP_EXTI_LINE_COMP2)
+/**
+  * @}
+  */
+
+/** @defgroup COMP_IS_COMP_Private_Definitions COMP private macros to check input parameters
+  * @{
+  */
+#define IS_COMP_WINDOWMODE(__WINDOWMODE__)  (((__WINDOWMODE__) == COMP_WINDOWMODE_DISABLE)                || \
+                                             ((__WINDOWMODE__) == COMP_WINDOWMODE_COMP1_INPUT_PLUS_COMMON)  )
+
+#define IS_COMP_POWERMODE(__POWERMODE__)    (((__POWERMODE__) == COMP_POWERMODE_HIGHSPEED)    || \
+                                             ((__POWERMODE__) == COMP_POWERMODE_MEDIUMSPEED)  || \
+                                             ((__POWERMODE__) == COMP_POWERMODE_ULTRALOWPOWER)  )
+
+#define IS_COMP_INPUT_PLUS(__COMP_INSTANCE__, __INPUT_PLUS__) ((__COMP_INSTANCE__ == COMP1)                     \
+                                                               ? (((__INPUT_PLUS__) == COMP_INPUT_PLUS_IO1) ||  \
+                                                                  ((__INPUT_PLUS__) == COMP_INPUT_PLUS_IO2) ||  \
+                                                                  ((__INPUT_PLUS__) == COMP_INPUT_PLUS_IO3)   ) \
+                                                               :                                                \
+                                                               (((__INPUT_PLUS__) == COMP_INPUT_PLUS_IO1) ||    \
+                                                                ((__INPUT_PLUS__) == COMP_INPUT_PLUS_IO2)   )   \
+                                                              )
+
+/* Note: On this STM32 series, comparator input minus parameters are          */
+/*       the same on all COMP instances.                                      */
+/*       However, comparator instance kept as macro parameter for             */
+/*       compatibility with other STM32 series.                               */
+#define IS_COMP_INPUT_MINUS(__COMP_INSTANCE__, __INPUT_MINUS__) (((__INPUT_MINUS__) == COMP_INPUT_MINUS_1_4VREFINT)  || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_1_2VREFINT)  || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_3_4VREFINT)  || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_VREFINT)     || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_DAC1_CH1)    || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_DAC1_CH2)    || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_IO1)         || \
+                                                                 ((__INPUT_MINUS__) == COMP_INPUT_MINUS_IO2))
+
+#define IS_COMP_HYSTERESIS(__HYSTERESIS__)  (((__HYSTERESIS__) == COMP_HYSTERESIS_NONE)   || \
+                                             ((__HYSTERESIS__) == COMP_HYSTERESIS_LOW)    || \
+                                             ((__HYSTERESIS__) == COMP_HYSTERESIS_MEDIUM) || \
+                                             ((__HYSTERESIS__) == COMP_HYSTERESIS_HIGH))
+
+#define IS_COMP_OUTPUTPOL(__POL__)          (((__POL__) == COMP_OUTPUTPOL_NONINVERTED) || \
+                                             ((__POL__) == COMP_OUTPUTPOL_INVERTED))
+
+#define IS_COMP_BLANKINGSRCE(__OUTPUT_BLANKING_SOURCE__)                    \
+  (((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_NONE)                  \
+   || ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM1_OC5_COMP1)     \
+   || ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM2_OC3_COMP1)     \
+   || ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM3_OC3_COMP1)     \
+   || ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM3_OC4_COMP2)     \
+   || ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM8_OC5_COMP2)     \
+   || ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM15_OC1_COMP2)    \
+  )
+
+#define IS_COMP_BLANKINGSRC_INSTANCE(__INSTANCE__, __OUTPUT_BLANKING_SOURCE__)  \
+  ((((__INSTANCE__) == COMP1) &&                                                \
+    (((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_NONE)            ||      \
+     ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM1_OC5_COMP1)  ||      \
+     ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM2_OC3_COMP1)  ||      \
+     ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM3_OC3_COMP1)))        \
+   ||                                                                           \
+   (((__INSTANCE__) == COMP2) &&                                                \
+    (((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_NONE)           ||       \
+     ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM3_OC4_COMP2) ||       \
+     ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM8_OC5_COMP2) ||       \
+     ((__OUTPUT_BLANKING_SOURCE__) == COMP_BLANKINGSRC_TIM15_OC1_COMP2))))
+
+
+#define IS_COMP_TRIGGERMODE(__MODE__)       (((__MODE__) == COMP_TRIGGERMODE_NONE)                 || \
+                                             ((__MODE__) == COMP_TRIGGERMODE_IT_RISING)            || \
+                                             ((__MODE__) == COMP_TRIGGERMODE_IT_FALLING)           || \
+                                             ((__MODE__) == COMP_TRIGGERMODE_IT_RISING_FALLING)    || \
+                                             ((__MODE__) == COMP_TRIGGERMODE_EVENT_RISING)         || \
+                                             ((__MODE__) == COMP_TRIGGERMODE_EVENT_FALLING)        || \
+                                             ((__MODE__) == COMP_TRIGGERMODE_EVENT_RISING_FALLING))
+
+#define IS_COMP_OUTPUT_LEVEL(__OUTPUT_LEVEL__) (((__OUTPUT_LEVEL__) == COMP_OUTPUT_LEVEL_LOW)     || \
+                                                ((__OUTPUT_LEVEL__) == COMP_OUTPUT_LEVEL_HIGH))
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+
+/* Exported functions --------------------------------------------------------*/
+/** @addtogroup COMP_Exported_Functions
+  * @{
+  */
+
+/** @addtogroup COMP_Exported_Functions_Group1
+  * @{
+  */
+
+/* Initialization and de-initialization functions  **********************************/
+HAL_StatusTypeDef HAL_COMP_Init(COMP_HandleTypeDef *hcomp);
+HAL_StatusTypeDef HAL_COMP_DeInit(COMP_HandleTypeDef *hcomp);
+void              HAL_COMP_MspInit(COMP_HandleTypeDef *hcomp);
+void              HAL_COMP_MspDeInit(COMP_HandleTypeDef *hcomp);
+
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+/* Callbacks Register/UnRegister functions  ***********************************/
+HAL_StatusTypeDef HAL_COMP_RegisterCallback(COMP_HandleTypeDef *hcomp, HAL_COMP_CallbackIDTypeDef CallbackID,
+                                            pCOMP_CallbackTypeDef pCallback);
+HAL_StatusTypeDef HAL_COMP_UnRegisterCallback(COMP_HandleTypeDef *hcomp, HAL_COMP_CallbackIDTypeDef CallbackID);
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+/**
+  * @}
+  */
+
+/* IO operation functions  *****************************************************/
+/** @addtogroup COMP_Exported_Functions_Group2
+  * @{
+  */
+HAL_StatusTypeDef HAL_COMP_Start(COMP_HandleTypeDef *hcomp);
+HAL_StatusTypeDef HAL_COMP_Stop(COMP_HandleTypeDef *hcomp);
+void              HAL_COMP_IRQHandler(COMP_HandleTypeDef *hcomp);
+/**
+  * @}
+  */
+
+/* Peripheral Control functions  ************************************************/
+/** @addtogroup COMP_Exported_Functions_Group3
+  * @{
+  */
+HAL_StatusTypeDef HAL_COMP_Lock(COMP_HandleTypeDef *hcomp);
+uint32_t          HAL_COMP_GetOutputLevel(const COMP_HandleTypeDef *hcomp);
+/* Callback in interrupt mode */
+void              HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp);
+/**
+  * @}
+  */
+
+/* Peripheral State functions  **************************************************/
+/** @addtogroup COMP_Exported_Functions_Group4
+  * @{
+  */
+HAL_COMP_StateTypeDef HAL_COMP_GetState(const COMP_HandleTypeDef *hcomp);
+uint32_t              HAL_COMP_GetError(const COMP_HandleTypeDef *hcomp);
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+#endif /* COMP1 || COMP2 */
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32L5xx_HAL_COMP_H */

+ 1019 - 0
Drivers/STM32L5xx_HAL_Driver/Src/stm32l5xx_hal_comp.c

@@ -0,0 +1,1019 @@
+/**
+  ******************************************************************************
+  * @file    stm32l5xx_hal_comp.c
+  * @author  MCD Application Team
+  * @brief   COMP HAL module driver.
+  *          This file provides firmware functions to manage the following
+  *          functionalities of the COMP peripheral:
+  *           + Initialization and de-initialization functions
+  *           + Peripheral control functions
+  *           + Peripheral state functions
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2019 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  @verbatim
+  ==============================================================================
+          ##### COMP Peripheral features #####
+  ==============================================================================
+
+  [..]
+      The STM32L5xx device family integrates two analog comparators instances:
+      COMP1, COMP2.
+      (#) Comparators input minus (inverting input) and input plus (non inverting input)
+          can be set to internal references or to GPIO pins
+          (refer to GPIO list in reference manual).
+
+      (#) Comparators output level is available using HAL_COMP_GetOutputLevel()
+          and can be redirected to other peripherals: GPIO pins (in mode
+          alternate functions for comparator), timers.
+          (refer to GPIO list in reference manual).
+
+      (#) The comparators have interrupt capability through the EXTI controller
+          with wake-up from sleep and stop modes.
+
+      (#) Pairs of comparators instances can be combined in window mode
+          (2 consecutive instances odd and even COMP<x> and COMP<x+1>).
+
+          From the corresponding IRQ handler, the right interrupt source can be retrieved
+          using macro __HAL_COMP_COMPx_EXTI_GET_FLAG().
+
+            ##### How to use this driver #####
+  ==============================================================================
+  [..]
+      This driver provides functions to configure and program the comparator instances
+      of STM32L5xx devices.
+
+      To use the comparator, perform the following steps:
+
+      (#)  Initialize the COMP low level resources by implementing the HAL_COMP_MspInit():
+      (++) Configure the GPIO connected to comparator inputs plus and minus in analog mode
+           using HAL_GPIO_Init().
+      (++) If needed, configure the GPIO connected to comparator output in alternate function mode
+           using HAL_GPIO_Init().
+      (++) If required enable the COMP interrupt by configuring and enabling EXTI line in Interrupt mode and
+           selecting the desired sensitivity level using HAL_GPIO_Init() function. After that enable the comparator
+           interrupt vector using HAL_NVIC_EnableIRQ() function.
+
+      (#) Configure the comparator using HAL_COMP_Init() function:
+      (++) Select the input minus (inverting input)
+      (++) Select the input plus (non-inverting input)
+      (++) Select the hysteresis
+      (++) Select the blanking source
+      (++) Select the output polarity
+      (++) Select the power mode
+      (++) Select the window mode
+
+      -@@- HAL_COMP_Init() calls internally __HAL_RCC_SYSCFG_CLK_ENABLE()
+          to enable internal control clock of the comparators.
+          However, this is a legacy strategy. In future STM32 families,
+          COMP clock enable must be implemented by user in "HAL_COMP_MspInit()".
+          Therefore, for compatibility anticipation, it is recommended to
+          implement __HAL_RCC_SYSCFG_CLK_ENABLE() in "HAL_COMP_MspInit()".
+
+      (#) Reconfiguration on-the-fly of comparator can be done by calling again
+          function HAL_COMP_Init() with new input structure parameters values.
+
+      (#) Enable the comparator using HAL_COMP_Start() function.
+
+      (#) Use HAL_COMP_TriggerCallback() or HAL_COMP_GetOutputLevel() functions
+          to manage comparator outputs (events and output level).
+
+      (#) Disable the comparator using HAL_COMP_Stop() function.
+
+      (#) De-initialize the comparator using HAL_COMP_DeInit() function.
+
+      (#) For safety purpose, comparator configuration can be locked using HAL_COMP_Lock() function.
+          The only way to unlock the comparator is a device hardware reset.
+
+    *** Callback registration ***
+    =============================================
+    [..]
+
+     The compilation flag USE_HAL_COMP_REGISTER_CALLBACKS, when set to 1,
+     allows the user to configure dynamically the driver callbacks.
+     Use Functions HAL_COMP_RegisterCallback()
+     to register an interrupt callback.
+    [..]
+
+     Function HAL_COMP_RegisterCallback() allows to register following callbacks:
+       (+) TriggerCallback       : callback for COMP trigger.
+       (+) MspInitCallback       : callback for Msp Init.
+       (+) MspDeInitCallback     : callback for Msp DeInit.
+     This function takes as parameters the HAL peripheral handle, the Callback ID
+     and a pointer to the user callback function.
+    [..]
+
+     Use function HAL_COMP_UnRegisterCallback to reset a callback to the default
+     weak function.
+    [..]
+
+     HAL_COMP_UnRegisterCallback takes as parameters the HAL peripheral handle,
+     and the Callback ID.
+     This function allows to reset following callbacks:
+       (+) TriggerCallback       : callback for COMP trigger.
+       (+) MspInitCallback       : callback for Msp Init.
+       (+) MspDeInitCallback     : callback for Msp DeInit.
+     [..]
+
+     By default, after the HAL_COMP_Init() and when the state is HAL_COMP_STATE_RESET
+     all callbacks are set to the corresponding weak functions:
+     example HAL_COMP_TriggerCallback().
+     Exception done for MspInit and MspDeInit functions that are
+     reset to the legacy weak functions in the HAL_COMP_Init()/ HAL_COMP_DeInit() only when
+     these callbacks are null (not registered beforehand).
+    [..]
+
+     If MspInit or MspDeInit are not null, the HAL_COMP_Init()/ HAL_COMP_DeInit()
+     keep and use the user MspInit/MspDeInit callbacks (registered beforehand) whatever the state.
+     [..]
+
+     Callbacks can be registered/unregistered in HAL_COMP_STATE_READY state only.
+     Exception done MspInit/MspDeInit functions that can be registered/unregistered
+     in HAL_COMP_STATE_READY or HAL_COMP_STATE_RESET state,
+     thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
+    [..]
+
+     Then, the user first registers the MspInit/MspDeInit user callbacks
+     using HAL_COMP_RegisterCallback() before calling HAL_COMP_DeInit()
+     or HAL_COMP_Init() function.
+     [..]
+
+     When the compilation flag USE_HAL_COMP_REGISTER_CALLBACKS is set to 0 or
+     not defined, the callback registration feature is not available and all callbacks
+     are set to the corresponding weak functions.
+
+  @endverbatim
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32l5xx_hal.h"
+
+/** @addtogroup STM32L5xx_HAL_Driver
+  * @{
+  */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+
+#if defined (COMP1) || defined (COMP2)
+
+/** @defgroup COMP COMP
+  * @brief COMP HAL module driver
+  * @{
+  */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/** @addtogroup COMP_Private_Constants
+  * @{
+  */
+
+/* Delay for COMP startup time.                                               */
+/* Note: Delay required to reach propagation delay specification.             */
+/* Literal set to maximum value (refer to device datasheet,                   */
+/* parameter "tSTART").                                                       */
+/* Unit: us                                                                   */
+#define COMP_DELAY_STARTUP_US          (80UL)      /*!< Delay for COMP startup time */
+
+/* Delay for COMP voltage scaler stabilization time.                          */
+/* Literal set to maximum value (refer to device datasheet,                   */
+/* parameter "tSTART_SCALER").                                                */
+/* Unit: us                                                                   */
+#define COMP_DELAY_VOLTAGE_SCALER_STAB_US (200UL)  /*!< Delay for COMP voltage scaler stabilization time */
+
+#define COMP_OUTPUT_LEVEL_BITOFFSET_POS    (30UL)
+
+/**
+  * @}
+  */
+
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+/* Exported functions --------------------------------------------------------*/
+
+/** @defgroup COMP_Exported_Functions COMP Exported Functions
+  * @{
+  */
+
+/** @defgroup COMP_Exported_Functions_Group1 Initialization/de-initialization functions
+  *  @brief    Initialization and de-initialization functions.
+  *
+@verbatim
+ ===============================================================================
+              ##### Initialization and de-initialization functions #####
+ ===============================================================================
+    [..]  This section provides functions to initialize and de-initialize comparators
+
+@endverbatim
+  * @{
+  */
+
+/**
+  * @brief  Initialize the COMP according to the specified
+  *         parameters in the COMP_InitTypeDef and initialize the associated handle.
+  * @note   If the selected comparator is locked, initialization can't be performed.
+  *         To unlock the configuration, perform a system reset.
+  * @param  hcomp  COMP handle
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_Init(COMP_HandleTypeDef *hcomp)
+{
+  uint32_t tmp_csr;
+  uint32_t exti_line;
+  uint32_t comp_voltage_scaler_initialized; /* Value "0" if comparator voltage scaler is not initialized */
+  __IO uint32_t wait_loop_index = 0UL;
+  HAL_StatusTypeDef status = HAL_OK;
+
+  /* Check the COMP handle allocation and lock status */
+  if (hcomp == NULL)
+  {
+    status = HAL_ERROR;
+  }
+  else if (__HAL_COMP_IS_LOCKED(hcomp))
+  {
+    status = HAL_ERROR;
+  }
+  else
+  {
+    /* Check the parameters */
+    assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+    assert_param(IS_COMP_INPUT_PLUS(hcomp->Instance, hcomp->Init.InputPlus));
+    assert_param(IS_COMP_INPUT_MINUS(hcomp->Instance, hcomp->Init.InputMinus));
+    assert_param(IS_COMP_OUTPUTPOL(hcomp->Init.OutputPol));
+    assert_param(IS_COMP_POWERMODE(hcomp->Init.Mode));
+    assert_param(IS_COMP_HYSTERESIS(hcomp->Init.Hysteresis));
+    assert_param(IS_COMP_BLANKINGSRC_INSTANCE(hcomp->Instance, hcomp->Init.BlankingSrce));
+    assert_param(IS_COMP_TRIGGERMODE(hcomp->Init.TriggerMode));
+
+    assert_param(IS_COMP_WINDOWMODE(hcomp->Init.WindowMode));
+
+
+    if (hcomp->State == HAL_COMP_STATE_RESET)
+    {
+      /* Allocate lock resource and initialize it */
+      hcomp->Lock = HAL_UNLOCKED;
+
+      /* Set COMP error code to none */
+      COMP_CLEAR_ERRORCODE(hcomp);
+
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+      /* Init the COMP Callback settings */
+      hcomp->TriggerCallback = HAL_COMP_TriggerCallback; /* Legacy weak callback */
+
+      if (hcomp->MspInitCallback == NULL)
+      {
+        hcomp->MspInitCallback = HAL_COMP_MspInit; /* Legacy weak MspInit  */
+      }
+
+      /* Init the low level hardware */
+      /* Note: Internal control clock of the comparators must                 */
+      /*       be enabled in "HAL_COMP_MspInit()"                             */
+      /*       using "__HAL_RCC_SYSCFG_CLK_ENABLE()".                         */
+      hcomp->MspInitCallback(hcomp);
+#else
+      /* Init the low level hardware */
+      /* Note: Internal control clock of the comparators must                 */
+      /*       be enabled in "HAL_COMP_MspInit()"                             */
+      /*       using "__HAL_RCC_SYSCFG_CLK_ENABLE()".                         */
+      HAL_COMP_MspInit(hcomp);
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+    }
+
+    /* Memorize voltage scaler state before initialization */
+    comp_voltage_scaler_initialized = READ_BIT(hcomp->Instance->CSR, COMP_CSR_SCALEN);
+
+    /* Set COMP parameters */
+    tmp_csr = (hcomp->Init.InputMinus
+               | hcomp->Init.InputPlus
+               | hcomp->Init.BlankingSrce
+               | hcomp->Init.Hysteresis
+               | hcomp->Init.OutputPol
+               | hcomp->Init.Mode
+              );
+
+    /* Set parameters in COMP register */
+    /* Note: Update all bits except read-only, lock and enable bits */
+    MODIFY_REG(hcomp->Instance->CSR,
+               COMP_CSR_PWRMODE  | COMP_CSR_INMSEL   | COMP_CSR_INPSEL  |
+               COMP_CSR_WINMODE  | COMP_CSR_POLARITY | COMP_CSR_HYST    |
+               COMP_CSR_BLANKING | COMP_CSR_BRGEN    | COMP_CSR_SCALEN,
+               tmp_csr
+              );
+
+
+    /* Set window mode */
+    /* Note: Window mode bit is located into 1 out of the 2 pairs of COMP     */
+    /*       instances. Therefore, this function can update another COMP      */
+    /*       instance that the one currently selected.                        */
+    if (hcomp->Init.WindowMode == COMP_WINDOWMODE_COMP1_INPUT_PLUS_COMMON)
+    {
+      SET_BIT(COMP12_COMMON->CSR, COMP_CSR_WINMODE);
+    }
+    else
+    {
+      CLEAR_BIT(COMP12_COMMON->CSR, COMP_CSR_WINMODE);
+    }
+
+
+    /* Delay for COMP scaler bridge voltage stabilization */
+    /* Apply the delay if voltage scaler bridge is required and not already enabled */
+    if ((READ_BIT(hcomp->Instance->CSR, COMP_CSR_SCALEN) != 0UL) &&
+        (comp_voltage_scaler_initialized == 0UL))
+    {
+      /* Wait loop initialization and execution */
+      /* Note: Variable divided by 2 to compensate partially              */
+      /*       CPU processing cycles, scaling in us split to not          */
+      /*       exceed 32 bits register capacity and handle low frequency. */
+      wait_loop_index = ((COMP_DELAY_VOLTAGE_SCALER_STAB_US / 10UL) * ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
+      while (wait_loop_index != 0UL)
+      {
+        wait_loop_index--;
+      }
+    }
+
+    /* Get the EXTI line corresponding to the selected COMP instance */
+    exti_line = COMP_GET_EXTI_LINE(hcomp->Instance);
+
+    /* Manage EXTI settings */
+    if ((hcomp->Init.TriggerMode & (COMP_EXTI_IT | COMP_EXTI_EVENT)) != 0UL)
+    {
+      /* Configure EXTI rising edge */
+      if ((hcomp->Init.TriggerMode & COMP_EXTI_RISING) != 0UL)
+      {
+        LL_EXTI_EnableRisingTrig_0_31(exti_line);
+      }
+      else
+      {
+        LL_EXTI_DisableRisingTrig_0_31(exti_line);
+      }
+
+      /* Configure EXTI falling edge */
+      if ((hcomp->Init.TriggerMode & COMP_EXTI_FALLING) != 0UL)
+      {
+        LL_EXTI_EnableFallingTrig_0_31(exti_line);
+      }
+      else
+      {
+        LL_EXTI_DisableFallingTrig_0_31(exti_line);
+      }
+
+      /* Clear COMP EXTI pending bit (if any) */
+      LL_EXTI_ClearRisingFlag_0_31(exti_line);
+      LL_EXTI_ClearFallingFlag_0_31(exti_line);
+
+      /* Configure EXTI event mode */
+      if ((hcomp->Init.TriggerMode & COMP_EXTI_EVENT) != 0UL)
+      {
+        LL_EXTI_EnableEvent_0_31(exti_line);
+      }
+      else
+      {
+        LL_EXTI_DisableEvent_0_31(exti_line);
+      }
+
+      /* Configure EXTI interrupt mode */
+      if ((hcomp->Init.TriggerMode & COMP_EXTI_IT) != 0UL)
+      {
+        LL_EXTI_EnableIT_0_31(exti_line);
+      }
+      else
+      {
+        LL_EXTI_DisableIT_0_31(exti_line);
+      }
+    }
+    else
+    {
+      /* Disable EXTI event mode */
+      LL_EXTI_DisableEvent_0_31(exti_line);
+
+      /* Disable EXTI interrupt mode */
+      LL_EXTI_DisableIT_0_31(exti_line);
+    }
+
+    /* Set HAL COMP handle state */
+    /* Note: Transition from state reset to state ready,                      */
+    /*       otherwise (coming from state ready or busy) no state update.     */
+    if (hcomp->State == HAL_COMP_STATE_RESET)
+    {
+      hcomp->State = HAL_COMP_STATE_READY;
+    }
+  }
+
+  return status;
+}
+
+/**
+  * @brief  DeInitialize the COMP peripheral.
+  * @note   Deinitialization cannot be performed if the COMP configuration is locked.
+  *         To unlock the configuration, perform a system reset.
+  * @param  hcomp  COMP handle
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_DeInit(COMP_HandleTypeDef *hcomp)
+{
+  HAL_StatusTypeDef status = HAL_OK;
+
+  /* Check the COMP handle allocation and lock status */
+  if (hcomp == NULL)
+  {
+    status = HAL_ERROR;
+  }
+  else if (__HAL_COMP_IS_LOCKED(hcomp))
+  {
+    status = HAL_ERROR;
+  }
+  else
+  {
+    /* Check the parameter */
+    assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+    /* Set COMP_CSR register to reset value */
+    WRITE_REG(hcomp->Instance->CSR, 0x00000000UL);
+
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+    if (hcomp->MspDeInitCallback == NULL)
+    {
+      hcomp->MspDeInitCallback = HAL_COMP_MspDeInit; /* Legacy weak MspDeInit  */
+    }
+
+    /* DeInit the low level hardware: GPIO, RCC clock, NVIC */
+    hcomp->MspDeInitCallback(hcomp);
+#else
+    /* DeInit the low level hardware: GPIO, RCC clock, NVIC */
+    HAL_COMP_MspDeInit(hcomp);
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+
+    /* Set HAL COMP handle state */
+    hcomp->State = HAL_COMP_STATE_RESET;
+
+    /* Release Lock */
+    __HAL_UNLOCK(hcomp);
+  }
+
+  return status;
+}
+
+/**
+  * @brief  Initialize the COMP MSP.
+  * @param  hcomp  COMP handle
+  * @retval None
+  */
+__weak void HAL_COMP_MspInit(COMP_HandleTypeDef *hcomp)
+{
+  /* Prevent unused argument(s) compilation warning */
+  UNUSED(hcomp);
+
+  /* NOTE : This function should not be modified, when the callback is needed,
+            the HAL_COMP_MspInit could be implemented in the user file
+   */
+}
+
+/**
+  * @brief  DeInitialize the COMP MSP.
+  * @param  hcomp  COMP handle
+  * @retval None
+  */
+__weak void HAL_COMP_MspDeInit(COMP_HandleTypeDef *hcomp)
+{
+  /* Prevent unused argument(s) compilation warning */
+  UNUSED(hcomp);
+
+  /* NOTE : This function should not be modified, when the callback is needed,
+            the HAL_COMP_MspDeInit could be implemented in the user file
+   */
+}
+
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+/**
+  * @brief  Register a User COMP Callback
+  *         To be used instead of the weak predefined callback
+  * @param  hcomp Pointer to a COMP_HandleTypeDef structure that contains
+  *                the configuration information for the specified COMP.
+  * @param  CallbackID ID of the callback to be registered
+  *         This parameter can be one of the following values:
+  *          @arg @ref HAL_COMP_TRIGGER_CB_ID Trigger callback ID
+  *          @arg @ref HAL_COMP_MSPINIT_CB_ID MspInit callback ID
+  *          @arg @ref HAL_COMP_MSPDEINIT_CB_ID MspDeInit callback ID
+  * @param  pCallback pointer to the Callback function
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_RegisterCallback(COMP_HandleTypeDef *hcomp, HAL_COMP_CallbackIDTypeDef CallbackID,
+                                            pCOMP_CallbackTypeDef pCallback)
+{
+  HAL_StatusTypeDef status = HAL_OK;
+
+  if (pCallback == NULL)
+  {
+    /* Update the error code */
+    hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+    return HAL_ERROR;
+  }
+
+  if (HAL_COMP_STATE_READY == hcomp->State)
+  {
+    switch (CallbackID)
+    {
+      case HAL_COMP_TRIGGER_CB_ID :
+        hcomp->TriggerCallback = pCallback;
+        break;
+
+      case HAL_COMP_MSPINIT_CB_ID :
+        hcomp->MspInitCallback = pCallback;
+        break;
+
+      case HAL_COMP_MSPDEINIT_CB_ID :
+        hcomp->MspDeInitCallback = pCallback;
+        break;
+
+      default :
+        /* Update the error code */
+        hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+        /* Return error status */
+        status = HAL_ERROR;
+        break;
+    }
+  }
+  else if (HAL_COMP_STATE_RESET == hcomp->State)
+  {
+    switch (CallbackID)
+    {
+      case HAL_COMP_MSPINIT_CB_ID :
+        hcomp->MspInitCallback = pCallback;
+        break;
+
+      case HAL_COMP_MSPDEINIT_CB_ID :
+        hcomp->MspDeInitCallback = pCallback;
+        break;
+
+      default :
+        /* Update the error code */
+        hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+        /* Return error status */
+        status = HAL_ERROR;
+        break;
+    }
+  }
+  else
+  {
+    /* Update the error code */
+    hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+    /* Return error status */
+    status =  HAL_ERROR;
+  }
+
+  return status;
+}
+
+/**
+  * @brief  Unregister a COMP Callback
+  *         COMP callback is redirected to the weak predefined callback
+  * @param  hcomp Pointer to a COMP_HandleTypeDef structure that contains
+  *                the configuration information for the specified COMP.
+  * @param  CallbackID ID of the callback to be unregistered
+  *         This parameter can be one of the following values:
+  *          @arg @ref HAL_COMP_TRIGGER_CB_ID Trigger callback ID
+  *          @arg @ref HAL_COMP_MSPINIT_CB_ID MspInit callback ID
+  *          @arg @ref HAL_COMP_MSPDEINIT_CB_ID MspDeInit callback ID
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_UnRegisterCallback(COMP_HandleTypeDef *hcomp, HAL_COMP_CallbackIDTypeDef CallbackID)
+{
+  HAL_StatusTypeDef status = HAL_OK;
+
+  if (HAL_COMP_STATE_READY == hcomp->State)
+  {
+    switch (CallbackID)
+    {
+      case HAL_COMP_TRIGGER_CB_ID :
+        hcomp->TriggerCallback = HAL_COMP_TriggerCallback;         /* Legacy weak callback */
+        break;
+
+      case HAL_COMP_MSPINIT_CB_ID :
+        hcomp->MspInitCallback = HAL_COMP_MspInit;                 /* Legacy weak MspInit */
+        break;
+
+      case HAL_COMP_MSPDEINIT_CB_ID :
+        hcomp->MspDeInitCallback = HAL_COMP_MspDeInit;             /* Legacy weak MspDeInit */
+        break;
+
+      default :
+        /* Update the error code */
+        hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+        /* Return error status */
+        status =  HAL_ERROR;
+        break;
+    }
+  }
+  else if (HAL_COMP_STATE_RESET == hcomp->State)
+  {
+    switch (CallbackID)
+    {
+      case HAL_COMP_MSPINIT_CB_ID :
+        hcomp->MspInitCallback = HAL_COMP_MspInit;                 /* Legacy weak MspInit */
+        break;
+
+      case HAL_COMP_MSPDEINIT_CB_ID :
+        hcomp->MspDeInitCallback = HAL_COMP_MspDeInit;             /* Legacy weak MspDeInit */
+        break;
+
+      default :
+        /* Update the error code */
+        hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+        /* Return error status */
+        status =  HAL_ERROR;
+        break;
+    }
+  }
+  else
+  {
+    /* Update the error code */
+    hcomp->ErrorCode |= HAL_COMP_ERROR_INVALID_CALLBACK;
+
+    /* Return error status */
+    status =  HAL_ERROR;
+  }
+
+  return status;
+}
+
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+
+/**
+  * @}
+  */
+
+/** @defgroup COMP_Exported_Functions_Group2 Start-Stop operation functions
+  *  @brief   Start-Stop operation functions.
+  *
+@verbatim
+ ===============================================================================
+                      ##### IO operation functions #####
+ ===============================================================================
+    [..]  This section provides functions allowing to:
+      (+) Start a comparator instance.
+      (+) Stop a comparator instance.
+
+@endverbatim
+  * @{
+  */
+
+/**
+  * @brief  Start the comparator.
+  * @param  hcomp  COMP handle
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_Start(COMP_HandleTypeDef *hcomp)
+{
+  __IO uint32_t wait_loop_index = 0UL;
+  HAL_StatusTypeDef status = HAL_OK;
+
+  /* Check the COMP handle allocation and lock status */
+  if (hcomp == NULL)
+  {
+    status = HAL_ERROR;
+  }
+  else if (__HAL_COMP_IS_LOCKED(hcomp))
+  {
+    status = HAL_ERROR;
+  }
+  else
+  {
+    /* Check the parameter */
+    assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+    if (hcomp->State == HAL_COMP_STATE_READY)
+    {
+      /* Enable the selected comparator */
+      SET_BIT(hcomp->Instance->CSR, COMP_CSR_EN);
+
+      /* Set HAL COMP handle state */
+      hcomp->State = HAL_COMP_STATE_BUSY;
+
+      /* Delay for COMP startup time */
+      /* Wait loop initialization and execution */
+      /* Note: Variable divided by 2 to compensate partially              */
+      /*       CPU processing cycles, scaling in us split to not          */
+      /*       exceed 32 bits register capacity and handle low frequency. */
+      wait_loop_index = ((COMP_DELAY_STARTUP_US / 10UL) * ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
+      while (wait_loop_index != 0UL)
+      {
+        wait_loop_index--;
+      }
+    }
+    else
+    {
+      status = HAL_ERROR;
+    }
+  }
+
+  return status;
+}
+
+/**
+  * @brief  Stop the comparator.
+  * @param  hcomp  COMP handle
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_Stop(COMP_HandleTypeDef *hcomp)
+{
+  HAL_StatusTypeDef status = HAL_OK;
+
+  /* Check the COMP handle allocation and lock status */
+  if (hcomp == NULL)
+  {
+    status = HAL_ERROR;
+  }
+  else if (__HAL_COMP_IS_LOCKED(hcomp))
+  {
+    status = HAL_ERROR;
+  }
+  else
+  {
+    /* Check the parameter */
+    assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+    /* Check compliant states: HAL_COMP_STATE_READY or HAL_COMP_STATE_BUSY    */
+    /* (all states except HAL_COMP_STATE_RESET and except locked status.      */
+    if (hcomp->State != HAL_COMP_STATE_RESET)
+    {
+      /* Disable the selected comparator */
+      CLEAR_BIT(hcomp->Instance->CSR, COMP_CSR_EN);
+
+      /* Set HAL COMP handle state */
+      hcomp->State = HAL_COMP_STATE_READY;
+    }
+    else
+    {
+      status = HAL_ERROR;
+    }
+  }
+
+  return status;
+}
+
+/**
+  * @brief  Comparator IRQ handler.
+  * @param  hcomp  COMP handle
+  * @retval None
+  */
+void HAL_COMP_IRQHandler(COMP_HandleTypeDef *hcomp)
+{
+  /* Get the EXTI line corresponding to the selected COMP instance */
+  uint32_t exti_line = COMP_GET_EXTI_LINE(hcomp->Instance);
+
+  /* Check COMP EXTI flag */
+  if (LL_EXTI_IsActiveRisingFlag_0_31(exti_line) != 0UL)
+  {
+    /* Check whether comparator is in independent or window mode */
+    if (READ_BIT(COMP12_COMMON->CSR, COMP_CSR_WINMODE) != 0UL)
+    {
+      /* Clear COMP EXTI line pending bit of the pair of comparators          */
+      /* in window mode.                                                      */
+      /* Note: Pair of comparators in window mode can both trig IRQ when      */
+      /*       input voltage is changing from "out of window" area            */
+      /*       (low or high ) to the other "out of window" area (high or low).*/
+      /*       Both flags must be cleared to call comparator trigger          */
+      /*       callback is called once.                                       */
+      LL_EXTI_ClearRisingFlag_0_31((COMP_EXTI_LINE_COMP1 | COMP_EXTI_LINE_COMP2));
+    }
+    else
+    {
+      /* Clear COMP EXTI line pending bit */
+      LL_EXTI_ClearRisingFlag_0_31(exti_line);
+    }
+
+    /* COMP trigger user callback */
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+    hcomp->TriggerCallback(hcomp);
+#else
+    HAL_COMP_TriggerCallback(hcomp);
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+  }
+  else if (LL_EXTI_IsActiveFallingFlag_0_31(exti_line) != 0UL)
+  {
+    /* Check whether comparator is in independent or window mode */
+    if (READ_BIT(COMP12_COMMON->CSR, COMP_CSR_WINMODE) != 0UL)
+    {
+      /* Clear COMP EXTI line pending bit of the pair of comparators          */
+      /* in window mode.                                                      */
+      /* Note: Pair of comparators in window mode can both trig IRQ when      */
+      /*       input voltage is changing from "out of window" area            */
+      /*       (low or high ) to the other "out of window" area (high or low).*/
+      /*       Both flags must be cleared to call comparator trigger          */
+      /*       callback is called once.                                       */
+      LL_EXTI_ClearFallingFlag_0_31((COMP_EXTI_LINE_COMP1 | COMP_EXTI_LINE_COMP2));
+    }
+    else
+    {
+      /* Clear COMP EXTI line pending bit */
+      LL_EXTI_ClearFallingFlag_0_31(exti_line);
+    }
+
+    /* COMP trigger callback */
+#if (USE_HAL_COMP_REGISTER_CALLBACKS == 1)
+    hcomp->TriggerCallback(hcomp);
+#else
+    HAL_COMP_TriggerCallback(hcomp);
+#endif /* USE_HAL_COMP_REGISTER_CALLBACKS */
+  }
+  else
+  {
+    /* nothing to do */
+  }
+}
+
+/**
+  * @}
+  */
+
+/** @defgroup COMP_Exported_Functions_Group3 Peripheral Control functions
+  *  @brief   Management functions.
+  *
+@verbatim
+ ===============================================================================
+                      ##### Peripheral Control functions #####
+ ===============================================================================
+    [..]
+    This subsection provides a set of functions allowing to control the comparators.
+
+@endverbatim
+  * @{
+  */
+
+/**
+  * @brief  Lock the selected comparator configuration.
+  * @note   A system reset is required to unlock the comparator configuration.
+  * @note   Locking the comparator from reset state is possible
+  *         if __HAL_RCC_SYSCFG_CLK_ENABLE() is being called before.
+  * @param  hcomp  COMP handle
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_COMP_Lock(COMP_HandleTypeDef *hcomp)
+{
+  HAL_StatusTypeDef status = HAL_OK;
+
+  /* Check the COMP handle allocation and lock status */
+  if (hcomp == NULL)
+  {
+    status = HAL_ERROR;
+  }
+  else if (__HAL_COMP_IS_LOCKED(hcomp))
+  {
+    status = HAL_ERROR;
+  }
+  else
+  {
+    /* Check the parameter */
+    assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+    /* Set HAL COMP handle state */
+    switch (hcomp->State)
+    {
+      case HAL_COMP_STATE_RESET:
+        hcomp->State = HAL_COMP_STATE_RESET_LOCKED;
+        break;
+      case HAL_COMP_STATE_READY:
+        hcomp->State = HAL_COMP_STATE_READY_LOCKED;
+        break;
+      default: /* HAL_COMP_STATE_BUSY */
+        hcomp->State = HAL_COMP_STATE_BUSY_LOCKED;
+        break;
+    }
+
+    /* Set the lock bit corresponding to selected comparator */
+    __HAL_COMP_LOCK(hcomp);
+  }
+
+  return status;
+}
+
+/**
+  * @brief  Return the output level (high or low) of the selected comparator.
+  *         The output level depends on the selected polarity.
+  *         If the polarity is not inverted:
+  *           - Comparator output is low when the input plus is at a lower
+  *             voltage than the input minus
+  *           - Comparator output is high when the input plus is at a higher
+  *             voltage than the input minus
+  *         If the polarity is inverted:
+  *           - Comparator output is high when the input plus is at a lower
+  *             voltage than the input minus
+  *           - Comparator output is low when the input plus is at a higher
+  *             voltage than the input minus
+  * @param  hcomp  COMP handle
+  * @retval Returns the selected comparator output level:
+  *         @arg COMP_OUTPUT_LEVEL_LOW
+  *         @arg COMP_OUTPUT_LEVEL_HIGH
+  *
+  */
+uint32_t HAL_COMP_GetOutputLevel(const COMP_HandleTypeDef *hcomp)
+{
+  /* Check the parameter */
+  assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+  return (uint32_t)(READ_BIT(hcomp->Instance->CSR, COMP_CSR_VALUE)
+                    >> COMP_OUTPUT_LEVEL_BITOFFSET_POS);
+}
+
+/**
+  * @brief  Comparator trigger callback.
+  * @param  hcomp  COMP handle
+  * @retval None
+  */
+__weak void HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp)
+{
+  /* Prevent unused argument(s) compilation warning */
+  UNUSED(hcomp);
+
+  /* NOTE : This function should not be modified, when the callback is needed,
+            the HAL_COMP_TriggerCallback should be implemented in the user file
+   */
+}
+
+
+/**
+  * @}
+  */
+
+/** @defgroup COMP_Exported_Functions_Group4 Peripheral State functions
+  *  @brief   Peripheral State functions.
+  *
+@verbatim
+ ===============================================================================
+                      ##### Peripheral State functions #####
+ ===============================================================================
+    [..]
+    This subsection permit to get in run-time the status of the peripheral.
+
+@endverbatim
+  * @{
+  */
+
+/**
+  * @brief  Return the COMP handle state.
+  * @param  hcomp  COMP handle
+  * @retval HAL state
+  */
+HAL_COMP_StateTypeDef HAL_COMP_GetState(const COMP_HandleTypeDef *hcomp)
+{
+  /* Check the COMP handle allocation */
+  if (hcomp == NULL)
+  {
+    return HAL_COMP_STATE_RESET;
+  }
+
+  /* Check the parameter */
+  assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+  /* Return HAL COMP handle state */
+  return hcomp->State;
+}
+
+/**
+  * @brief  Return the COMP error code.
+  * @param hcomp COMP handle
+  * @retval COMP error code
+  */
+uint32_t HAL_COMP_GetError(const COMP_HandleTypeDef *hcomp)
+{
+  /* Check the parameters */
+  assert_param(IS_COMP_ALL_INSTANCE(hcomp->Instance));
+
+  return hcomp->ErrorCode;
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#endif /* COMP1 || COMP2 */
+
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+/**
+  * @}
+  */

+ 2 - 2
Middlewares/Third_Party/FreeRTOS/Source/include/task.h

@@ -2533,7 +2533,7 @@ TaskHandle_t pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;
  */
 void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
 
-// #if (imcUSE_IMC_KERNEL == 1)
+#if (imcUSE_IMC_KERNEL == 1)
 
 // // #include "ImC/imc_kernel.h"
 // // #include "cmsis_os.h"
@@ -2544,7 +2544,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
 
 // // osThreadId_t imcOsThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
 
-// #endif // imcUSE_IMC_KERNEL
+#endif // imcUSE_IMC_KERNEL
 
 #ifdef __cplusplus
 }

+ 23 - 0
Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM33_NTZ/non_secure/port.c

@@ -930,6 +930,29 @@ uint8_t ucSVCNumber;
 					"pxCurrentTCBConst3: .word pxCurrentTCB				\n" );
 			}
 			break;
+
+			case portSVC_IMC_CHECKPOINT_ALL_TASKS:
+				__asm volatile(
+
+					"	stmdb sp!, {lr}				\n"
+					"	push {r0}							\n"
+					"	push {r1}							\n"
+					"ldr r1, pxImcTCB					\n"
+					"ldr r0, [r1]					\n"
+					"	mov r1, %0 							\n"
+					"	msr basepri, r1						\n"
+					"	dsb									\n"
+					"	isb									\n"
+
+					"	bl xTaskCheckpointImcTask		\n"
+
+					"	pop {r1}								\n"
+					"	pop {r0}								\n"
+					"	pop {lr}								\n"
+
+					"pxImcTCB: .word imcTCB				\n" ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
+				);
+			break;
 		#endif /* imcUSE_IMC_KERNEL */
 
 		default:

+ 95 - 0
Middlewares/Third_Party/FreeRTOS/Source/tasks.c

@@ -5309,8 +5309,10 @@ when performing module tests). */
 
 #include "ImC/imc_kernel.h"
 #include "ImC/imc_extension.h"
+#include "ImC/imc_api.h"
 #include <stdio.h>
 #if (imcUSE_IMC_KERNEL == 1)
+extern ADC_HandleTypeDef ADC_HANDLER_SBC;
 
 #include "stm32l5xx.h"
 
@@ -5323,6 +5325,8 @@ uint8_t ucLatestBufferIndex[imcMAX_NUM_TASKS] __attribute__((section(".kernel_nv
 #define prvUNUSED_STACK_SIZE(tcb) ((tcb->pxTopOfStack - tcb->pxStack) * sizeof(StackType_t))
 #define prvCHECKPOINT_STACK(buffer, start, size) (memcpy((void *)buffer + start - stack_start, (void *)start, size))
 
+TCB_t *imcTCB;
+
 void xTaskCheckpointCurrentTask(uint32_t lr_register)
 {
 	#if(imcPRINT_STATS)
@@ -5358,6 +5362,87 @@ void xTaskCheckpointCurrentTask(uint32_t lr_register)
 
 	__DMB();
 	imc_backup_estimations();
+
+	#if (imcPRINT_STATS)
+		first_checkpoint = 1;
+		imc_backup_stats();
+	#endif
+
+	#if (imcPRINT_LATENCY_OVERHEAD)
+		imc_backup_latency_overhead();
+	#endif
+
+	int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
+	#if(imcUSE_CHECKPOINT_PASS_COUNTER)
+		int turnoff_volt = 3600;
+	#else
+		int turnoff_volt = 3600;
+	#endif
+
+	if(volt < turnoff_volt) {
+		while(1) { __ASM(" nop"); }
+	}
+
+	// portENABLE_INTERRUPTS();
+	
+}
+
+void xTaskCheckpointImcTask(TCB_t *tcb)
+{
+	#if(imcPRINT_STATS)
+		imc_checkpoint_executed++;
+	#endif
+	// portDISABLE_INTERRUPTS();
+	// TCB_t *tcb = pxCurrentTCB;
+	UBaseType_t taskNumber = tcb->uxTCBNumber;
+	uint8_t currentBufferIndex = ucLatestBufferIndex[taskNumber];
+	uint8_t nextBufferIndex = currentBufferIndex == 0 ? 1 : 0;
+
+	// Relevant values
+	uint32_t stack_start = (uint32_t)tcb->pxStack;
+	// uint32_t stack_end = (uint32_t)stack_start + (imcSTACK_SIZE - 1) * sizeof(StackType_t);
+	uint32_t top_of_stack = (uint32_t)tcb->pxTopOfStack;
+	uint32_t checkpoint_size = 0;
+
+	// ========== start stack checkpointing ==========
+	// stack checkpoint consists of two operations: checkpointing the active frame and the inactive frames
+	StackType_t *buffer = xImcTaskStackBuffers[taskNumber][nextBufferIndex];
+	// 1: if no optimization is enabled, checkpoint the entire used stack (inactive + active)
+	checkpoint_size = prvUSED_STACK_SIZE(tcb);
+	prvCHECKPOINT_STACK(buffer, top_of_stack, checkpoint_size);
+	// ========== end stack checkpointing ==========
+
+	// checkpoint TCB
+	memcpy(&xTcbSnapshots[taskNumber][nextBufferIndex], tcb, sizeof(TCB_t));
+
+	__DMB();
+
+	ucLatestBufferIndex[taskNumber] = nextBufferIndex;
+	ucTaskSnapshotValid[taskNumber] = pdTRUE;
+
+	__DMB();
+	// imc_backup_estimations();
+
+	#if (imcPRINT_STATS)
+		first_checkpoint = 1;
+		// imc_backup_stats();
+	#endif
+
+	#if (imcPRINT_LATENCY_OVERHEAD)
+		imc_backup_latency_overhead();
+	#endif
+
+	// int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
+	// #if(imcUSE_CHECKPOINT_PASS_COUNTER)
+	// 	int turnoff_volt = 3600;
+	// #else
+	// 	int turnoff_volt = 3600;
+	// #endif
+
+	// if(volt < turnoff_volt) {
+	// 	while(1) { __ASM(" nop"); }
+	// }
+
 	// portENABLE_INTERRUPTS();
 	
 }
@@ -5381,6 +5466,14 @@ void vRecoverTask(TCB_t *tcb)
 	// recover stack
 	memcpy((void *)(tcb->pxTopOfStack), (void *)((unsigned int)(xImcTaskStackBuffers[taskNumber][bufferIndex]) + (unsigned int)(prvUNUSED_STACK_SIZE(tcb))), prvUSED_STACK_SIZE(tcb));
 
+	#if (imcPRINT_STATS)
+		imc_recover_stats();
+	#endif
+
+	#if (imcPRINT_LATENCY_OVERHEAD)
+		imc_recover_latency_overhead();
+	#endif
+
 	__DMB();
 }
 
@@ -5397,6 +5490,8 @@ osThreadId_t imcOsThreadNew(osThreadFunc_t func, void *argument, const osThreadA
 	TCB_t *tcb = (TCB_t *)attr->cb_mem;
 	UBaseType_t taskNumber = tcb->uxTCBNumber;
 
+	imcTCB = tcb;
+
 	if (ucTaskSnapshotValid[taskNumber] == pdTRUE)
 	{
 #if(imcPRINT_RECOVERY_MESSAGE)

File diff suppressed because it is too large
+ 39 - 0
imc/exprs/dac2025/1_measure_timings/draw_graph_expr_1.ipynb


+ 94 - 0
imc/exprs/dac2025/1_measure_timings/draw_graph_expr_1.py

@@ -0,0 +1,94 @@
+import pickle
+import pandas as pd
+import seaborn as sns
+import pprint
+
+from imc_utils.oscilloscope_dsox1204a import CommonOperations
+
+def draw_graph():
+    with open("output/sample_result.pickle", "rb") as f:
+        result = pickle.load(f)
+    df = pd.DataFrame(result["results"])
+    info = result["info"]
+    x_increment = info["x_increment"]
+
+    print(info)
+    eps_intervals = CommonOperations.get_high_intervals(df["eps"], 3)
+    task_intervals = CommonOperations.get_high_intervals(df["task"], 1)
+
+    eps_lengths = [ v[1] - v[0] for v in eps_intervals]
+    task_lengths = [ v[1] - v[0] for v in task_intervals]
+
+    iterations = []
+
+    for i in range(len(eps_intervals)):
+        eps_interval = eps_intervals[i]
+        eps_start = eps_interval[0]
+
+        iteration = None
+        
+        if i == len(eps_intervals)-1:
+            next_eps_start = float("inf")
+        else:
+            next_eps_interval = eps_intervals[i+1]
+            next_eps_start = next_eps_interval[0]
+
+        for task_interval in task_intervals:
+            task_start = task_interval[0]
+            if eps_start <= task_start and task_start <= next_eps_start:
+                iteration = {
+                    "eps": eps_interval,
+                    "task": task_interval
+                }
+                break
+        
+        if iteration is None:
+            iteration = {
+                "eps": eps_interval,
+                "task": None,
+            }
+
+        iterations.append(iteration)
+
+    results = []
+
+    for iteration in iterations:
+        eps_interval = iteration["eps"]
+        task_interval = iteration["task"]
+        eps_duration = eps_interval[1] - eps_interval[0]
+        eps_duration *= x_increment * 1000
+        task_duration = task_interval[1] - task_interval[0] if not task_interval is None else 0
+        task_duration *= x_increment * 1000
+        ratio = task_duration / eps_duration
+        results.append({
+            "eps_duration": eps_duration,
+            "task_duration": task_duration,
+            "ratio": ratio,
+        })
+    
+    d = pd.DataFrame(results)
+    print(d)
+    total_eps_duration = d["eps_duration"].sum()
+    total_task_duration = d["task_duration"].sum()
+
+    average_eps_duration = d["eps_duration"].mean()
+    average_task_duration = d["task_duration"].mean()
+    overhead_ticks = total_eps_duration - total_task_duration
+    average_overhead_ticks = overhead_ticks / len(d)
+    print("total eps duration:", total_eps_duration)
+    print("total task duration:", total_task_duration)
+    print("efficiency:", total_task_duration/total_eps_duration)
+    print(f"average eps duration: {average_eps_duration:.3f} ms")
+    print(f"average task duration: {average_task_duration:.3f} ms")
+    print(f"average wasted: {average_overhead_ticks:.3f} ms")
+
+    g = sns.lineplot(df)
+    g.grid()
+    g.set_ylim([-1, 4])
+
+    for (start, end) in eps_intervals:
+        g.axvspan(start, end, alpha=0.3)
+
+    for (start, end) in task_intervals:
+        g.axvspan(start, end, facecolor="b", alpha=0.3)
+    

+ 55 - 0
imc/exprs/dac2025/1_measure_timings/run_expr_1.py

@@ -0,0 +1,55 @@
+import pickle
+import time
+
+from imc_utils.oscilloscope_dsox1204a import DSOX1204A
+from imc_utils.pps_e36311a import PPS_E36311A
+
+scope = DSOX1204A()
+
+timebase = 1
+scope.set_volt_scale(3, 1)
+scope.set_timebase(timebase)
+scope.set_timebase_reference_left()
+scope.set_trigger_rising_edge(3, 3)
+scope.set_acquisition_type("hresolution")
+scope.aquire_single()
+
+pps = PPS_E36311A()
+# target_current = 0.005
+# target_voltage = 1
+target_current = 0.002
+target_voltage = 3.3
+pps.set_current(target_current, 1)
+pps.set_voltage(target_voltage, 1)
+pps.output_on(1)
+
+time.sleep(timebase * 10 + 3)
+
+print("receiving vdd")
+result_vdd = scope.get_waveform(1)
+print("receiving task")
+result_task = scope.get_waveform(2)
+print("receiving eps")
+result_eps = scope.get_waveform(3)
+
+print("x increment:", scope.get_xincrement())
+
+pps.output_off(1)
+
+results = {
+    "vdd": result_vdd,
+    "task": result_task,
+    "eps": result_eps
+}
+info = {
+    "x_increment": scope.get_xincrement(),
+    "target_current": target_current,
+}
+
+output = {
+    "results": results,
+    "info": info,
+}
+
+with open("output/sample_result.pickle", "wb") as f:
+    pickle.dump(output, f)

File diff suppressed because it is too large
+ 42 - 0
imc/exprs/dac2025/2_error_low_voltage/draw_graph_expr_2.ipynb


+ 59 - 0
imc/exprs/dac2025/2_error_low_voltage/draw_graph_expr_2.py

@@ -0,0 +1,59 @@
+import pickle
+import os
+import pandas as pd
+import seaborn as sns
+import matplotlib.pyplot as plt
+import matplotlib.ticker
+from scipy import stats
+import numpy as np
+
+import plot_utils
+
+def draw_graph():
+    with open("output/adc_demo.pickle", "rb") as f:
+        df = pickle.load(f)
+    
+    with open("output/voltage_real.pickle", "rb") as f:
+        voltage_scope = pickle.load(f)
+
+    x_tick = 0.000130208333
+
+    # make the first tick to be 100ms
+    first_tick = df.iloc[0]["tick"]
+    tick_to_ms = 1000 / 32_000_000
+    df["ms"] = 100 + (df["tick"] - first_tick) * tick_to_ms
+    print(df)
+
+    df_eps_off = df[df["eps_on"] == False]
+    eps_off_start, eps_off_end = df_eps_off.iloc[0]["ms"], df_eps_off.iloc[-1]["ms"]
+    print(eps_off_start, eps_off_end)
+
+    df2 = pd.DataFrame(voltage_scope)
+    df2["ms"] = df2.index * x_tick * 1000
+    df2.columns = ["voltage_real", "ms"]
+
+    plot_utils.set_theme_seaborn(kind="line")
+
+    g = sns.lineplot(
+        df,
+        x = "ms",
+        y = "voltage_adc",
+        label = "From ADC",
+    )
+    sns.lineplot(
+        df2,
+        x = "ms",
+        y = "voltage_real",
+        label = "Measurement",
+    )
+
+    g.axvspan(eps_off_start, eps_off_end, color = "lightgray", alpha=0.6)
+
+    g.set_xlim([100, 750])
+    g.legend()
+    g.set_ylabel("Capacitor voltage (V)")
+    g.set_xlabel("Time after boot (ms)")
+
+    print("4.7mF, 10mA, 3.3V")
+
+    return g

+ 171 - 0
imc/exprs/dac2025/2_error_low_voltage/run_expr_2.py

@@ -0,0 +1,171 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+from imc_utils.oscilloscope_dsox1204a import DSOX1204A
+
+import imc_utils.serial_device
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+use_smu = False
+
+# pin setup: scope #3 -> EPS capacitor voltage
+# pin setup: GPIO PF10 -> EPS on signal
+
+def main():
+    pps = PPS_E36311A()
+
+    if use_smu:
+        volt = 3.3
+        smu = SMU_B2902A(voltage=3.3)
+    config = get_default_build_config()
+
+    scope = DSOX1204A()
+
+    timebase = 0.1
+    scope.set_volt_scale(3, 2)
+    scope.set_timebase(timebase)
+    scope.set_timebase_reference_left()
+    scope.set_trigger_rising_edge(2, 3)
+    scope.set_acquisition_type("hresolution")
+
+    benchmark = "adc_demo"
+
+    total_iterations = 1
+    target_current_limit = 0.010
+
+    all_records = []
+    config.bench_name = benchmark
+
+    if use_smu:
+        smu.set_current_limit(0.1)
+        smu.power_on()
+    else:
+        pps.set_voltage(3.3, 1)
+        pps.set_current(0.1, 1)
+        pps.output_on(1)
+
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=False)
+
+    if use_smu:
+        smu.set_current_limit(target_current_limit)
+    else:
+        pps.set_current(target_current_limit, 1)
+
+    time.sleep(1)
+
+    env.resume_board(terminate=True)
+
+    ser = imc_utils.serial_device.get_serial()
+    lines = []
+    start_deteced = False
+
+    time.sleep(2)
+
+    ser.read_all()
+    while True:
+        if ser.readable():
+            res = ser.readline()
+            try:
+                line = res.decode()[: len(res) - 1]
+                line = line.strip()
+            except:
+                continue
+
+            if line.startswith("Start benchmark"):
+                if start_deteced is False:
+                    start_deteced = True
+                    scope.aquire_single()
+                    continue
+                else:
+                    break
+            if start_deteced:
+                lines.append(line)
+    
+    results = []
+
+    results_real = scope.get_waveform(3)
+    print(results_real)
+
+    x_increment = scope.get_xincrement()
+
+    for line in lines:
+        try:
+            tick, eps_on, voltage = line.split()
+            tick = int(tick.strip())
+            eps_on = True if eps_on.strip() == "1" else False
+            voltage = float(voltage.strip())
+            results.append({
+                "tick": tick,
+                "eps_on": eps_on,
+                "voltage_adc": voltage,
+            })
+        except:
+            continue
+
+    first_voltage_tick = results[0]["tick"]
+    print(x_increment)
+
+    # def tick_to_waveform_index(tick):
+    #     tick_offset = tick - first_voltage_tick
+    #     waveform_offset = int(timebase / x_increment)
+    #     x_increment_to_ms = 0.001 / x_increment
+    #     return waveform_offset + int(tick_offset * x_increment_to_ms)
+
+    # for result in results:
+    #     tick = result["tick"]
+    #     result.update({
+    #         "voltage_real": results_real[tick_to_waveform_index(tick)],
+    #         "index": tick_to_waveform_index(tick),
+    #     })
+
+    df = pd.DataFrame(results)
+    print(df)
+    save_records(benchmark, df)
+
+    with open("output/voltage_real.pickle", "wb") as f:
+        pickle.dump(results_real, f)
+
+    if use_smu:
+        smu.power_off()
+    else:
+        pps.output_off(1)
+
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = True
+    config.custom_unroll = False
+    config.loop_opt_debug = False
+    return config
+
+
+def save_records(bench_name, df):
+    with open(f"output/{bench_name}.pickle", "wb") as f:
+        pickle.dump(df, f)
+
+
+if __name__ == "__main__":
+    main()

File diff suppressed because it is too large
+ 88 - 0
imc/exprs/dac2025/3_fmc_error/draw_graph_expr_3.ipynb


+ 78 - 0
imc/exprs/dac2025/3_fmc_error/draw_graph_expr_3.py

@@ -0,0 +1,78 @@
+import pickle
+import os
+import pandas as pd
+import seaborn as sns
+import matplotlib.pyplot as plt
+import matplotlib.ticker
+from scipy import stats
+import numpy as np
+
+import plot_utils
+
+
+def draw_graph():
+    with open("output/fmc_expr.pickle", "rb") as f:
+        df = pickle.load(f)
+
+    with open("output/vdd.pickle", "rb") as f:
+        vdd = pickle.load(f)
+
+    x_tick = 6.51041666e-05
+
+    # make the first tick to be 50ms
+    first_tick = df.iloc[0]["tick"]
+    tick_to_ms = 1000 / 32_000_000
+    df["ms"] = 50 + (df["tick"] - first_tick) * tick_to_ms
+    error_rates = [0]
+    for i in range(1, len(df)):
+        current = df.iloc[i]
+        prev = df.iloc[i-1]
+        sampled = current["total"] - prev["total"]
+        errors = current["errors"] - prev["errors"]
+        error_rates.append(100 * errors/sampled)
+    df["error_rate"] = error_rates
+    print(df.to_string())
+
+    # df_eps_off = df[df["eps_on"] == False]
+    # eps_off_start, eps_off_end = df_eps_off.iloc[0]["ms"], df_eps_off.iloc[-1]["ms"]
+    # print(eps_off_start, eps_off_end)
+
+    df2 = pd.DataFrame(vdd)
+    df2["ms"] = df2.index * x_tick * 1000
+    df2.columns = ["vdd", "ms"]
+
+    print(df2)
+
+    plot_utils.set_theme_seaborn(kind="line")
+
+    g = sns.lineplot(
+        df,
+        x="ms",
+        y="error_rate",
+        # marker=".",
+        label="FMC error rate",
+    )
+    ax2 = g.twinx()
+    sns.lineplot(
+        df2,
+        x="ms",
+        y="vdd",
+        label="Vdd",
+        linestyle="--",
+        color="cornflowerblue",
+        ax = ax2,
+    )
+
+    # g.axvspan(eps_off_start, eps_off_end, color="lightgray", alpha=0.6)
+
+    g.set_xlim([100, 350])
+    # g.legend()
+    g.set_ylabel("Memory error rate (%)")
+    g.set_xlabel("Time after boot (ms)")
+
+    ax2.set_ylabel("Voltage")
+    ax2.grid()
+
+    print("1mF, 15mA, 3.3V")
+
+    return g

+ 170 - 0
imc/exprs/dac2025/3_fmc_error/run_expr_3.py

@@ -0,0 +1,170 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+from imc_utils.oscilloscope_dsox1204a import DSOX1204A
+
+import imc_utils.serial_device
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+use_smu = False
+
+
+def main():
+    pps = PPS_E36311A()
+
+    if use_smu:
+        volt = 3.3
+        smu = SMU_B2902A(voltage=3.3)
+    config = get_default_build_config()
+
+    scope = DSOX1204A()
+
+    timebase = 0.05
+    scope.set_volt_scale(3, 1)
+    scope.set_timebase(timebase)
+    scope.set_timebase_reference_left()
+    scope.set_trigger_rising_edge(2, 2)
+    scope.set_acquisition_type("hresolution")
+
+    benchmark = "fmc_expr"
+
+    total_iterations = 1
+    target_current_limit = 0.015
+
+    all_records = []
+    config.bench_name = benchmark
+
+    if use_smu:
+        smu.set_current_limit(0.1)
+        smu.power_on()
+    else:
+        pps.set_voltage(3.3, 1)
+        pps.set_current(0.1, 1)
+        pps.output_on(1)
+
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=False)
+
+    if use_smu:
+        smu.set_current_limit(target_current_limit)
+    else:
+        pps.set_current(target_current_limit, 1)
+
+    time.sleep(1)
+
+    env.resume_board(terminate=True)
+
+    ser = imc_utils.serial_device.get_serial()
+    lines = []
+    start_deteced = False
+
+    time.sleep(2)
+
+    ser.read_all()
+    while True:
+        if ser.readable():
+            res = ser.readline()
+            try:
+                line = res.decode()[: len(res) - 1]
+                line = line.strip()
+            except:
+                continue
+
+            if line.startswith("Start benchmark"):
+                if start_deteced is False:
+                    start_deteced = True
+                    scope.aquire_single()
+                    continue
+                else:
+                    break
+            if start_deteced:
+                lines.append(line)
+
+    results = []
+
+    vdd = scope.get_waveform(1)
+    print(vdd)
+
+    x_increment = scope.get_xincrement()
+
+    for line in lines:
+        try:
+            tick, errors, total = line.split()
+            tick = int(tick.strip())
+            errors = int(errors.strip())
+            total = int(total.strip())
+            results.append(
+                {
+                    "tick": tick,
+                    "errors": errors,
+                    "total": total
+                }
+            )
+        except:
+            continue
+
+    print(x_increment)
+
+    # def tick_to_waveform_index(tick):
+    #     tick_offset = tick - first_voltage_tick
+    #     waveform_offset = int(timebase / x_increment)
+    #     x_increment_to_ms = 0.001 / x_increment
+    #     return waveform_offset + int(tick_offset * x_increment_to_ms)
+
+    # for result in results:
+    #     tick = result["tick"]
+    #     result.update({
+    #         "voltage_real": results_real[tick_to_waveform_index(tick)],
+    #         "index": tick_to_waveform_index(tick),
+    #     })
+
+    df = pd.DataFrame(results)
+    print(df)
+    save_records(benchmark, df)
+
+    with open("output/vdd.pickle", "wb") as f:
+        pickle.dump(vdd, f)
+
+    if use_smu:
+        smu.power_off()
+    else:
+        pps.output_off(1)
+
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = False
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.loop_opt_debug = False
+    return config
+
+
+def save_records(bench_name, df):
+    with open(f"output/{bench_name}.pickle", "wb") as f:
+        pickle.dump(df, f)
+
+
+if __name__ == "__main__":
+    main()

File diff suppressed because it is too large
+ 66 - 0
imc/exprs/dac2025/4_energy_efficiency/draw_graph_expr_4.ipynb


+ 152 - 0
imc/exprs/dac2025/4_energy_efficiency/draw_graph_expr_4.py

@@ -0,0 +1,152 @@
+import pickle
+import os
+import pandas as pd
+import seaborn as sns
+import matplotlib.pyplot as plt
+import matplotlib.ticker
+from scipy import stats
+import numpy as np
+
+import plot_utils
+from imc_utils.oscilloscope_dsox1204a import CommonOperations
+
+def merge_and_analyze_df(df_smu, df_scope):
+    df_smu["watt"] = df_smu["curr"] * df_smu["volt"]
+
+    df_scope = df_scope.drop(df_scope.tail(3).index)
+    df_scope["in_execution"] = df_scope["in_execution"].abs() > 1
+    df_scope["eps_on"] = df_scope["eps_on"].abs() > 1
+
+    timestamp_offset = df_smu.iloc[-1]["timestamp"] - df_scope.iloc[-1]["timestamp"]
+    df_smu["time_synced"] = df_smu["timestamp"] - timestamp_offset
+
+    time_resolution = df_scope.iloc[1]["timestamp"]
+    ratio = np.round(df_smu["time_synced"] / time_resolution)
+    df_smu["time_res_synced"] = ratio * time_resolution
+    duplicated_rows = df_smu.duplicated("time_res_synced", keep="first")
+    df_smu = df_smu[duplicated_rows == False]
+
+    df_smu_simple = df_smu.drop(columns=["curr", "volt", "timestamp", "time_synced"])
+    df_smu_simple = df_smu_simple.rename(
+        columns = {"time_res_synced": "timestamp"}
+    )
+    df = pd.merge(df_scope, df_smu_simple, how="left", on="timestamp")
+
+    results = []
+
+    eps_falling_edges = CommonOperations.get_falling_edge_index(df["eps_on"], 0.9)
+    eps_joules = []
+    for i in range(len(eps_falling_edges)-1):
+        start = eps_falling_edges[i]
+        end = eps_falling_edges[i+1]
+        watts = df.iloc[start:end+1]["watt"]
+        energy = watts.sum() * time_resolution
+        eps_joules.append(energy)
+
+        results.append({
+            "charge_start": df.iloc[start]["timestamp"],
+            "charge_end": df.iloc[end]["timestamp"],
+            "input_energy": energy,
+            "watt": watts.mean(),
+        })
+
+    in_execution_intervals = CommonOperations.get_high_intervals(df["in_execution"], 0.9)
+
+    for execution_interval in in_execution_intervals:
+        execution_start, execution_end = execution_interval
+        mask = execution_start - np.array(eps_falling_edges)
+        mask = np.where(mask > 0)
+        indices = mask[0]
+        if indices.size == 0:
+            continue
+        index = indices[-1]
+        if index == len(results):
+            continue
+
+        start_time = df.iloc[execution_start]["timestamp"]
+        end_time = df.iloc[execution_end]["timestamp"]
+        results[index].update({
+            "execution_start": start_time,
+            "execution_end": end_time,
+            "execution_time": end_time - start_time,
+        })
+
+    result = pd.DataFrame(results)
+
+    if result.empty:
+        return result
+    
+    execution_columns = ["execution_start", "execution_end", "execution_time"]
+    for col in execution_columns:
+        if col not in result.columns:
+            result[col] = np.nan
+
+    mask = np.isnan(result["execution_time"])
+    result.loc[mask, "execution_time"] = 0
+    result["time_per_energy"] = result["execution_time"] / result["input_energy"]
+
+    return result
+
+def print_stat_summary(df):
+    average_time_per_energy = df["time_per_energy"].mean()
+    average_execution_time = df[df["execution_time"] != 0]["execution_time"].mean()
+    average_power = df["watt"].mean()
+
+    print(f"average time per energy (s/j): {average_time_per_energy:.3f}")
+    print(f"average execution duration (ms): {average_execution_time*1000:.3f}")
+    print(f"average power (mW): {average_power*1000:.3f}")
+
+
+def approximate_watt(df: pd.DataFrame, resolution: float):
+    ratio = df["watt"] / resolution
+    df["watt_adjusted"] = resolution * np.round(ratio)
+    return df
+
+
+def draw_graph():
+    cap_sizes = [50, 100, 220, 470, 1000]
+    merged_dfs = []
+    for cap_size_uF in cap_sizes:
+        with open(f"output/result_{cap_size_uF}_uF.pickle", "rb") as f:
+            expr_results = pickle.load(f)
+        
+        dfs = []
+        for i, expr_result in enumerate(expr_results):
+            df_smu = expr_result["smu_result"]
+            df_scope = expr_result["scope_result"]
+            df = merge_and_analyze_df(df_smu, df_scope)
+            df["run_id"] = i
+            dfs.append(df)
+
+        df = pd.concat(dfs).reset_index(drop=True)
+        df = approximate_watt(df, 0.001)
+        df["cap_size_uF"] = cap_size_uF
+        merged_dfs.append(df)
+    
+    df = pd.concat(merged_dfs).reset_index()
+    print(df)
+
+    # plot_utils.set_theme_seaborn(kind="line")
+
+    watt_filter = [0.001, 0.002, 0.003, 0.005, 0.010]
+    df = df[np.isin(df["watt_adjusted"], watt_filter)]
+    g = sns.lineplot(
+        df,
+        x = "cap_size_uF",
+        y = "time_per_energy",
+        hue = "watt_adjusted",
+    )
+    return g
+
+    # g = sns.lineplot(
+    #     df_scope,
+    #     x="timestamp",
+    #     y="eps_on",
+    # )
+    # sns.lineplot(
+    #     df_scope,
+    #     x="timestamp",
+    #     y="in_execution",
+    #     linestyle="--",
+    #     color="cornflowerblue",
+    # )

+ 189 - 0
imc/exprs/dac2025/4_energy_efficiency/run_expr_4.py

@@ -0,0 +1,189 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+import threading
+import datetime
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+from imc_utils.oscilloscope_dsox1204a import DSOX1204A
+
+import imc_utils.serial_device
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+def set_current_limit_thread(current_limits, interval_sec, smu: SMU_B2902A):
+    for limit in current_limits:
+        # smu_busy = smu.smu.ask("*OPC?")
+        # print(smu_busy)
+        smu.smu.write("*WAI")
+        print(f"set current limit to: {limit*1000:.3f}mA")
+        smu.set_current_limit(limit)
+        time.sleep(interval_sec)
+
+def get_sampling_duration(curr_limit):
+    ratio = 0.020 / curr_limit
+    return 10 * ratio
+
+def get_scope_timebase(cap_size_uF):
+    d = {
+        1000: 3,
+        470: 2,
+        220: 1,
+        100: 0.8,
+        50: 0.5,
+    }
+    return d[cap_size_uF]
+
+def get_smu_sample_freq(cap_size_uF):
+    d = {
+        1000: 1000,
+        470: 1000,
+        220: 1000,
+        100: 2000,
+        50: 2000,
+    }
+    return d[cap_size_uF]
+
+def main():
+    volt = 1.5
+    cap_size_uF = 1000
+    smu_sample_freq = get_smu_sample_freq(cap_size_uF)
+    smu = SMU_B2902A(voltage=volt, sample_freq=smu_sample_freq)
+    smu.setup_sense()
+
+    config = get_default_build_config()
+
+    scope = DSOX1204A()
+
+    timebase = get_scope_timebase(cap_size_uF)
+    scope.set_volt_scale(3, 1)
+    scope.set_timebase(timebase)
+    scope.set_timebase_reference_left()
+    scope.set_trigger_falling_edge(3, 2)
+    scope.set_acquisition_type("hresolution")
+
+    benchmark = "vFFT"
+
+    current_limits = [ 0.001*i for i in range(20,0,-1)]
+    # current_limits = []
+    current_limits += [0.0005]
+    # current_limits = [0.01, 0.005, 0.001]
+
+    config.bench_name = benchmark
+
+    smu.set_current_limit(0.1)
+    smu.power_on()
+
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=False)
+
+
+    smu.power_on()
+    smu.set_current_limit(current_limits[0])
+    startup_time = 10
+    print(f"wait for startup ({startup_time}s)")
+    time.sleep(startup_time)
+
+    interval = get_sampling_duration(current_limits[0])
+    # t = threading.Thread(target=set_current_limit_thread, args=(current_limits, interval, smu))
+    # t.start()
+
+    results = []
+    i = 0
+    current_limit_index = 0
+    start = datetime.datetime.now()
+
+    while True:
+        print(f"({i}) Start waiting for trigger")
+        scope.aquire_single()
+        smu.start_measure()
+
+        scope.wait_aquire_finish()
+        smu.stop_measure_only()
+        print(f"({i}) Finish measurement")
+
+        in_execution = scope.get_waveform(2)
+        eps_on = scope.get_waveform(3)
+        x_increment = scope.get_xincrement()
+
+        d = {
+            "in_execution": in_execution,
+            "eps_on": eps_on,
+            "timestamp": [i * x_increment for i in range(len(in_execution))],
+        }
+        scope_results = pd.DataFrame(d)
+
+        print(f"Sampled {len(scope_results)} points from the scope")
+
+        currs = smu.fetch_curr()
+        volts = smu.fetch_volt()
+        timestamps = smu.fetch_time()
+
+        d = {
+            "curr": currs,
+            "volt": volts,
+            "timestamp": timestamps
+        }
+
+        smu_results = pd.DataFrame(d)
+        print(f"Sampled {len(smu_results)} point from the smu")
+
+        results.append({
+            "scope_result": scope_results,
+            "smu_result": smu_results,
+        })
+
+        i += 1
+        now = datetime.datetime.now()
+        time_elapsed = now - start
+        print(time_elapsed)
+        if time_elapsed > datetime.timedelta(seconds=interval):
+            if current_limit_index == len(current_limits)-1:
+                break
+            current_limit_index += 1
+            current_limit = current_limits[current_limit_index]
+            print(f"set current limit to {current_limit*1000:.3f}mA")
+            interval = get_sampling_duration(current_limit)
+            print(f"set sampling duration: {interval:.3f}s")
+            smu.set_current_limit(current_limit)
+            start = now
+        
+
+    save_records(f"result_{cap_size_uF}_uF", results)
+    smu.power_off()
+
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = False
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.loop_opt_debug = False
+    return config
+
+
+def save_records(bench_name, df):
+    with open(f"output/{bench_name}.pickle", "wb") as f:
+        pickle.dump(df, f)
+
+
+if __name__ == "__main__":
+    main()

+ 55 - 0
imc/exprs/dac2025/build_and_program.py

@@ -0,0 +1,55 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+import threading
+import datetime
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+from imc_utils.oscilloscope_dsox1204a import DSOX1204A
+
+import imc_utils.serial_device
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+def main():
+    volt = 3.3
+    smu = SMU_B2902A(voltage=volt)
+
+    benchmark = "vrefint_expr"
+
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = False
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.loop_opt_debug = False
+    config.bench_name = benchmark
+
+    smu.set_current_limit(0.1)
+    smu.power_on()
+
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=True)
+
+    smu.power_off()
+
+
+if __name__ == "__main__":
+    main()

+ 5 - 0
imc/exprs/dac2025/set_smu_current.py

@@ -0,0 +1,5 @@
+from imc_utils.smu_b2902a import SMU_B2902A
+
+smu = SMU_B2902A(voltage=1.5)
+smu.set_current_limit(0.020)
+smu.power_on()

File diff suppressed because it is too large
+ 8 - 11
imc/exprs/date2025/1_overhead_stable_power/draw_graph_expr_1.ipynb


+ 81 - 36
imc/exprs/date2025/1_overhead_stable_power/draw_graph_expr_1.py

@@ -2,81 +2,97 @@ import pickle
 import os
 import pandas as pd
 import seaborn as sns
+import matplotlib.ticker
 
 import plot_utils
 
+bench_order = ["fft", "basicmath", "crc", "sha", "stringsearch", "aes", "conv2d", "matmul"]
+
 def validate_and_cleanup_df(df):
-    rename_dict = {
-        "checkpoint_enabled": "ckpt",
-        "voltage_check_enabled": "VC",
-        "pass_counter_enabled": "PC"
-    }
-    df = df.rename(columns=rename_dict)
 
     assert(df["is_correct"].all())
 
-    def category_mapper(row):
-        if row["ckpt"] == False:
-            return "Baseline"
-        else:
-            if row["VC"] == False:
-                assert(row["PC"] == True)
-                return "PC"
-            else:
-                assert(row["PC"] == False)
-                return "VC"
+    df["bench_name"] = df["bench_name"].apply(lambda name: name.lower()[1:])
+
+    def process_stats(row):
+        lines = row["stats"]
+        result = {}
+        for line in lines:
+            key, val = line.split(":")
+            val = int(val.strip())
+            if key.startswith("checkpoint triggered"):
+                result["ckpt_trig"] = val
+            if key.startswith("checkpoint executed"):
+                result["ckpt_exec"] = val
+        return result
 
-    category_column_name = "config"
-    df[category_column_name] = df.apply(category_mapper, axis=1)
+    df_stats = df.apply(process_stats, axis=1, result_type="expand")
+    df = pd.concat([df, df_stats], axis=1)
 
     drop_columns = [
         "start",
         "end",
         "recovery",
         "outputs",
-        "ckpt",
-        "VC",
-        "PC",
-        "is_correct"
+        "is_correct",
+        "stats",
+        "debug_outputs"
     ]
     df = df.drop(columns = drop_columns) 
     return df
 
 
 def draw_graph():
-    benchmarks = ["vBasicMath", "vCrc", "vFFT", "vSha"]
     benchmarks = [ "vBasicMath", "vCrc", "vFFT", "vSha", "vStringSearch", "vMatMul", "vConv2d", "vAes"]
+    # benchmarks = ["vBasicMath", "vCrc", "vFFT", "vSha", "vStringSearch"]
     output_dir = "/home/ybkim/workspace/imc/imc_freertos_app_m33/imc/exprs/date2025/1_overhead_stable_power/output"
+    configs = ["original", "pass_count", "unroll", "adaptive"]
 
     all_dfs = []
 
     for benchmark in benchmarks:
-        pickle_filename = f"{output_dir}/{benchmark}.pickle"
-        if not os.path.exists(pickle_filename):
-            continue
-        with open(pickle_filename, "rb") as f:
-            orig_df = pickle.load(f)
-            df = validate_and_cleanup_df(orig_df)
-            all_dfs.append(df)
+        for config_name in configs:
+            pickle_filename = f"{output_dir}/{benchmark}.{config_name}.pickle"
+            if not os.path.exists(pickle_filename):
+                continue
+            with open(pickle_filename, "rb") as f:
+                orig_df = pickle.load(f)
+                df = validate_and_cleanup_df(orig_df)
+                all_dfs.append(df)
 
     orig_df = pd.concat(all_dfs)
+
+    mask = (orig_df["bench_name"] == "sha") & (orig_df["config"] == "adaptive")
+    print(orig_df[mask])
+
+    mask = (orig_df["bench_name"] == "sha") & (orig_df["config"] == "unroll")
+    print(orig_df[mask])
+
     df = orig_df.groupby(["bench_name", "config"]).mean()
     df = df.reset_index()
 
     df = df.pivot(index="bench_name", columns="config", values="time_taken")
 
+    include_adaptive = True
+
     df2 = pd.DataFrame()
-    df2["PC"] = df["PC"] / df["Baseline"]
-    df2["VC"] = df["VC"] / df["Baseline"]
+    df2["counter"] = df["pass_count"] / df["original"]
+    df2["unroll"] = df["unroll"] / df["original"]
+
+    if include_adaptive:
+        df2["adaptive"] = df["adaptive"] / df["original"]
+        n_cols = 3
+        config_order = ["counter", "unroll", "adaptive"]  
+    else:
+        n_cols = 1
+        config_order = ["counter", "unroll"]
 
     df2 = df2.reset_index().melt(id_vars=["bench_name"], var_name="config", value_name="normalized")
     df2 = df2.sort_values(by="bench_name")
-    df2 = df2[df2["config"] == "PC"]
+    # df2 = df2[df2["config"] == "PC"]
     # df2 = df2[df2["config"] == "VC"]
     # df2 = df2[df2["bench_name"] == "vFFT"]
 
-    print(df2)
-
     plot_utils.set_theme_seaborn()
     g = sns.catplot(
         data=df2,
@@ -84,7 +100,36 @@ def draw_graph():
         x="bench_name",
         y = "normalized",
         hue="config",
-        aspect=2.3
+        aspect=3.0,
+        height=4,
+        order=bench_order,
+        hue_order=config_order,
+        legend_out=False
     )
 
+    ax = g.ax
+    ax.set_ylim([0, 10])
+    ax.set_xlabel("Benchmark")
+    ax.set_ylabel("Exec Time (Normalized)")
+    ax.set_ylabel("Normalized")
+    ax.yaxis.set_major_locator(matplotlib.ticker.MaxNLocator(5))
+    ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(2))
+    ax.grid(True, which="both", axis="y")
+    sns.despine(g.figure, right=False, top=False)
+
+    for c in ax.containers:
+        labels = [f"{(v.get_height()):.1f}" if v.get_height() > 10 else "" for v in c]
+        padding = 90
+        ax.bar_label(c, labels=labels, label_type="center", padding=padding, size=16)
+
+    num_categories = len(df2.bench_name.unique())
+    num_hues = len(df2.config.unique())
+    plot_utils.draw_hatch(ax, num_categories, num_hues)
+
+    if include_adaptive:
+        ax.legend(ncol=n_cols, loc="upper center", bbox_to_anchor=(0.5, 1.4))
+    else:
+        ax.legend(ncol=n_cols, loc="upper left")
+
+
     return g

+ 63 - 32
imc/exprs/date2025/1_overhead_stable_power/run_expr_1.py

@@ -4,6 +4,7 @@ import pickle
 import pandas as pd
 
 from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
 from imc_utils.build_config.cortex_m33 import BuildConfigM33
 from imc_utils.build_config.test_env import TestEnv
 from imc_utils.serial_watch import SerialWatcher
@@ -15,36 +16,61 @@ WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
 NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
 OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
 
+def get_config(benchmark, config_name):
+    config = get_default_build_config()
+    bench_repeat_count = config.bench_repeat_count_small[benchmark]
+    config.bench_repeat_count = bench_repeat_count
+
+    if config_name == "original":
+        config.insert_compiler_checkpoints = False
+
+    if config_name == "pass_count":
+        config.use_checkpoint_pass_counter = True
+        config.checkpoint_pass_count = 100000000
+
+    if config_name == "unroll":
+        config.custom_unroll = True
+        config.use_checkpoint_voltage_check = True
+    
+    if config_name == "adaptive":
+        config.split_loop = True
+        config.enable_adaptive_loop_pass_count = True
+        config.use_checkpoint_voltage_check = True
+        config.max_loop_ids = 20
+        config.loop_opt_debug = False
+
+    return config
+
+
 def main():
     pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=3.3)
+    use_smu = True
     config = get_default_build_config()
 
     benchmarks = [ "vBasicMath", "vCrc", "vFFT", "vSha", "vStringSearch", "vMatMul", "vConv2d", "vAes"]
-    benchmarks = ["vMatMul", "vStringSearch"]
+    benchmarks = ["vCrc"]
 
-    # (insert_compiler_checkpoints, voltage_check, enable_pass_counter)
-    measure_configs = [
-        (False, False, False),
-        # (True, True, False),
-        (True, False, True)
-    ]
+    configs = ["original", "pass_count", "unroll", "adaptive"]
+    configs = ["adaptive"]
+    total_iterations = 10
+    # configs = ["unroll"]
+    # total_iterations = 1
 
     for benchmark in benchmarks:
-        all_records = []
-        for measure_config in measure_configs:
-            insert_compiler_checkpoints = measure_config[0]
-            use_checkpoint_voltage_check = measure_config[1]
-            use_checkpoint_pass_counter = measure_config[2]
+        for measure_config in configs:
+            all_records = []
 
+            config = get_config(benchmark, measure_config)
             config.bench_name = benchmark
-            config.insert_compiler_checkpoints = insert_compiler_checkpoints
-            config.use_checkpoint_voltage_check = use_checkpoint_voltage_check
-            config.use_checkpoint_pass_counter = use_checkpoint_pass_counter
-            config.checkpoint_pass_count = 1000000
 
-            pps.set_voltage(3.3, 1)
-            pps.set_current(0.1, 1)
-            pps.output_on(1)
+            if use_smu:
+                smu.set_current_limit(0.1)
+                smu.power_on()
+            else:
+                pps.set_voltage(3.3, 1)
+                pps.set_current(0.1, 1)
+                pps.output_on(1)
 
             env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
 
@@ -52,20 +78,23 @@ def main():
                 binary = env.build_binary(config, build_dir)
                 env.clear_nvm_and_load_binary(binary, resume=True)
 
-            total_iterations = 10
-            watcher = SerialWatcher(benchmark, total_iterations)
+            iterations = total_iterations if measure_config == "adaptive" else 1
+            watcher = SerialWatcher(benchmark, iterations)
             records = watcher.run()
             for record in records:
                 record.update({
-                    "checkpoint_enabled": insert_compiler_checkpoints,
-                    "voltage_check_enabled": use_checkpoint_voltage_check,
-                    "pass_counter_enabled": use_checkpoint_pass_counter
+                    "config": measure_config,
                 })
                 all_records.append(record)
-        df = pd.DataFrame(all_records)
-        print(df)
-        save_records(benchmark, df)
-    pps.output_off(1)
+
+            df = pd.DataFrame(all_records)
+            print(df)
+            save_records(benchmark, measure_config, df)
+
+    if use_smu:
+        smu.power_off()
+    else:
+        pps.output_off(1)
 
 
 def get_default_build_config():
@@ -74,14 +103,16 @@ def get_default_build_config():
     config.insert_compiler_checkpoints = True
     config.enable_extension = True
     config.use_checkpoint_pass_counter = False
-    config.use_checkpoint_voltage_check = True
+    config.use_checkpoint_voltage_check = False
     config.bench_infinite_loop = True
+    config.print_recovery_message = False
+    config.split_loop = False
+    config.print_stats = True
     return config
 
-def save_records(bench_name, df):
-    with open(f"output/{bench_name}.pickle", "wb") as f:
+def save_records(bench_name, config_name, df):
+    with open(f"output/{bench_name}.{config_name}.pickle", "wb") as f:
         pickle.dump(df, f)
 
-
 if __name__ == "__main__":
     main()

+ 52 - 0
imc/exprs/date2025/3_adaptive/debug_output.py

@@ -0,0 +1,52 @@
+import pickle
+
+df_loc = "output/adaptive/vConv2d.pickle"
+with open(df_loc, "rb") as f:
+    df = pickle.load(f)
+
+debug_outputs = df["debug_outputs"]
+message_by_loop = {}
+
+for i, output in enumerate(debug_outputs):
+    for line in output:
+        try:
+            if line.startswith("Start recovery"):
+                log = (i, "R")
+                for loop_id in message_by_loop.keys():
+                    message_by_loop[loop_id].append(log)
+                continue
+            loop_index_string = "estimation for loop"
+            loc = line.find(loop_index_string)
+            assert(loc > -1)
+            loop_index = loc + len(loop_index_string) + 1
+            loop_id = line[loop_index:].split()[0]
+
+            update_string = "is updated to"
+            loc = line.find(update_string)
+            assert(loc > -1)
+            val_index = loc + len(update_string) + 1
+            updated_val = line[val_index:].split()[0]
+
+            if line.startswith("(recovery)"):
+                updated_val = "!" + updated_val
+
+            if loop_id not in message_by_loop:
+                message_by_loop[loop_id] = []
+            
+            log = (i, updated_val)
+            message_by_loop[loop_id].append(log)
+
+        except:
+            print("incomplete string:", line)
+
+for key in sorted(message_by_loop.keys()):
+    # print(key, message_by_loop[key])
+    outputs = []
+    current_iter = -1
+    for log in message_by_loop[key]:
+        i, val = log
+        while current_iter < i:
+            current_iter += 1
+            outputs.append(f"({current_iter})")
+        outputs.append(val)
+    print(f"{key}:", "  ".join(outputs))

File diff suppressed because it is too large
+ 72 - 4
imc/exprs/date2025/3_adaptive/draw_graph_expr_3.ipynb


+ 121 - 45
imc/exprs/date2025/3_adaptive/draw_graph_expr_3.py

@@ -12,15 +12,30 @@ import plot_utils
 config_order = ["counter", "unroll", "adaptive"]  
 bench_order = ["fft", "basicmath", "crc", "sha", "stringsearch", "aes", "conv2d", "matmul"]
 
+def get_df_after_converged(df):
+    # converged = df.groupby("bench_name", as_index=False).apply(lambda d: d.iloc[10:])
+    # return converged
+
+    def filter_unconverged(df):
+        config = df["config"].unique()[0]
+        if config != "adaptive":
+            return df
+        d = df.iloc[10:]
+        return d
+    
+    d = df.groupby(["bench_name", "config"], as_index=False).apply(filter_unconverged)
+    return d
+
 def validate_and_cleanup_df(df, config_name):
 
-    # mask = df["is_correct"] == False
-    # if mask.any():
-    #     print(f"({config_name}) drop {mask.sum()} rows with incorrect output")
-    # df = df[~mask]
-    # assert(df["is_correct"].all())
-    
     bench_name = df.iloc[0,0]
+
+    mask = df["is_correct"] == False
+    if mask.any():
+        print(f"({bench_name}, {config_name}) drop {mask.sum()} rows with incorrect output")
+    df = df[~mask]
+    assert(df["is_correct"].all())
+    
     z_score = stats.zscore(df["time_taken"])
     mask2 = np.abs(z_score) > 4.35
     if mask2.any():
@@ -46,6 +61,8 @@ def validate_and_cleanup_df(df, config_name):
                 result["ckpt_trig"] = val
             if key.startswith("checkpoint executed"):
                 result["ckpt_exec"] = val
+            if key.startswith("no forward progress"):
+                result["no_forward_progress"] = val
         return result
 
     df_stats = df.apply(process_stats, axis=1, result_type="expand")
@@ -60,7 +77,8 @@ def validate_and_cleanup_df(df, config_name):
         # "ckpt",
         # "VC",
         # "PC",
-        "is_correct"
+        "is_correct",
+        # "debug_outputs"
     ]
     df = df.drop(columns = drop_columns) 
     return df
@@ -81,7 +99,7 @@ def get_base_df():
 
     all_dfs = []
     configs = ["pass_count", "adaptive", "unroll"]
-    drop_index = list(range(0, 1))
+    drop_index = list(range(0, 10))
     drop_index = None
 
     for benchmark in benchmarks:
@@ -137,15 +155,8 @@ def draw_checkpoint_count():
     plot_utils.set_theme_seaborn(kind="line", rc_custom=rc)
 
     orig_df = get_base_df()
-    # mask = orig_df["ckpt_trig"].abs() > 1e7 
-    # df = orig_df[~mask]
-    # mask = orig_df["ckpt_exec"].abs() > 1e6
-    # df = orig_df[~mask]
-    # mask = orig_df["ckpt_trig"] < 0
-    # df = orig_df[~mask]
-    # mask = orig_df["ckpt_exec"] < 0
-    # df = orig_df[~mask]
-    df = remove_error_stats(orig_df)
+    # df = remove_error_stats(orig_df)
+    df = orig_df
 
     benchmarks = bench_order
     fig_size = (13, 5.5)
@@ -162,13 +173,11 @@ def draw_checkpoint_count():
     df = df.drop(columns=["config", "time_taken"])
     for i, benchmark in enumerate(benchmarks):
         d = df[df["bench_name"] == benchmark].reset_index()
-        print(d)
 
         id_vars = ["index", "bench_name"]
         value_vars = ["trig", "exec"]
         d = d.melt(id_vars=id_vars, value_vars=value_vars, value_name="count", var_name="type")
         # d = d.reset_index().melt(id_vars=["bench_name"], var_name="config", value_name="normalized")
-        print(d)
 
         ax = axes.reshape(-1)[i]
         sns.lineplot(
@@ -185,9 +194,9 @@ def draw_checkpoint_count():
             ax.set_xlabel("Execution #")
         if i in [0, 4]:
             ax.set_ylabel("Count (k)")
-        ax.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: f"{x/1000:.0f}"))
+        ax.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: f"{x/1000:.1f}"))
         ax.yaxis.grid(visible=True, which="both")
-        ax.yaxis.set_major_locator(matplotlib.ticker.MaxNLocator(3))
+        # ax.yaxis.set_major_locator(matplotlib.ticker.MaxNLocator(3))
         ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(3))
 
         ax.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(2))
@@ -209,7 +218,7 @@ def draw_graph():
     orig_df = get_base_df()
     # df = orig_df.groupby(["bench_name", "config"]).mean()
     df = orig_df.reset_index()
-
+    df = get_df_after_converged(df)
 
     err_kws = {
         "linewidth": 1.2,
@@ -220,6 +229,25 @@ def draw_graph():
         "legend.fontsize": 24,
     }
 
+    print("average improvement")
+    mean_df = df.groupby(["config", "bench_name"])["time_taken"].mean()
+    adaptive_times = mean_df.loc["adaptive"]
+
+    def add_improvement(s):
+        s = s.reset_index(level="config", drop=True)
+        return s / adaptive_times
+
+    # for key, d in mean_df.groupby("config", level="config"):
+    #     print(key)
+    #     print(d)
+    
+    d = mean_df.groupby("config", level="config").apply(add_improvement)
+    print(d.loc["counter"])
+    print(d.loc["unroll"])
+    d = d.groupby("config").mean()
+
+    print(mean_df)
+
     plot_utils.set_theme_seaborn(rc)
 
     g = sns.catplot(
@@ -230,12 +258,13 @@ def draw_graph():
         hue="config",
         legend="brief",
         legend_out=False,
-        aspect=2.5,
+        aspect=2.7,
         errorbar=lambda x: (x.min(), x.max()),
         hue_order=config_order,
         order=bench_order,
         err_kws=err_kws,
         capsize=0.2,
+        height=4.5,
     )
     ax = g.ax
     ax.set_ylim([0, 35])
@@ -247,33 +276,41 @@ def draw_graph():
 
     for i, c in enumerate(ax.containers):
         labels = [f"{(v.get_height()):.0f}" if v.get_height() > 50 else "" for v in c]
-        padding = 125
+        padding = 107
         ax.bar_label(c, labels=labels, label_type="center", padding=padding, size=16)
 
     num_categories = len(df.bench_name.unique())
     num_hues = len(df.config.unique())
     plot_utils.draw_hatch(ax, num_categories, num_hues)
-    
-    ax.legend(ncol=1, loc="upper right", bbox_to_anchor=(0.265, 0.995), labelspacing=0.3)
 
-    sns.despine(g.fig, right=False, top=False)
+    ax.legend(ncol=1, loc="upper right", bbox_to_anchor=(0.29, 0.995), labelspacing=0.3)
+    for t in ax.get_legend().get_texts():
+        if t.get_text() == "adaptive":
+            t.set_text("FastTrack")
+
+    sns.despine(g.figure, right=False, top=False)
 
     return g
 
 def draw_checkpoint_frequency_comparison():
     orig_df = get_base_df()
     df = remove_error_stats(orig_df)
-    df = df.drop(columns=["time_taken"])
+    df = df.drop(columns=["time_taken", "debug_outputs"])
     df = df.groupby(["bench_name", "config"]).mean()
     df = df.reset_index()
 
-    print(df)
-    base_df = df
+    base_df = orig_df
+    base_df = get_df_after_converged(base_df)
+
     adaptive_df = base_df[base_df["config"] == "adaptive"]
-    adaptive_df = adaptive_df.set_index("bench_name")
+    # adaptive_df = get_df_after_converged(adaptive_df)
+    adaptive_df = adaptive_df.drop(columns=["time_taken", "debug_outputs", "config"])
+    adaptive_df = adaptive_df.groupby("bench_name").mean()
+    print(adaptive_df)
 
     rc = {
         "legend.fontsize": 24,
+        "ytick.labelsize": 18,
     }
     plot_utils.set_theme_seaborn(rc)
 
@@ -287,7 +324,7 @@ def draw_checkpoint_frequency_comparison():
 
     configs = ["counter", "unroll"]
     for i, config in enumerate(configs):
-        d = base_df[base_df["config"] == config]
+        d = df[df["config"] == config]
         d = d.set_index("bench_name")
 
         df2 = pd.DataFrame()
@@ -296,7 +333,6 @@ def draw_checkpoint_frequency_comparison():
         df2 = df2.reset_index()
         df2 = df2.melt(id_vars=["bench_name"], value_vars=["trig", "exec"], var_name="type", value_name="normalized")
 
-        print(axes)
         ax = axes[i]
 
         g = sns.barplot(
@@ -308,21 +344,26 @@ def draw_checkpoint_frequency_comparison():
             order=bench_order,
             ax = ax,
         )
+        g.set_yscale("log")
         ax.set_title(f"vs. {config}", fontsize=22)
-        ax.set_ylim([0, 0.8])
+        g.tick_params("y", left=True, which="minor", width=0.5, direction="in", color="gray")
+        g.tick_params("y", which="major", labelsize=20)
+        # ylim = 1
+        # ax.set_ylim([0, ylim])
         ax.set_xlabel("Benchmark")
         ax.set_ylabel("Ratio")
-        # ax.yaxis.set_major_locator(matplotlib.ticker.MaxNLocator(6))
-        ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(5))
-        ax.yaxis.grid(visible=True, which="both")
-
-        for c in ax.containers:
-            labels = [f"{(v.get_height()):.2f}" if v.get_height() > 0.8 else "" for v in c]
-            padding = 80
-            ax.bar_label(c, labels=labels, label_type="center", padding=padding, size=16)
-
-        num_categories = len(df.bench_name.unique())
-        num_hues = len(df.config.unique())
+        ax.yaxis.set_major_locator(matplotlib.ticker.LogLocator(base=10, numticks=6))
+        subs = [0.2, 0.4, 0.6, 0.8]
+        ax.yaxis.set_minor_locator(matplotlib.ticker.LogLocator(base=10, numticks=6, subs=subs))
+        ax.yaxis.grid(visible=True, which="major")
+
+        # for c in ax.containers:
+        #     labels = [f"{(v.get_height()):.2f}" if v.get_height() > ylim else "" for v in c]
+        #     padding = 80
+        #     ax.bar_label(c, labels=labels, label_type="center", padding=padding, size=16)
+
+        num_categories = len(df2.bench_name.unique())
+        num_hues = len(df2.type.unique())
         plot_utils.draw_hatch(ax, num_categories, num_hues)
 
         if i == 0:
@@ -334,3 +375,38 @@ def draw_checkpoint_frequency_comparison():
         sns.despine(fig, right=False, top=False)
 
     return fig
+
+
+def print_summary():
+    orig_df = get_base_df()
+    df = remove_error_stats(orig_df)
+    df = df.drop(columns=["time_taken", "debug_outputs"])
+    df = df.groupby(["bench_name", "config"]).mean()
+    df = df.reset_index()
+
+    base_df = orig_df
+    base_df = get_df_after_converged(base_df)
+    base_df = base_df.drop(columns=["time_taken", "debug_outputs", "no_forward_progress"])
+
+    dfs = []
+    for config in ["counter", "unroll", "adaptive"]:
+        d = base_df[base_df["config"] == config]
+        d = d.drop(columns=["config"])
+        d = d.groupby("bench_name").mean()
+        dfs.append(d)
+    
+    counter_df, unroll_df, adaptive_df = dfs
+
+    removed_vs_counter = 1 - adaptive_df / counter_df
+    removed_vs_unroll = 1 - adaptive_df / unroll_df
+    print("remove vs counter:")
+    print(removed_vs_counter)
+    print("mean:")
+    print(removed_vs_counter.mean())
+    print()
+
+    print("remove vs unroll:")
+    print(removed_vs_unroll)
+    print("mean:")
+    print(removed_vs_unroll.mean())
+    print()

+ 37 - 13
imc/exprs/date2025/3_adaptive/run_expr_3.py

@@ -4,6 +4,7 @@ import pickle
 import pandas as pd
 
 from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
 from imc_utils.build_config.cortex_m33 import BuildConfigM33
 from imc_utils.build_config.test_env import TestEnv
 from imc_utils.serial_watch import SerialWatcher
@@ -12,6 +13,8 @@ WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
 NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
 OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
 
+use_smu = False
+
 def get_build_config(benchmark, config_name):
     config = get_default_build_config()
     config.bench_name = benchmark
@@ -20,15 +23,17 @@ def get_build_config(benchmark, config_name):
 
     if config_name == "pass_count":
         config.use_checkpoint_pass_counter = True
-        config.checkpoint_pass_count = config.pass_count_10ms[benchmark]
+        # config.checkpoint_pass_count = config.pass_count_10ms[benchmark]
+        # config.checkpoint_pass_count = config.pass_count_400ms[benchmark]
+        # config.checkpoint_pass_count = config.pass_count_167ms[benchmark]
+        config.checkpoint_pass_count = config.pass_count_154ms[benchmark]
     
     if config_name == "adaptive":
         config.use_checkpoint_voltage_check = True
         config.split_loop = True
         config.enable_adaptive_loop_pass_count = True
-        # config.enable_static_loop_pass_count = True
-        # config.loop_pass_count = 50
-        config.max_loop_ids = 30
+        config.max_loop_ids = 15
+        config.loop_opt_debug = False
     
     if config_name == "unroll":
         config.use_checkpoint_voltage_check = True
@@ -38,6 +43,9 @@ def get_build_config(benchmark, config_name):
 
 def main():
     pps = PPS_E36311A()
+    if use_smu:
+        volt = 3.3
+        smu = SMU_B2902A(voltage=3.3)
     config = get_default_build_config()
 
     benchmarks = [
@@ -50,23 +58,31 @@ def main():
         "vConv2d",
         "vAes",
     ]
-    # benchmarks = [
-    #     "vAes"
-    # ]
+    benchmarks = [
+        # "vCrc",
+        # "vSha",
+        "vBasicMath",
+        # "vMatMul"
+    ]
 
     configs = ["pass_count", "adaptive", "unroll"]
-    # configs = ["adaptive", "unroll"]
+    # configs = ["adaptive"]
 
     total_iterations = 20
+    target_current_limit = 0.015
 
     for benchmark in benchmarks:
         for config_name in  configs:
             all_records = []
             config = get_build_config(benchmark, config_name)
 
-            pps.set_voltage(3.3, 1)
-            pps.set_current(0.1, 1)
-            pps.output_on(1)
+            if use_smu:
+                smu.set_current_limit(0.1)
+                smu.power_on()
+            else:
+                pps.set_voltage(3.3, 1)
+                pps.set_current(0.1, 1)
+                pps.output_on(1)
 
             env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
 
@@ -74,7 +90,11 @@ def main():
                 binary = env.build_binary(config, build_dir)
                 env.clear_nvm_and_load_binary(binary, resume=False)
 
-            pps.set_current(0.015, 1)
+            if use_smu:
+                smu.set_current_limit(target_current_limit)
+            else:
+                pps.set_current(target_current_limit, 1)
+
             time.sleep(1)
 
             env.resume_board(terminate=True)
@@ -94,7 +114,10 @@ def main():
             print(df[columns])
             save_records(benchmark, config_name, df)
 
-    pps.output_off(1)
+    if use_smu:
+        smu.power_off()
+    else:
+        pps.output_off(1)
 
 
 def get_default_build_config():
@@ -110,6 +133,7 @@ def get_default_build_config():
     config.enable_adaptive_loop_pass_count = False
     config.print_stats = True
     config.custom_unroll = False
+    config.loop_opt_debug = False
     return config
 
 

+ 106 - 0
imc/exprs/date2025/4_decide_pass_count/measure_current.py

@@ -0,0 +1,106 @@
+import tempfile
+import time
+import pandas as pd
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+def get_exec_time(curr):
+    capacitance_F = 0.0047
+    # capacitance_F = 0.01
+    volt_high = 4.8
+    volt_low = 3.7
+    energy_j = 0.5 * capacitance_F * (volt_high**2 - volt_low**2)
+    volt_mcu = 3.3
+    avg_time = energy_j / volt_mcu / curr
+    print(f"estimated running time (curr): {avg_time}")
+
+
+def main():
+
+    max_curr = 0.0214817
+    get_exec_time(max_curr)
+    return
+
+    benchmarks = [
+        "vBasicMath",
+        "vCrc",
+        "vFFT",
+        "vSha",
+        "vStringSearch",
+        "vMatMul",
+        "vConv2d",
+        "vAes",
+    ]
+    # benchmarks = ["vBasicMath"]
+    measure_time = 5
+
+    volt = 0
+    curr = 0.1
+    smu = SMU_B2902A(voltage=volt, curr_limit=curr, use_external_power=True)
+    smu.power_on()
+
+    pps = PPS_E36311A()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(curr, 1)
+    pps.output_on(1)
+
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+    config = get_default_build_config()
+
+    for benchmark in benchmarks:
+        config.bench_name = benchmark
+        smu.power_on()
+        with tempfile.TemporaryDirectory() as build_dir:
+            binary = env.build_binary(config, build_dir)
+            env.clear_nvm_and_load_binary(binary, resume=True)
+
+        smu.start_measure()
+        time.sleep(measure_time)
+        currs = smu.stop_measure()
+        df = pd.DataFrame(currs)
+        # print(df)
+        avg_curr = float(df.mean().iloc[0])
+        print(avg_curr)
+
+        max_curr = float(df.max().iloc[0])
+        print(max_curr)
+
+        capacitance_F = 0.047
+        volt_high = 4.8
+        volt_low = 3.6
+        energy_j = 0.5 * capacitance_F * (volt_high**2 - volt_low**2)
+        volt_mcu = 3.3
+        avg_time = energy_j / volt_mcu / avg_curr
+        print(f"estimated running time (avg curr): {avg_time}")
+        max_time = energy_j / volt_mcu / max_curr
+        print(f"estimated running time (max curr): {max_time}")
+
+    smu.power_off()
+    pps.output_off(1)
+
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = False
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    return config
+
+if __name__ == "__main__":
+    main()

+ 5 - 2
imc/exprs/date2025/4_decide_pass_count/run_expr_4.py

@@ -27,9 +27,12 @@ def main():
         "vConv2d",
         "vAes",
     ]
-    # benchmarks = ["vSha"]
+    # benchmarks = ["vCrc"]
 
     target_period_ms = 10
+    target_period_ms = 400 # for 10mF
+    target_period_ms = 334/2 # for 4.7mF
+    target_period_ms = 309/2
 
     output_dict = {}
 
@@ -62,7 +65,7 @@ def main():
             if stat.startswith("checkpoint triggered"):
                 checkpoint_triggered = int(stat.split(":")[1].strip())
                 break
-        
+
         trigger_period = time_taken / checkpoint_triggered * 1000
         pass_count = target_period_ms / trigger_period
 

+ 66 - 11
imc/exprs/date2025/5_size_overhead/draw_graph_expr_5.py

@@ -67,6 +67,20 @@ def validate_and_cleanup_df(df):
     return df
 
 
+def get_num_cloned_loops(benchmark):
+    d = {
+        "vBasicMath": 5,
+        "vCrc": 4,
+        "vFFT": 9,
+        "vSha": 6,
+        "vStringSearch": 6,
+        "vMatMul": 4,
+        "vConv2d": 5,
+        "vAes": 15,
+    }
+    return d[benchmark]
+
+
 def get_base_df():
     benchmarks = [
         "vBasicMath",
@@ -78,9 +92,9 @@ def get_base_df():
         "vConv2d",
         "vAes",
     ]
-    benchmarks = [
-        "vStringSearch"
-    ]
+    # benchmarks = [
+    #     "vStringSearch"
+    # ]
     output_dir = "/home/ybkim/workspace/imc/imc_freertos_app_m33/imc/exprs/date2025/5_size_overhead/output"
 
     all_dfs = []
@@ -95,7 +109,7 @@ def get_base_df():
             mask = df["config"] == "original"
             base = int(df[mask]["text"].iloc[0])
             df["normalized_text"] = df["text"] / base
-            df = df[~mask]
+            # df = df[~mask]
             all_dfs.append(df)
 
     orig_df = pd.concat(all_dfs)
@@ -103,13 +117,54 @@ def get_base_df():
 
 
 def draw_graph():
-    orig_df = get_base_df()
-    mask = orig_df["config"] != "original"
-    df = orig_df[mask]
+    df = get_base_df()
+    print(df)
 
-    plot_utils.set_theme_seaborn()
-    g = sns.catplot(
-        data=df, kind="bar", x="benchmark", y="normalized_text", hue="config", aspect=2.3
+    rows = []
+
+    benchmarks = df["benchmark"].unique()
+    for benchmark in benchmarks:
+        bench_name = benchmark.lower()[1:]
+        print(bench_name)
+
+        n_cloned_loops = get_num_cloned_loops(benchmark)
+
+        mask = (df["benchmark"] == benchmark) & (df["config"] == "original")
+        func_size_original = int(df[mask]["func"])
+
+        mask = (df["benchmark"] == benchmark) & (df["config"] == "adaptive")
+        func_size_after = int(df[mask]["func"])
+
+        func_size_overhead = func_size_after / func_size_original
+        func_size_original = f"{func_size_original:,}"
+        func_size_after = f"{func_size_after:,}"
+
+        text_overhead = float(df[mask]["normalized_text"] * 100 - 100)
+
+        rows.append({
+            "benchmark": bench_name,
+            "cloned loops (N)": n_cloned_loops,
+            "function size (orig)": func_size_original,
+            "function size (after)": func_size_after,
+            "function size overhead": func_size_overhead,
+            "\\texttt{.text} increased (%)": text_overhead,
+        })
+
+    d = pd.DataFrame(rows)
+    print(d)
+    print("average function size overhead: ")
+    print(d["function size overhead"].mean())
+    print("average code size overhead: ")
+    print(d["\\texttt{.text} increased (%)"].mean())
+    d = d.drop(columns=["function size overhead"])
+    latex = d.to_latex(
+        index=False,
+        escape=True,
+        float_format="%.2f",
+        column_format="ccccc",
     )
+    print(latex)
+
 
-    return g
+if __name__ == "__main__":
+    draw_graph()

+ 55 - 8
imc/exprs/date2025/5_size_overhead/run_expr_5.py

@@ -71,10 +71,56 @@ def get_flash_size(binary):
                 if section == ".text":
                     text = size
     return total, text
-    
+
+
+def get_func_size(binary, bench_name):
+    function_names = {
+        "vBasicMath": ["vBasicMath"],
+        "vCrc": ["updateCRC32", "crc32file", "crc32buf", "vCrc"],
+        "vFFT": ["vFFT"],
+        "vSha": [
+            "sha_init",
+            "sha_update",
+            "byte_reverse",
+            "sha_transform",
+            "sha_final",
+            "sha_stream",
+            "sha_print",
+            "vSha",
+        ],
+        "vStringSearch": ["vStringSearch"],
+        "vMatMul": ["vMatMul"],
+        "vConv2d": ["vConv2d"],
+        "vAes": [
+            "AES_init_ctx_iv",
+            "KeyExpansion",
+            "AES_CBC_encrypt_buffer",
+            "XorWithIv",
+            "Cipher",
+            "vAes",
+            "AddRoundKey",
+            "SubBytes",
+            "ShiftRows",
+            "MixColumns",
+            "xtime",
+        ],
+    }
+    funcs = function_names[bench_name]
+    inst = f"nm -S -t d {binary}".split()
+    output = subprocess.run(inst, capture_output=True)
+    lines = output.stdout.decode().split("\n")
+    total_size = 0
+    for line in lines:
+        if len(line) == 0:
+            continue
+        tokens = line.strip().split()
+        if tokens[-1] in funcs:
+            size = int(tokens[1])
+            total_size += size
+    return total_size
+
 
 def main():
-    pps = PPS_E36311A()
     config = get_default_build_config()
 
     benchmarks = [
@@ -87,12 +133,12 @@ def main():
         "vConv2d",
         "vAes",
     ]
-    benchmarks = [
-        "vAes"
-    ]
+    # benchmarks = [
+    #     "vBasicMath"
+    # ]
 
     configs = ["original", "pass_count", "adaptive", "unroll"]
-    # configs = ["pass_count"]
+    configs = ["original", "adaptive"]
 
     for benchmark in benchmarks:
         all_records = []
@@ -104,13 +150,14 @@ def main():
             with tempfile.TemporaryDirectory() as build_dir:
                 binary = env.build_binary(config, build_dir)
                 size, text_size = get_flash_size(binary)
-                # size = os.path.getsize(binary)
+                func_size = get_func_size(binary, benchmark)
             
             record = {
                 "benchmark": benchmark,
                 "config": config_name,
                 "flash": size,
-                "text": text_size
+                "text": text_size,
+                "func": func_size,
             }
 
             all_records.append(record)

+ 807 - 0
imc/exprs/date2025/6_varying_power/data/2015-04-22-Sacramento.csv

@@ -0,0 +1,807 @@
+DATE (MM/DD/YYYY),PST,Global Horizontal [W/m^2]
+4/22/2015,05:22,3.50689
+4/22/2015,05:23,2.16921
+4/22/2015,05:24,0.964964
+4/22/2015,05:25,1.32731
+4/22/2015,05:26,1.66946
+4/22/2015,05:27,2.01772
+4/22/2015,05:28,2.56262
+4/22/2015,05:29,3.02515
+4/22/2015,05:30,3.70780
+4/22/2015,05:31,4.27395
+4/22/2015,05:32,4.74900
+4/22/2015,05:33,5.12673
+4/22/2015,05:34,5.47350
+4/22/2015,05:35,5.71969
+4/22/2015,05:36,6.25664
+4/22/2015,05:37,6.74344
+4/22/2015,05:38,7.24453
+4/22/2015,05:39,7.36830
+4/22/2015,05:40,7.57006
+4/22/2015,05:41,7.82318
+4/22/2015,05:42,8.39448
+4/22/2015,05:43,8.38940
+4/22/2015,05:44,9.24232
+4/22/2015,05:45,10.0136
+4/22/2015,05:46,10.7401
+4/22/2015,05:47,11.9213
+4/22/2015,05:48,13.3298
+4/22/2015,05:49,14.3096
+4/22/2015,05:50,15.3616
+4/22/2015,05:51,16.6400
+4/22/2015,05:52,18.1455
+4/22/2015,05:53,19.1448
+4/22/2015,05:54,19.8700
+4/22/2015,05:55,20.9772
+4/22/2015,05:56,23.0442
+4/22/2015,05:57,24.2597
+4/22/2015,05:58,24.1261
+4/22/2015,05:59,23.9046
+4/22/2015,06:00,24.1909
+4/22/2015,06:01,24.7340
+4/22/2015,06:02,24.7973
+4/22/2015,06:03,23.1232
+4/22/2015,06:04,23.2614
+4/22/2015,06:05,25.1121
+4/22/2015,06:06,26.1913
+4/22/2015,06:07,25.5927
+4/22/2015,06:08,25.5988
+4/22/2015,06:09,26.0232
+4/22/2015,06:10,27.3014
+4/22/2015,06:11,27.6288
+4/22/2015,06:12,27.1796
+4/22/2015,06:13,27.3186
+4/22/2015,06:14,28.7403
+4/22/2015,06:15,31.5260
+4/22/2015,06:16,35.9410
+4/22/2015,06:17,38.1552
+4/22/2015,06:18,38.4896
+4/22/2015,06:19,39.4527
+4/22/2015,06:20,42.8651
+4/22/2015,06:21,45.7270
+4/22/2015,06:22,48.1836
+4/22/2015,06:23,50.6054
+4/22/2015,06:24,50.2274
+4/22/2015,06:25,50.3669
+4/22/2015,06:26,51.6997
+4/22/2015,06:27,53.8528
+4/22/2015,06:28,56.0429
+4/22/2015,06:29,56.1645
+4/22/2015,06:30,55.3842
+4/22/2015,06:31,55.9115
+4/22/2015,06:32,57.7475
+4/22/2015,06:33,58.8233
+4/22/2015,06:34,59.6694
+4/22/2015,06:35,62.2765
+4/22/2015,06:36,65.7830
+4/22/2015,06:37,67.3248
+4/22/2015,06:38,67.7279
+4/22/2015,06:39,68.9899
+4/22/2015,06:40,69.6010
+4/22/2015,06:41,70.2058
+4/22/2015,06:42,71.4089
+4/22/2015,06:43,73.1903
+4/22/2015,06:44,74.0346
+4/22/2015,06:45,74.9545
+4/22/2015,06:46,78.4685
+4/22/2015,06:47,82.0123
+4/22/2015,06:48,86.9787
+4/22/2015,06:49,92.9925
+4/22/2015,06:50,99.7900
+4/22/2015,06:51,101.194
+4/22/2015,06:52,98.6200
+4/22/2015,06:53,101.735
+4/22/2015,06:54,109.985
+4/22/2015,06:55,112.429
+4/22/2015,06:56,114.350
+4/22/2015,06:57,121.422
+4/22/2015,06:58,123.184
+4/22/2015,06:59,120.834
+4/22/2015,07:00,121.066
+4/22/2015,07:01,124.293
+4/22/2015,07:02,127.209
+4/22/2015,07:03,130.908
+4/22/2015,07:04,133.232
+4/22/2015,07:05,128.163
+4/22/2015,07:06,136.187
+4/22/2015,07:07,144.243
+4/22/2015,07:08,148.610
+4/22/2015,07:09,157.555
+4/22/2015,07:10,150.662
+4/22/2015,07:11,151.150
+4/22/2015,07:12,156.563
+4/22/2015,07:13,156.414
+4/22/2015,07:14,144.205
+4/22/2015,07:15,151.985
+4/22/2015,07:16,163.071
+4/22/2015,07:17,157.034
+4/22/2015,07:18,151.747
+4/22/2015,07:19,150.335
+4/22/2015,07:20,143.989
+4/22/2015,07:21,141.056
+4/22/2015,07:22,145.895
+4/22/2015,07:23,158.602
+4/22/2015,07:24,158.597
+4/22/2015,07:25,151.688
+4/22/2015,07:26,153.394
+4/22/2015,07:27,145.156
+4/22/2015,07:28,143.375
+4/22/2015,07:29,142.861
+4/22/2015,07:30,139.981
+4/22/2015,07:31,141.915
+4/22/2015,07:32,138.361
+4/22/2015,07:33,136.627
+4/22/2015,07:34,132.593
+4/22/2015,07:35,141.239
+4/22/2015,07:36,144.878
+4/22/2015,07:37,139.323
+4/22/2015,07:38,148.511
+4/22/2015,07:39,152.625
+4/22/2015,07:40,154.220
+4/22/2015,07:41,158.918
+4/22/2015,07:42,152.221
+4/22/2015,07:43,150.934
+4/22/2015,07:44,155.877
+4/22/2015,07:45,163.143
+4/22/2015,07:46,157.543
+4/22/2015,07:47,164.358
+4/22/2015,07:48,182.667
+4/22/2015,07:49,185.907
+4/22/2015,07:50,184.278
+4/22/2015,07:51,201.188
+4/22/2015,07:52,192.457
+4/22/2015,07:53,201.232
+4/22/2015,07:54,209.874
+4/22/2015,07:55,214.672
+4/22/2015,07:56,224.487
+4/22/2015,07:57,215.622
+4/22/2015,07:58,213.370
+4/22/2015,07:59,215.808
+4/22/2015,08:00,222.479
+4/22/2015,08:01,215.052
+4/22/2015,08:02,212.718
+4/22/2015,08:03,216.370
+4/22/2015,08:04,231.715
+4/22/2015,08:05,250.720
+4/22/2015,08:06,260.104
+4/22/2015,08:07,263.090
+4/22/2015,08:08,259.458
+4/22/2015,08:09,268.514
+4/22/2015,08:10,268.033
+4/22/2015,08:11,268.765
+4/22/2015,08:12,272.57
+4/22/2015,08:13,276.263
+4/22/2015,08:14,287.025
+4/22/2015,08:15,311.282
+4/22/2015,08:16,294.208
+4/22/2015,08:17,287.821
+4/22/2015,08:18,311.475
+4/22/2015,08:19,324.207
+4/22/2015,08:20,322.659
+4/22/2015,08:21,309.987
+4/22/2015,08:22,294.272
+4/22/2015,08:23,276.791
+4/22/2015,08:24,275.079
+4/22/2015,08:25,291.298
+4/22/2015,08:26,344.342
+4/22/2015,08:27,349.296
+4/22/2015,08:28,324.462
+4/22/2015,08:29,328.615
+4/22/2015,08:30,303.673
+4/22/2015,08:31,304.036
+4/22/2015,08:32,356.345
+4/22/2015,08:33,476.510
+4/22/2015,08:34,299.252
+4/22/2015,08:35,289.728
+4/22/2015,08:36,379.315
+4/22/2015,08:37,684.817
+4/22/2015,08:38,640.315
+4/22/2015,08:39,429.879
+4/22/2015,08:40,278.786
+4/22/2015,08:41,363.950
+4/22/2015,08:42,468.690
+4/22/2015,08:43,387.132
+4/22/2015,08:44,391.099
+4/22/2015,08:45,544.872
+4/22/2015,08:46,535.711
+4/22/2015,08:47,551.936
+4/22/2015,08:48,421.893
+4/22/2015,08:49,496.208
+4/22/2015,08:50,576.886
+4/22/2015,08:51,662.164
+4/22/2015,08:52,685.994
+4/22/2015,08:53,591.485
+4/22/2015,08:54,692.766
+4/22/2015,08:55,768.423
+4/22/2015,08:56,476.839
+4/22/2015,08:57,557.644
+4/22/2015,08:58,617.752
+4/22/2015,08:59,660.793
+4/22/2015,09:00,609.798
+4/22/2015,09:01,681.262
+4/22/2015,09:02,587.030
+4/22/2015,09:03,589.276
+4/22/2015,09:04,517.884
+4/22/2015,09:05,325.976
+4/22/2015,09:06,663.072
+4/22/2015,09:07,683.444
+4/22/2015,09:08,462.255
+4/22/2015,09:09,484.224
+4/22/2015,09:10,365.835
+4/22/2015,09:11,287.999
+4/22/2015,09:12,263.312
+4/22/2015,09:13,285.559
+4/22/2015,09:14,479.483
+4/22/2015,09:15,746.543
+4/22/2015,09:16,740.472
+4/22/2015,09:17,715.418
+4/22/2015,09:18,605.750
+4/22/2015,09:19,636.125
+4/22/2015,09:20,550.535
+4/22/2015,09:21,633.587
+4/22/2015,09:22,523.448
+4/22/2015,09:23,451.373
+4/22/2015,09:24,567.196
+4/22/2015,09:25,800.095
+4/22/2015,09:26,816.421
+4/22/2015,09:27,636.783
+4/22/2015,09:28,515.226
+4/22/2015,09:29,365.132
+4/22/2015,09:30,366.202
+4/22/2015,09:31,348.262
+4/22/2015,09:32,313.340
+4/22/2015,09:33,336.979
+4/22/2015,09:34,516.102
+4/22/2015,09:35,806.636
+4/22/2015,09:36,768.208
+4/22/2015,09:37,451.179
+4/22/2015,09:38,366.278
+4/22/2015,09:39,395.447
+4/22/2015,09:40,320.990
+4/22/2015,09:41,701.676
+4/22/2015,09:42,758.063
+4/22/2015,09:43,700.125
+4/22/2015,09:44,706.548
+4/22/2015,09:45,749.666
+4/22/2015,09:46,775.202
+4/22/2015,09:47,782.961
+4/22/2015,09:48,776.392
+4/22/2015,09:49,751.101
+4/22/2015,09:50,747.894
+4/22/2015,09:51,742.502
+4/22/2015,09:52,735.695
+4/22/2015,09:53,731.655
+4/22/2015,09:54,728.590
+4/22/2015,09:55,729.879
+4/22/2015,09:56,728.009
+4/22/2015,09:57,594.383
+4/22/2015,09:58,608.080
+4/22/2015,09:59,713.578
+4/22/2015,10:00,731.687
+4/22/2015,10:01,731.057
+4/22/2015,10:02,733.662
+4/22/2015,10:03,735.857
+4/22/2015,10:04,734.722
+4/22/2015,10:05,736.636
+4/22/2015,10:06,739.934
+4/22/2015,10:07,740.674
+4/22/2015,10:08,739.125
+4/22/2015,10:09,740.986
+4/22/2015,10:10,743.957
+4/22/2015,10:11,750.11
+4/22/2015,10:12,751.875
+4/22/2015,10:13,755.331
+4/22/2015,10:14,754.336
+4/22/2015,10:15,754.617
+4/22/2015,10:16,757.216
+4/22/2015,10:17,759.765
+4/22/2015,10:18,758.597
+4/22/2015,10:19,755.520
+4/22/2015,10:20,760.099
+4/22/2015,10:21,768.040
+4/22/2015,10:22,774.192
+4/22/2015,10:23,773.988
+4/22/2015,10:24,774.901
+4/22/2015,10:25,774.161
+4/22/2015,10:26,773.738
+4/22/2015,10:27,777.174
+4/22/2015,10:28,777.990
+4/22/2015,10:29,779.239
+4/22/2015,10:30,780.717
+4/22/2015,10:31,783.276
+4/22/2015,10:32,782.106
+4/22/2015,10:33,779.596
+4/22/2015,10:34,784.792
+4/22/2015,10:35,788.099
+4/22/2015,10:36,788.920
+4/22/2015,10:37,794.234
+4/22/2015,10:38,796.125
+4/22/2015,10:39,796.799
+4/22/2015,10:40,797.946
+4/22/2015,10:41,801.121
+4/22/2015,10:42,801.631
+4/22/2015,10:43,799.827
+4/22/2015,10:44,798.169
+4/22/2015,10:45,802.072
+4/22/2015,10:46,802.258
+4/22/2015,10:47,803.812
+4/22/2015,10:48,786.840
+4/22/2015,10:49,808.803
+4/22/2015,10:50,812.520
+4/22/2015,10:51,813.730
+4/22/2015,10:52,814.415
+4/22/2015,10:53,816.496
+4/22/2015,10:54,815.356
+4/22/2015,10:55,814.104
+4/22/2015,10:56,817.416
+4/22/2015,10:57,816.372
+4/22/2015,10:58,817.866
+4/22/2015,10:59,822.385
+4/22/2015,11:00,827.057
+4/22/2015,11:01,826.013
+4/22/2015,11:02,825.369
+4/22/2015,11:03,825.539
+4/22/2015,11:04,827.68
+4/22/2015,11:05,830.508
+4/22/2015,11:06,832.693
+4/22/2015,11:07,833.919
+4/22/2015,11:08,832.957
+4/22/2015,11:09,832.816
+4/22/2015,11:10,834.592
+4/22/2015,11:11,835.871
+4/22/2015,11:12,837.572
+4/22/2015,11:13,840.693
+4/22/2015,11:14,841.306
+4/22/2015,11:15,842.857
+4/22/2015,11:16,843.252
+4/22/2015,11:17,844.119
+4/22/2015,11:18,847.043
+4/22/2015,11:19,847.987
+4/22/2015,11:20,849.287
+4/22/2015,11:21,850.195
+4/22/2015,11:22,849.605
+4/22/2015,11:23,849.801
+4/22/2015,11:24,848.559
+4/22/2015,11:25,847.334
+4/22/2015,11:26,848.202
+4/22/2015,11:27,849.681
+4/22/2015,11:28,851.678
+4/22/2015,11:29,850.409
+4/22/2015,11:30,851.084
+4/22/2015,11:31,852.822
+4/22/2015,11:32,853.685
+4/22/2015,11:33,852.303
+4/22/2015,11:34,850.799
+4/22/2015,11:35,854.226
+4/22/2015,11:36,855.114
+4/22/2015,11:37,855.075
+4/22/2015,11:38,857.154
+4/22/2015,11:39,856.843
+4/22/2015,11:40,856.895
+4/22/2015,11:41,858.444
+4/22/2015,11:42,859.199
+4/22/2015,11:43,860.601
+4/22/2015,11:44,859.433
+4/22/2015,11:45,858.086
+4/22/2015,11:46,857.798
+4/22/2015,11:47,858.850
+4/22/2015,11:48,860.072
+4/22/2015,11:49,861.870
+4/22/2015,11:50,862.323
+4/22/2015,11:51,862.163
+4/22/2015,11:52,861.809
+4/22/2015,11:53,862.056
+4/22/2015,11:54,863.378
+4/22/2015,11:55,863.082
+4/22/2015,11:56,862.764
+4/22/2015,11:57,862.169
+4/22/2015,11:58,862.016
+4/22/2015,11:59,864.782
+4/22/2015,12:00,864.258
+4/22/2015,12:01,863.660
+4/22/2015,12:02,864.858
+4/22/2015,12:03,863.335
+4/22/2015,12:04,862.560
+4/22/2015,12:05,862.789
+4/22/2015,12:06,865.412
+4/22/2015,12:07,865.183
+4/22/2015,12:08,862.654
+4/22/2015,12:09,864.163
+4/22/2015,12:10,864.677
+4/22/2015,12:11,867.277
+4/22/2015,12:12,867.124
+4/22/2015,12:13,865.353
+4/22/2015,12:14,864.588
+4/22/2015,12:15,865.452
+4/22/2015,12:16,864.277
+4/22/2015,12:17,864.280
+4/22/2015,12:18,864.420
+4/22/2015,12:19,864.773
+4/22/2015,12:20,863.625
+4/22/2015,12:21,862.689
+4/22/2015,12:22,862.678
+4/22/2015,12:23,862.496
+4/22/2015,12:24,860.269
+4/22/2015,12:25,859.158
+4/22/2015,12:26,860.159
+4/22/2015,12:27,861.231
+4/22/2015,12:28,862.901
+4/22/2015,12:29,863.550
+4/22/2015,12:30,862.218
+4/22/2015,12:31,859.793
+4/22/2015,12:32,861.165
+4/22/2015,12:33,857.858
+4/22/2015,12:34,855.210
+4/22/2015,12:35,855.465
+4/22/2015,12:36,856.149
+4/22/2015,12:37,856.028
+4/22/2015,12:38,856.714
+4/22/2015,12:39,854.505
+4/22/2015,12:40,856.96
+4/22/2015,12:41,859.149
+4/22/2015,12:42,859.941
+4/22/2015,12:43,858.775
+4/22/2015,12:44,856.479
+4/22/2015,12:45,856.837
+4/22/2015,12:46,855.265
+4/22/2015,12:47,855.218
+4/22/2015,12:48,854.731
+4/22/2015,12:49,855.014
+4/22/2015,12:50,850.983
+4/22/2015,12:51,848.722
+4/22/2015,12:52,846.582
+4/22/2015,12:53,846.223
+4/22/2015,12:54,848.636
+4/22/2015,12:55,851.073
+4/22/2015,12:56,851.596
+4/22/2015,12:57,843.610
+4/22/2015,12:58,840.455
+4/22/2015,12:59,841.766
+4/22/2015,13:00,844.935
+4/22/2015,13:01,845.217
+4/22/2015,13:02,847.509
+4/22/2015,13:03,848.703
+4/22/2015,13:04,843.425
+4/22/2015,13:05,837.090
+4/22/2015,13:06,833.133
+4/22/2015,13:07,835.152
+4/22/2015,13:08,839.148
+4/22/2015,13:09,846.691
+4/22/2015,13:10,851.349
+4/22/2015,13:11,846.621
+4/22/2015,13:12,838.375
+4/22/2015,13:13,837.975
+4/22/2015,13:14,822.585
+4/22/2015,13:15,818.003
+4/22/2015,13:16,824.315
+4/22/2015,13:17,831.349
+4/22/2015,13:18,840.027
+4/22/2015,13:19,843.420
+4/22/2015,13:20,846.501
+4/22/2015,13:21,844.576
+4/22/2015,13:22,842.607
+4/22/2015,13:23,841.084
+4/22/2015,13:24,843.571
+4/22/2015,13:25,844.769
+4/22/2015,13:26,842.883
+4/22/2015,13:27,842.144
+4/22/2015,13:28,841.574
+4/22/2015,13:29,848.934
+4/22/2015,13:30,854.893
+4/22/2015,13:31,857.295
+4/22/2015,13:32,857.459
+4/22/2015,13:33,862.005
+4/22/2015,13:34,866.775
+4/22/2015,13:35,875.207
+4/22/2015,13:36,882.694
+4/22/2015,13:37,888.888
+4/22/2015,13:38,877.793
+4/22/2015,13:39,886.308
+4/22/2015,13:40,895.572
+4/22/2015,13:41,912.703
+4/22/2015,13:42,928.125
+4/22/2015,13:43,938.993
+4/22/2015,13:44,947.381
+4/22/2015,13:45,955.364
+4/22/2015,13:46,966.642
+4/22/2015,13:47,974.939
+4/22/2015,13:48,982.821
+4/22/2015,13:49,983.819
+4/22/2015,13:50,993.731
+4/22/2015,13:51,998.947
+4/22/2015,13:52,1010.10
+4/22/2015,13:53,1004.93
+4/22/2015,13:54,969.906
+4/22/2015,13:55,773.453
+4/22/2015,13:56,682.432
+4/22/2015,13:57,649.963
+4/22/2015,13:58,587.289
+4/22/2015,13:59,513.775
+4/22/2015,14:00,466.257
+4/22/2015,14:01,490.289
+4/22/2015,14:02,512.123
+4/22/2015,14:03,506.160
+4/22/2015,14:04,482.046
+4/22/2015,14:05,504.164
+4/22/2015,14:06,478.009
+4/22/2015,14:07,460.335
+4/22/2015,14:08,464.196
+4/22/2015,14:09,493.417
+4/22/2015,14:10,505.788
+4/22/2015,14:11,507.318
+4/22/2015,14:12,499.136
+4/22/2015,14:13,474.884
+4/22/2015,14:14,450.598
+4/22/2015,14:15,440.553
+4/22/2015,14:16,436.573
+4/22/2015,14:17,431.543
+4/22/2015,14:18,424.319
+4/22/2015,14:19,417.124
+4/22/2015,14:20,410.663
+4/22/2015,14:21,406.278
+4/22/2015,14:22,408.796
+4/22/2015,14:23,410.776
+4/22/2015,14:24,411.954
+4/22/2015,14:25,412.272
+4/22/2015,14:26,411.466
+4/22/2015,14:27,412.673
+4/22/2015,14:28,413.423
+4/22/2015,14:29,410.511
+4/22/2015,14:30,407.502
+4/22/2015,14:31,415.362
+4/22/2015,14:32,424.380
+4/22/2015,14:33,436.228
+4/22/2015,14:34,447.877
+4/22/2015,14:35,460.390
+4/22/2015,14:36,457.974
+4/22/2015,14:37,457.369
+4/22/2015,14:38,468.034
+4/22/2015,14:39,478.851
+4/22/2015,14:40,497.998
+4/22/2015,14:41,515.159
+4/22/2015,14:42,523.802
+4/22/2015,14:43,532.486
+4/22/2015,14:44,534.217
+4/22/2015,14:45,504.955
+4/22/2015,14:46,484.532
+4/22/2015,14:47,468.405
+4/22/2015,14:48,455.256
+4/22/2015,14:49,450.440
+4/22/2015,14:50,451.034
+4/22/2015,14:51,449.603
+4/22/2015,14:52,448.465
+4/22/2015,14:53,445.455
+4/22/2015,14:54,435.415
+4/22/2015,14:55,425.551
+4/22/2015,14:56,418.144
+4/22/2015,14:57,413.250
+4/22/2015,14:58,408.541
+4/22/2015,14:59,399.361
+4/22/2015,15:00,392.662
+4/22/2015,15:01,397.305
+4/22/2015,15:02,390.403
+4/22/2015,15:03,384.353
+4/22/2015,15:04,377.873
+4/22/2015,15:05,369.781
+4/22/2015,15:06,368.843
+4/22/2015,15:07,364.450
+4/22/2015,15:08,358.724
+4/22/2015,15:09,353.064
+4/22/2015,15:10,351.763
+4/22/2015,15:11,352.619
+4/22/2015,15:12,353.436
+4/22/2015,15:13,351.188
+4/22/2015,15:14,351.766
+4/22/2015,15:15,353.060
+4/22/2015,15:16,354.952
+4/22/2015,15:17,356.282
+4/22/2015,15:18,360.205
+4/22/2015,15:19,369.332
+4/22/2015,15:20,377.430
+4/22/2015,15:21,378.795
+4/22/2015,15:22,382.771
+4/22/2015,15:23,382.331
+4/22/2015,15:24,387.590
+4/22/2015,15:25,407.980
+4/22/2015,15:26,443.791
+4/22/2015,15:27,468.480
+4/22/2015,15:28,465.971
+4/22/2015,15:29,465.974
+4/22/2015,15:30,452.619
+4/22/2015,15:31,464.509
+4/22/2015,15:32,460.719
+4/22/2015,15:33,452.490
+4/22/2015,15:34,442.394
+4/22/2015,15:35,453.783
+4/22/2015,15:36,475.466
+4/22/2015,15:37,484.702
+4/22/2015,15:38,491.295
+4/22/2015,15:39,514.609
+4/22/2015,15:40,565.287
+4/22/2015,15:41,560.219
+4/22/2015,15:42,524.010
+4/22/2015,15:43,496.038
+4/22/2015,15:44,475.858
+4/22/2015,15:45,475.284
+4/22/2015,15:46,462.134
+4/22/2015,15:47,427.798
+4/22/2015,15:48,422.735
+4/22/2015,15:49,430.411
+4/22/2015,15:50,438.944
+4/22/2015,15:51,436.790
+4/22/2015,15:52,440.488
+4/22/2015,15:53,434.130
+4/22/2015,15:54,433.506
+4/22/2015,15:55,432.744
+4/22/2015,15:56,392.089
+4/22/2015,15:57,381.384
+4/22/2015,15:58,408.596
+4/22/2015,15:59,435.909
+4/22/2015,16:00,430.321
+4/22/2015,16:01,456.594
+4/22/2015,16:02,406.331
+4/22/2015,16:03,392.438
+4/22/2015,16:04,402.792
+4/22/2015,16:05,383.134
+4/22/2015,16:06,403.334
+4/22/2015,16:07,412.128
+4/22/2015,16:08,428.672
+4/22/2015,16:09,432.885
+4/22/2015,16:10,436.453
+4/22/2015,16:11,459.253
+4/22/2015,16:12,470.915
+4/22/2015,16:13,454.942
+4/22/2015,16:14,440.755
+4/22/2015,16:15,433.945
+4/22/2015,16:16,424.364
+4/22/2015,16:17,458.160
+4/22/2015,16:18,500.252
+4/22/2015,16:19,502.486
+4/22/2015,16:20,499.266
+4/22/2015,16:21,493.053
+4/22/2015,16:22,488.201
+4/22/2015,16:23,485.271
+4/22/2015,16:24,481.581
+4/22/2015,16:25,477.500
+4/22/2015,16:26,473.661
+4/22/2015,16:27,470.093
+4/22/2015,16:28,466.272
+4/22/2015,16:29,460.991
+4/22/2015,16:30,455.267
+4/22/2015,16:31,412.584
+4/22/2015,16:32,353.352
+4/22/2015,16:33,360.748
+4/22/2015,16:34,339.132
+4/22/2015,16:35,334.546
+4/22/2015,16:36,344.917
+4/22/2015,16:37,352.504
+4/22/2015,16:38,346.991
+4/22/2015,16:39,349.236
+4/22/2015,16:40,341.236
+4/22/2015,16:41,337.594
+4/22/2015,16:42,328.229
+4/22/2015,16:43,324.059
+4/22/2015,16:44,324.175
+4/22/2015,16:45,320.960
+4/22/2015,16:46,333.061
+4/22/2015,16:47,340.657
+4/22/2015,16:48,348.928
+4/22/2015,16:49,347.937
+4/22/2015,16:50,338.417
+4/22/2015,16:51,324.610
+4/22/2015,16:52,318.364
+4/22/2015,16:53,311.263
+4/22/2015,16:54,309.068
+4/22/2015,16:55,306.871
+4/22/2015,16:56,295.613
+4/22/2015,16:57,293.471
+4/22/2015,16:58,295.344
+4/22/2015,16:59,279.110
+4/22/2015,17:00,275.232
+4/22/2015,17:01,270.716
+4/22/2015,17:02,248.357
+4/22/2015,17:03,244.519
+4/22/2015,17:04,250.040
+4/22/2015,17:05,262.062
+4/22/2015,17:06,279.849
+4/22/2015,17:07,283.530
+4/22/2015,17:08,275.320
+4/22/2015,17:09,264.660
+4/22/2015,17:10,255.221
+4/22/2015,17:11,239.566
+4/22/2015,17:12,225.065
+4/22/2015,17:13,213.680
+4/22/2015,17:14,199.633
+4/22/2015,17:15,205.905
+4/22/2015,17:16,223.334
+4/22/2015,17:17,233.900
+4/22/2015,17:18,211.457
+4/22/2015,17:19,191.026
+4/22/2015,17:20,179.844
+4/22/2015,17:21,175.050
+4/22/2015,17:22,174.785
+4/22/2015,17:23,180.035
+4/22/2015,17:24,181.958
+4/22/2015,17:25,173.906
+4/22/2015,17:26,169.990
+4/22/2015,17:27,168.174
+4/22/2015,17:28,164.398
+4/22/2015,17:29,162.931
+4/22/2015,17:30,163.831
+4/22/2015,17:31,166.932
+4/22/2015,17:32,174.899
+4/22/2015,17:33,184.312
+4/22/2015,17:34,187.029
+4/22/2015,17:35,187.459
+4/22/2015,17:36,183.328
+4/22/2015,17:37,167.175
+4/22/2015,17:38,163.465
+4/22/2015,17:39,158.257
+4/22/2015,17:40,150.560
+4/22/2015,17:41,138.873
+4/22/2015,17:42,127.261
+4/22/2015,17:43,118.125
+4/22/2015,17:44,113.847
+4/22/2015,17:45,111.122
+4/22/2015,17:46,107.868
+4/22/2015,17:47,105.863
+4/22/2015,17:48,104.658
+4/22/2015,17:49,103.045
+4/22/2015,17:50,97.5852
+4/22/2015,17:51,92.2459
+4/22/2015,17:52,88.7782
+4/22/2015,17:53,86.1482
+4/22/2015,17:54,83.3488
+4/22/2015,17:55,80.5129
+4/22/2015,17:56,77.8344
+4/22/2015,17:57,75.7739
+4/22/2015,17:58,73.7875
+4/22/2015,17:59,71.3417
+4/22/2015,18:00,69.2950
+4/22/2015,18:01,67.4327
+4/22/2015,18:02,66.1099
+4/22/2015,18:03,64.0922
+4/22/2015,18:04,61.9504
+4/22/2015,18:05,61.7477
+4/22/2015,18:06,67.7201
+4/22/2015,18:07,78.0763
+4/22/2015,18:08,84.2750
+4/22/2015,18:09,84.2584
+4/22/2015,18:10,78.7348
+4/22/2015,18:11,80.3095
+4/22/2015,18:12,78.1195
+4/22/2015,18:13,75.6592
+4/22/2015,18:14,72.9973
+4/22/2015,18:15,68.8363
+4/22/2015,18:16,62.0307
+4/22/2015,18:17,58.1843
+4/22/2015,18:18,61.0739
+4/22/2015,18:19,55.1729
+4/22/2015,18:20,54.2847
+4/22/2015,18:21,52.3108
+4/22/2015,18:22,49.9515
+4/22/2015,18:23,47.2413
+4/22/2015,18:24,44.4858
+4/22/2015,18:25,41.5028
+4/22/2015,18:26,37.7735
+4/22/2015,18:27,33.5058
+4/22/2015,18:28,29.4524
+4/22/2015,18:29,26.0216
+4/22/2015,18:30,23.0911
+4/22/2015,18:31,21.1612
+4/22/2015,18:32,19.2314
+4/22/2015,18:33,18.0810
+4/22/2015,18:34,16.8807
+4/22/2015,18:35,15.3467
+4/22/2015,18:36,13.3212
+4/22/2015,18:37,11.1984
+4/22/2015,18:38,9.37804
+4/22/2015,18:39,7.44300
+4/22/2015,18:40,5.85914
+4/22/2015,18:41,4.48939
+4/22/2015,18:42,3.51793
+4/22/2015,18:43,2.54060
+4/22/2015,18:44,1.88938
+4/22/2015,18:45,1.77717
+4/22/2015,18:46,6.51751
+4/22/2015,18:47,6.11063

+ 809 - 0
imc/exprs/date2025/6_varying_power/data/2015-04-23-Sacramento.csv

@@ -0,0 +1,809 @@
+DATE (MM/DD/YYYY),PST,Global Horizontal [W/m^2]
+4/23/2015,05:21,3.66759
+4/23/2015,05:22,0.844226
+4/23/2015,05:23,1.15068
+4/23/2015,05:24,1.46938
+4/23/2015,05:25,1.87779
+4/23/2015,05:26,2.37960
+4/23/2015,05:27,2.96000
+4/23/2015,05:28,3.46057
+4/23/2015,05:29,4.07380
+4/23/2015,05:30,4.51638
+4/23/2015,05:31,4.99804
+4/23/2015,05:32,5.57824
+4/23/2015,05:33,6.30074
+4/23/2015,05:34,7.27664
+4/23/2015,05:35,8.19809
+4/23/2015,05:36,9.28578
+4/23/2015,05:37,10.3377
+4/23/2015,05:38,11.4895
+4/23/2015,05:39,13.2197
+4/23/2015,05:40,15.1376
+4/23/2015,05:41,17.3554
+4/23/2015,05:42,19.6485
+4/23/2015,05:43,21.8210
+4/23/2015,05:44,23.2576
+4/23/2015,05:45,24.4098
+4/23/2015,05:46,25.1593
+4/23/2015,05:47,26.0861
+4/23/2015,05:48,27.1551
+4/23/2015,05:49,28.4063
+4/23/2015,05:50,30.0337
+4/23/2015,05:51,31.5754
+4/23/2015,05:52,33.3799
+4/23/2015,05:53,34.9071
+4/23/2015,05:54,36.3899
+4/23/2015,05:55,37.5208
+4/23/2015,05:56,38.6862
+4/23/2015,05:57,40.1171
+4/23/2015,05:58,44.7200
+4/23/2015,05:59,53.0154
+4/23/2015,06:00,58.7494
+4/23/2015,06:01,61.1468
+4/23/2015,06:02,63.5504
+4/23/2015,06:03,65.8591
+4/23/2015,06:04,68.0033
+4/23/2015,06:05,70.4307
+4/23/2015,06:06,72.9954
+4/23/2015,06:07,75.5204
+4/23/2015,06:08,77.3190
+4/23/2015,06:09,79.5988
+4/23/2015,06:10,82.0164
+4/23/2015,06:11,84.8101
+4/23/2015,06:12,87.5373
+4/23/2015,06:13,90.3051
+4/23/2015,06:14,93.1132
+4/23/2015,06:15,95.6285
+4/23/2015,06:16,98.3274
+4/23/2015,06:17,101.029
+4/23/2015,06:18,103.472
+4/23/2015,06:19,106.287
+4/23/2015,06:20,109.027
+4/23/2015,06:21,112.062
+4/23/2015,06:22,114.760
+4/23/2015,06:23,118.011
+4/23/2015,06:24,120.735
+4/23/2015,06:25,124.427
+4/23/2015,06:26,127.066
+4/23/2015,06:27,129.432
+4/23/2015,06:28,132.201
+4/23/2015,06:29,135.413
+4/23/2015,06:30,138.232
+4/23/2015,06:31,141.540
+4/23/2015,06:32,144.527
+4/23/2015,06:33,147.460
+4/23/2015,06:34,150.188
+4/23/2015,06:35,152.412
+4/23/2015,06:36,155.593
+4/23/2015,06:37,158.344
+4/23/2015,06:38,161.189
+4/23/2015,06:39,163.787
+4/23/2015,06:40,166.769
+4/23/2015,06:41,169.091
+4/23/2015,06:42,171.258
+4/23/2015,06:43,175.000
+4/23/2015,06:44,178.541
+4/23/2015,06:45,181.190
+4/23/2015,06:46,183.833
+4/23/2015,06:47,186.329
+4/23/2015,06:48,186.488
+4/23/2015,06:49,185.058
+4/23/2015,06:50,187.523
+4/23/2015,06:51,190.051
+4/23/2015,06:52,192.126
+4/23/2015,06:53,195.851
+4/23/2015,06:54,197.064
+4/23/2015,06:55,196.002
+4/23/2015,06:56,202.050
+4/23/2015,06:57,205.247
+4/23/2015,06:58,205.942
+4/23/2015,06:59,204.547
+4/23/2015,07:00,206.265
+4/23/2015,07:01,209.410
+4/23/2015,07:02,218.652
+4/23/2015,07:03,221.254
+4/23/2015,07:04,220.260
+4/23/2015,07:05,213.650
+4/23/2015,07:06,200.381
+4/23/2015,07:07,175.978
+4/23/2015,07:08,189.359
+4/23/2015,07:09,210.797
+4/23/2015,07:10,223.430
+4/23/2015,07:11,221.619
+4/23/2015,07:12,215.827
+4/23/2015,07:13,224.700
+4/23/2015,07:14,232.796
+4/23/2015,07:15,255.298
+4/23/2015,07:16,259.324
+4/23/2015,07:17,259.629
+4/23/2015,07:18,257.718
+4/23/2015,07:19,267.159
+4/23/2015,07:20,282.824
+4/23/2015,07:21,290.005
+4/23/2015,07:22,297.811
+4/23/2015,07:23,301.755
+4/23/2015,07:24,304.963
+4/23/2015,07:25,309.040
+4/23/2015,07:26,310.173
+4/23/2015,07:27,312.554
+4/23/2015,07:28,316.320
+4/23/2015,07:29,318.568
+4/23/2015,07:30,322.352
+4/23/2015,07:31,325.165
+4/23/2015,07:32,331.078
+4/23/2015,07:33,334.002
+4/23/2015,07:34,336.187
+4/23/2015,07:35,340.082
+4/23/2015,07:36,342.736
+4/23/2015,07:37,345.417
+4/23/2015,07:38,348.879
+4/23/2015,07:39,350.941
+4/23/2015,07:40,356.163
+4/23/2015,07:41,357.621
+4/23/2015,07:42,361.191
+4/23/2015,07:43,364.039
+4/23/2015,07:44,367.344
+4/23/2015,07:45,371.238
+4/23/2015,07:46,374.424
+4/23/2015,07:47,377.959
+4/23/2015,07:48,380.388
+4/23/2015,07:49,382.606
+4/23/2015,07:50,386.584
+4/23/2015,07:51,389.587
+4/23/2015,07:52,389.998
+4/23/2015,07:53,394.472
+4/23/2015,07:54,396.880
+4/23/2015,07:55,399.957
+4/23/2015,07:56,403.957
+4/23/2015,07:57,405.840
+4/23/2015,07:58,408.023
+4/23/2015,07:59,411.936
+4/23/2015,08:00,414.595
+4/23/2015,08:01,415.609
+4/23/2015,08:02,418.697
+4/23/2015,08:03,419.691
+4/23/2015,08:04,413.209
+4/23/2015,08:05,395.153
+4/23/2015,08:06,368.477
+4/23/2015,08:07,332.415
+4/23/2015,08:08,290.452
+4/23/2015,08:09,248.991
+4/23/2015,08:10,210.209
+4/23/2015,08:11,177.008
+4/23/2015,08:12,152.379
+4/23/2015,08:13,135.233
+4/23/2015,08:14,127.007
+4/23/2015,08:15,125.819
+4/23/2015,08:16,126.132
+4/23/2015,08:17,126.789
+4/23/2015,08:18,127.767
+4/23/2015,08:19,128.416
+4/23/2015,08:20,128.821
+4/23/2015,08:21,128.318
+4/23/2015,08:22,127.791
+4/23/2015,08:23,127.167
+4/23/2015,08:24,127.047
+4/23/2015,08:25,127.971
+4/23/2015,08:26,134.524
+4/23/2015,08:27,150.318
+4/23/2015,08:28,177.048
+4/23/2015,08:29,213.374
+4/23/2015,08:30,257.435
+4/23/2015,08:31,306.626
+4/23/2015,08:32,356.307
+4/23/2015,08:33,405.105
+4/23/2015,08:34,448.088
+4/23/2015,08:35,481.607
+4/23/2015,08:36,506.629
+4/23/2015,08:37,521.729
+4/23/2015,08:38,528.343
+4/23/2015,08:39,530.968
+4/23/2015,08:40,533.606
+4/23/2015,08:41,537.21
+4/23/2015,08:42,538.588
+4/23/2015,08:43,541.931
+4/23/2015,08:44,545.460
+4/23/2015,08:45,551.259
+4/23/2015,08:46,556.015
+4/23/2015,08:47,557.545
+4/23/2015,08:48,561.293
+4/23/2015,08:49,562.883
+4/23/2015,08:50,567.107
+4/23/2015,08:51,570.671
+4/23/2015,08:52,573.707
+4/23/2015,08:53,577.631
+4/23/2015,08:54,581.086
+4/23/2015,08:55,584.364
+4/23/2015,08:56,587.583
+4/23/2015,08:57,588.824
+4/23/2015,08:58,589.177
+4/23/2015,08:59,591.639
+4/23/2015,09:00,594.566
+4/23/2015,09:01,596.637
+4/23/2015,09:02,601.541
+4/23/2015,09:03,607.911
+4/23/2015,09:04,609.636
+4/23/2015,09:05,611.584
+4/23/2015,09:06,612.449
+4/23/2015,09:07,613.792
+4/23/2015,09:08,619.09
+4/23/2015,09:09,621.730
+4/23/2015,09:10,624.218
+4/23/2015,09:11,624.994
+4/23/2015,09:12,627.947
+4/23/2015,09:13,632.498
+4/23/2015,09:14,636.001
+4/23/2015,09:15,640.746
+4/23/2015,09:16,641.028
+4/23/2015,09:17,643.560
+4/23/2015,09:18,645.232
+4/23/2015,09:19,648.568
+4/23/2015,09:20,651.584
+4/23/2015,09:21,653.166
+4/23/2015,09:22,655.961
+4/23/2015,09:23,658.411
+4/23/2015,09:24,660.495
+4/23/2015,09:25,664.336
+4/23/2015,09:26,668.326
+4/23/2015,09:27,671.693
+4/23/2015,09:28,674.120
+4/23/2015,09:29,674.683
+4/23/2015,09:30,675.935
+4/23/2015,09:31,677.481
+4/23/2015,09:32,679.072
+4/23/2015,09:33,683.065
+4/23/2015,09:34,685.281
+4/23/2015,09:35,688.961
+4/23/2015,09:36,691.519
+4/23/2015,09:37,693.175
+4/23/2015,09:38,695.328
+4/23/2015,09:39,695.780
+4/23/2015,09:40,700.312
+4/23/2015,09:41,701.920
+4/23/2015,09:42,705.422
+4/23/2015,09:43,708.298
+4/23/2015,09:44,711.821
+4/23/2015,09:45,713.946
+4/23/2015,09:46,717.735
+4/23/2015,09:47,719.656
+4/23/2015,09:48,719.349
+4/23/2015,09:49,723.357
+4/23/2015,09:50,724.404
+4/23/2015,09:51,726.280
+4/23/2015,09:52,728.479
+4/23/2015,09:53,733.268
+4/23/2015,09:54,734.938
+4/23/2015,09:55,736.444
+4/23/2015,09:56,739.138
+4/23/2015,09:57,740.204
+4/23/2015,09:58,741.529
+4/23/2015,09:59,745.351
+4/23/2015,10:00,748.412
+4/23/2015,10:01,748.851
+4/23/2015,10:02,751.995
+4/23/2015,10:03,750.844
+4/23/2015,10:04,754.840
+4/23/2015,10:05,756.781
+4/23/2015,10:06,757.602
+4/23/2015,10:07,761.327
+4/23/2015,10:08,763.073
+4/23/2015,10:09,764.718
+4/23/2015,10:10,764.077
+4/23/2015,10:11,767.312
+4/23/2015,10:12,767.767
+4/23/2015,10:13,772.314
+4/23/2015,10:14,773.701
+4/23/2015,10:15,775.047
+4/23/2015,10:16,775.387
+4/23/2015,10:17,780.506
+4/23/2015,10:18,781.906
+4/23/2015,10:19,783.06
+4/23/2015,10:20,785.141
+4/23/2015,10:21,786.409
+4/23/2015,10:22,786.805
+4/23/2015,10:23,784.787
+4/23/2015,10:24,787.149
+4/23/2015,10:25,790.982
+4/23/2015,10:26,794.335
+4/23/2015,10:27,796.826
+4/23/2015,10:28,797.253
+4/23/2015,10:29,798.204
+4/23/2015,10:30,802.448
+4/23/2015,10:31,800.775
+4/23/2015,10:32,806.824
+4/23/2015,10:33,805.412
+4/23/2015,10:34,802.543
+4/23/2015,10:35,804.452
+4/23/2015,10:36,806.347
+4/23/2015,10:37,809.148
+4/23/2015,10:38,814.626
+4/23/2015,10:39,814.463
+4/23/2015,10:40,815.597
+4/23/2015,10:41,817.024
+4/23/2015,10:42,817.370
+4/23/2015,10:43,819.882
+4/23/2015,10:44,820.295
+4/23/2015,10:45,822.027
+4/23/2015,10:46,824.551
+4/23/2015,10:47,825.290
+4/23/2015,10:48,828.592
+4/23/2015,10:49,833.197
+4/23/2015,10:50,833.465
+4/23/2015,10:51,831.838
+4/23/2015,10:52,833.503
+4/23/2015,10:53,835.629
+4/23/2015,10:54,833.007
+4/23/2015,10:55,834.614
+4/23/2015,10:56,836.924
+4/23/2015,10:57,838.143
+4/23/2015,10:58,840.181
+4/23/2015,10:59,841.233
+4/23/2015,11:00,844.028
+4/23/2015,11:01,844.686
+4/23/2015,11:02,844.127
+4/23/2015,11:03,847.026
+4/23/2015,11:04,850.324
+4/23/2015,11:05,849.483
+4/23/2015,11:06,850.842
+4/23/2015,11:07,851.472
+4/23/2015,11:08,850.629
+4/23/2015,11:09,855.402
+4/23/2015,11:10,857.311
+4/23/2015,11:11,855.626
+4/23/2015,11:12,852.224
+4/23/2015,11:13,852.149
+4/23/2015,11:14,856.953
+4/23/2015,11:15,855.792
+4/23/2015,11:16,854.574
+4/23/2015,11:17,857.178
+4/23/2015,11:18,857.478
+4/23/2015,11:19,862.108
+4/23/2015,11:20,862.150
+4/23/2015,11:21,861.040
+4/23/2015,11:22,863.123
+4/23/2015,11:23,867.045
+4/23/2015,11:24,868.080
+4/23/2015,11:25,867.829
+4/23/2015,11:26,866.358
+4/23/2015,11:27,869.030
+4/23/2015,11:28,868.632
+4/23/2015,11:29,870.276
+4/23/2015,11:30,872.82
+4/23/2015,11:31,870.723
+4/23/2015,11:32,870.755
+4/23/2015,11:33,872.339
+4/23/2015,11:34,871.079
+4/23/2015,11:35,870.424
+4/23/2015,11:36,873.462
+4/23/2015,11:37,871.805
+4/23/2015,11:38,871.807
+4/23/2015,11:39,873.745
+4/23/2015,11:40,871.484
+4/23/2015,11:41,872.958
+4/23/2015,11:42,872.785
+4/23/2015,11:43,875.112
+4/23/2015,11:44,875.009
+4/23/2015,11:45,876.894
+4/23/2015,11:46,877.077
+4/23/2015,11:47,875.417
+4/23/2015,11:48,874.995
+4/23/2015,11:49,876.932
+4/23/2015,11:50,879.857
+4/23/2015,11:51,879.981
+4/23/2015,11:52,880.368
+4/23/2015,11:53,885.070
+4/23/2015,11:54,883.949
+4/23/2015,11:55,879.204
+4/23/2015,11:56,870.614
+4/23/2015,11:57,871.423
+4/23/2015,11:58,874.131
+4/23/2015,11:59,876.535
+4/23/2015,12:00,877.640
+4/23/2015,12:01,878.368
+4/23/2015,12:02,879.753
+4/23/2015,12:03,881.296
+4/23/2015,12:04,882.573
+4/23/2015,12:05,882.443
+4/23/2015,12:06,885.365
+4/23/2015,12:07,888.944
+4/23/2015,12:08,888.454
+4/23/2015,12:09,888.236
+4/23/2015,12:10,888.302
+4/23/2015,12:11,885.963
+4/23/2015,12:12,887.485
+4/23/2015,12:13,886.109
+4/23/2015,12:14,885.795
+4/23/2015,12:15,887.617
+4/23/2015,12:16,888.960
+4/23/2015,12:17,889.155
+4/23/2015,12:18,864.634
+4/23/2015,12:19,830.372
+4/23/2015,12:20,824.264
+4/23/2015,12:21,816.005
+4/23/2015,12:22,821.265
+4/23/2015,12:23,834.691
+4/23/2015,12:24,865.913
+4/23/2015,12:25,879.383
+4/23/2015,12:26,881.210
+4/23/2015,12:27,880.979
+4/23/2015,12:28,879.109
+4/23/2015,12:29,866.556
+4/23/2015,12:30,871.697
+4/23/2015,12:31,882.932
+4/23/2015,12:32,876.812
+4/23/2015,12:33,894.872
+4/23/2015,12:34,894.054
+4/23/2015,12:35,848.977
+4/23/2015,12:36,867.541
+4/23/2015,12:37,870.167
+4/23/2015,12:38,881.282
+4/23/2015,12:39,872.577
+4/23/2015,12:40,862.631
+4/23/2015,12:41,861.136
+4/23/2015,12:42,856.563
+4/23/2015,12:43,856.781
+4/23/2015,12:44,850.112
+4/23/2015,12:45,838.160
+4/23/2015,12:46,846.183
+4/23/2015,12:47,843.381
+4/23/2015,12:48,825.958
+4/23/2015,12:49,802.475
+4/23/2015,12:50,812.148
+4/23/2015,12:51,779.672
+4/23/2015,12:52,811.681
+4/23/2015,12:53,835.528
+4/23/2015,12:54,862.373
+4/23/2015,12:55,865.963
+4/23/2015,12:56,861.410
+4/23/2015,12:57,864.168
+4/23/2015,12:58,861.824
+4/23/2015,12:59,849.341
+4/23/2015,13:00,861.557
+4/23/2015,13:01,859.486
+4/23/2015,13:02,857.565
+4/23/2015,13:03,870.407
+4/23/2015,13:04,869.394
+4/23/2015,13:05,867.909
+4/23/2015,13:06,860.968
+4/23/2015,13:07,859.951
+4/23/2015,13:08,852.877
+4/23/2015,13:09,835.390
+4/23/2015,13:10,824.865
+4/23/2015,13:11,825.843
+4/23/2015,13:12,828.662
+4/23/2015,13:13,823.589
+4/23/2015,13:14,819.029
+4/23/2015,13:15,805.870
+4/23/2015,13:16,791.047
+4/23/2015,13:17,787.453
+4/23/2015,13:18,793.195
+4/23/2015,13:19,813.711
+4/23/2015,13:20,823.671
+4/23/2015,13:21,832.288
+4/23/2015,13:22,828.401
+4/23/2015,13:23,843.270
+4/23/2015,13:24,842.714
+4/23/2015,13:25,836.959
+4/23/2015,13:26,839.571
+4/23/2015,13:27,828.731
+4/23/2015,13:28,819.579
+4/23/2015,13:29,803.370
+4/23/2015,13:30,790.840
+4/23/2015,13:31,787.484
+4/23/2015,13:32,786.518
+4/23/2015,13:33,784.068
+4/23/2015,13:34,776.041
+4/23/2015,13:35,777.453
+4/23/2015,13:36,793.428
+4/23/2015,13:37,790.097
+4/23/2015,13:38,793.438
+4/23/2015,13:39,797.326
+4/23/2015,13:40,788.044
+4/23/2015,13:41,781.691
+4/23/2015,13:42,779.804
+4/23/2015,13:43,781.318
+4/23/2015,13:44,790.421
+4/23/2015,13:45,800.010
+4/23/2015,13:46,805.941
+4/23/2015,13:47,793.990
+4/23/2015,13:48,784.524
+4/23/2015,13:49,783.932
+4/23/2015,13:50,785.676
+4/23/2015,13:51,788.705
+4/23/2015,13:52,791.256
+4/23/2015,13:53,788.733
+4/23/2015,13:54,776.158
+4/23/2015,13:55,769.992
+4/23/2015,13:56,774.571
+4/23/2015,13:57,783.257
+4/23/2015,13:58,783.724
+4/23/2015,13:59,783.194
+4/23/2015,14:00,785.645
+4/23/2015,14:01,778.323
+4/23/2015,14:02,761.491
+4/23/2015,14:03,760.279
+4/23/2015,14:04,705.979
+4/23/2015,14:05,680.227
+4/23/2015,14:06,717.097
+4/23/2015,14:07,694.606
+4/23/2015,14:08,697.126
+4/23/2015,14:09,703.555
+4/23/2015,14:10,717.059
+4/23/2015,14:11,738.639
+4/23/2015,14:12,739.215
+4/23/2015,14:13,740.939
+4/23/2015,14:14,709.875
+4/23/2015,14:15,712.423
+4/23/2015,14:16,732.537
+4/23/2015,14:17,746.346
+4/23/2015,14:18,738.340
+4/23/2015,14:19,704.785
+4/23/2015,14:20,702.644
+4/23/2015,14:21,680.358
+4/23/2015,14:22,715.220
+4/23/2015,14:23,735.094
+4/23/2015,14:24,729.747
+4/23/2015,14:25,731.500
+4/23/2015,14:26,730.740
+4/23/2015,14:27,729.525
+4/23/2015,14:28,712.743
+4/23/2015,14:29,705.758
+4/23/2015,14:30,718.6
+4/23/2015,14:31,718.049
+4/23/2015,14:32,710.743
+4/23/2015,14:33,700.519
+4/23/2015,14:34,693.831
+4/23/2015,14:35,696.284
+4/23/2015,14:36,699.857
+4/23/2015,14:37,697.705
+4/23/2015,14:38,697.881
+4/23/2015,14:39,696.452
+4/23/2015,14:40,696.604
+4/23/2015,14:41,676.730
+4/23/2015,14:42,665.763
+4/23/2015,14:43,690.202
+4/23/2015,14:44,690.153
+4/23/2015,14:45,687.309
+4/23/2015,14:46,685.813
+4/23/2015,14:47,681.314
+4/23/2015,14:48,677.103
+4/23/2015,14:49,669.242
+4/23/2015,14:50,662.018
+4/23/2015,14:51,648.583
+4/23/2015,14:52,647.763
+4/23/2015,14:53,623.563
+4/23/2015,14:54,614.449
+4/23/2015,14:55,611.026
+4/23/2015,14:56,631.024
+4/23/2015,14:57,617.959
+4/23/2015,14:58,622.908
+4/23/2015,14:59,628.768
+4/23/2015,15:00,636.972
+4/23/2015,15:01,638.297
+4/23/2015,15:02,642.453
+4/23/2015,15:03,642.576
+4/23/2015,15:04,643.567
+4/23/2015,15:05,629.953
+4/23/2015,15:06,614.329
+4/23/2015,15:07,577.911
+4/23/2015,15:08,569.698
+4/23/2015,15:09,581.487
+4/23/2015,15:10,581.612
+4/23/2015,15:11,585.779
+4/23/2015,15:12,601.435
+4/23/2015,15:13,598.785
+4/23/2015,15:14,596.912
+4/23/2015,15:15,592.243
+4/23/2015,15:16,586.248
+4/23/2015,15:17,568.354
+4/23/2015,15:18,572.512
+4/23/2015,15:19,566.914
+4/23/2015,15:20,554.347
+4/23/2015,15:21,545.180
+4/23/2015,15:22,505.857
+4/23/2015,15:23,483.088
+4/23/2015,15:24,456.349
+4/23/2015,15:25,429.746
+4/23/2015,15:26,408.293
+4/23/2015,15:27,362.852
+4/23/2015,15:28,348.501
+4/23/2015,15:29,343.904
+4/23/2015,15:30,352.103
+4/23/2015,15:31,402.043
+4/23/2015,15:32,403.262
+4/23/2015,15:33,407.367
+4/23/2015,15:34,392.913
+4/23/2015,15:35,308.595
+4/23/2015,15:36,310.766
+4/23/2015,15:37,278.976
+4/23/2015,15:38,267.666
+4/23/2015,15:39,292.908
+4/23/2015,15:40,281.119
+4/23/2015,15:41,279.918
+4/23/2015,15:42,290.769
+4/23/2015,15:43,286.404
+4/23/2015,15:44,260.420
+4/23/2015,15:45,234.636
+4/23/2015,15:46,238.930
+4/23/2015,15:47,238.865
+4/23/2015,15:48,232.489
+4/23/2015,15:49,228.572
+4/23/2015,15:50,229.185
+4/23/2015,15:51,233.666
+4/23/2015,15:52,239.679
+4/23/2015,15:53,234.014
+4/23/2015,15:54,232.720
+4/23/2015,15:55,233.734
+4/23/2015,15:56,231.940
+4/23/2015,15:57,226.518
+4/23/2015,15:58,217.376
+4/23/2015,15:59,210.876
+4/23/2015,16:00,207.960
+4/23/2015,16:01,209.906
+4/23/2015,16:02,212.871
+4/23/2015,16:03,212.394
+4/23/2015,16:04,221.416
+4/23/2015,16:05,230.210
+4/23/2015,16:06,232.841
+4/23/2015,16:07,232.322
+4/23/2015,16:08,224.443
+4/23/2015,16:09,218.709
+4/23/2015,16:10,216.693
+4/23/2015,16:11,216.406
+4/23/2015,16:12,219.552
+4/23/2015,16:13,219.522
+4/23/2015,16:14,219.771
+4/23/2015,16:15,221.568
+4/23/2015,16:16,219.226
+4/23/2015,16:17,218.895
+4/23/2015,16:18,219.775
+4/23/2015,16:19,221.506
+4/23/2015,16:20,221.006
+4/23/2015,16:21,228.234
+4/23/2015,16:22,250.201
+4/23/2015,16:23,272.811
+4/23/2015,16:24,290.055
+4/23/2015,16:25,288.658
+4/23/2015,16:26,282.807
+4/23/2015,16:27,285.971
+4/23/2015,16:28,294.264
+4/23/2015,16:29,294.447
+4/23/2015,16:30,309.040
+4/23/2015,16:31,306.013
+4/23/2015,16:32,299.951
+4/23/2015,16:33,288.670
+4/23/2015,16:34,281.689
+4/23/2015,16:35,260.994
+4/23/2015,16:36,277.116
+4/23/2015,16:37,252.454
+4/23/2015,16:38,272.275
+4/23/2015,16:39,299.883
+4/23/2015,16:40,295.889
+4/23/2015,16:41,296.271
+4/23/2015,16:42,282.223
+4/23/2015,16:43,266.034
+4/23/2015,16:44,265.624
+4/23/2015,16:45,261.818
+4/23/2015,16:46,255.091
+4/23/2015,16:47,245.669
+4/23/2015,16:48,232.774
+4/23/2015,16:49,217.219
+4/23/2015,16:50,209.244
+4/23/2015,16:51,208.790
+4/23/2015,16:52,219.651
+4/23/2015,16:53,270.921
+4/23/2015,16:54,366.393
+4/23/2015,16:55,401.993
+4/23/2015,16:56,400.964
+4/23/2015,16:57,394.772
+4/23/2015,16:58,393.796
+4/23/2015,16:59,389.095
+4/23/2015,17:00,382.654
+4/23/2015,17:01,377.297
+4/23/2015,17:02,368.882
+4/23/2015,17:03,359.141
+4/23/2015,17:04,341.235
+4/23/2015,17:05,328.530
+4/23/2015,17:06,329.186
+4/23/2015,17:07,316.152
+4/23/2015,17:08,309.628
+4/23/2015,17:09,317.871
+4/23/2015,17:10,312.481
+4/23/2015,17:11,307.044
+4/23/2015,17:12,302.968
+4/23/2015,17:13,295.553
+4/23/2015,17:14,286.067
+4/23/2015,17:15,271.341
+4/23/2015,17:16,267.263
+4/23/2015,17:17,264.173
+4/23/2015,17:18,255.398
+4/23/2015,17:19,248.211
+4/23/2015,17:20,237.951
+4/23/2015,17:21,224.727
+4/23/2015,17:22,219.245
+4/23/2015,17:23,209.226
+4/23/2015,17:24,193.952
+4/23/2015,17:25,174.031
+4/23/2015,17:26,155.382
+4/23/2015,17:27,140.158
+4/23/2015,17:28,137.858
+4/23/2015,17:29,138.238
+4/23/2015,17:30,121.638
+4/23/2015,17:31,123.897
+4/23/2015,17:32,120.632
+4/23/2015,17:33,122.201
+4/23/2015,17:34,133.032
+4/23/2015,17:35,140.832
+4/23/2015,17:36,137.287
+4/23/2015,17:37,133.876
+4/23/2015,17:38,134.662
+4/23/2015,17:39,127.980
+4/23/2015,17:40,126.841
+4/23/2015,17:41,118.790
+4/23/2015,17:42,100.623
+4/23/2015,17:43,99.8613
+4/23/2015,17:44,96.6442
+4/23/2015,17:45,89.0590
+4/23/2015,17:46,83.8028
+4/23/2015,17:47,77.0451
+4/23/2015,17:48,71.4042
+4/23/2015,17:49,78.0858
+4/23/2015,17:50,79.7455
+4/23/2015,17:51,73.4095
+4/23/2015,17:52,65.9183
+4/23/2015,17:53,60.5318
+4/23/2015,17:54,58.5843
+4/23/2015,17:55,56.7501
+4/23/2015,17:56,51.9853
+4/23/2015,17:57,47.6313
+4/23/2015,17:58,47.5884
+4/23/2015,17:59,47.0197
+4/23/2015,18:00,45.9536
+4/23/2015,18:01,46.5821
+4/23/2015,18:02,47.1648
+4/23/2015,18:03,46.2554
+4/23/2015,18:04,44.0913
+4/23/2015,18:05,41.9027
+4/23/2015,18:06,40.4931
+4/23/2015,18:07,39.2787
+4/23/2015,18:08,37.9624
+4/23/2015,18:09,36.6891
+4/23/2015,18:10,36.3902
+4/23/2015,18:11,35.8476
+4/23/2015,18:12,35.1527
+4/23/2015,18:13,34.3779
+4/23/2015,18:14,33.9058
+4/23/2015,18:15,33.8113
+4/23/2015,18:16,34.0926
+4/23/2015,18:17,33.8349
+4/23/2015,18:18,33.3815
+4/23/2015,18:19,32.8798
+4/23/2015,18:20,31.6403
+4/23/2015,18:21,30.5405
+4/23/2015,18:22,29.1584
+4/23/2015,18:23,27.7987
+4/23/2015,18:24,26.6870
+4/23/2015,18:25,25.6653
+4/23/2015,18:26,24.3173
+4/23/2015,18:27,23.0553
+4/23/2015,18:28,21.7994
+4/23/2015,18:29,20.6187
+4/23/2015,18:30,19.0051
+4/23/2015,18:31,17.7948
+4/23/2015,18:32,16.2704
+4/23/2015,18:33,14.8158
+4/23/2015,18:34,13.2130
+4/23/2015,18:35,11.5842
+4/23/2015,18:36,10.0378
+4/23/2015,18:37,8.58649
+4/23/2015,18:38,7.06807
+4/23/2015,18:39,5.69721
+4/23/2015,18:40,4.57719
+4/23/2015,18:41,3.64509
+4/23/2015,18:42,2.90099
+4/23/2015,18:43,2.34398
+4/23/2015,18:44,1.71637
+4/23/2015,18:45,1.24640
+4/23/2015,18:46,1.04925
+4/23/2015,18:47,3.26074
+4/23/2015,18:48,2.97559

File diff suppressed because it is too large
+ 41 - 0
imc/exprs/date2025/6_varying_power/draw_graph_expr_6.ipynb


+ 350 - 0
imc/exprs/date2025/6_varying_power/draw_graph_expr_6.py

@@ -0,0 +1,350 @@
+import pickle
+import os
+import pandas as pd
+import seaborn as sns
+import matplotlib.pyplot as plt
+import matplotlib.ticker
+from scipy import stats
+import numpy as np
+
+import plot_utils
+import run_expr_6
+
+config_order = ["counter", "unroll", "adaptive"]  
+bench_order = ["fft", "basicmath", "crc", "sha", "stringsearch", "aes", "conv2d", "matmul"]
+
+def validate_and_cleanup_df(df: pd.DataFrame):
+
+    # mask = df["is_correct"] == False
+    # if mask.any():
+    #     print(f"drop {mask.sum()} rows with incorrect output")
+    # df = df[~mask].copy()
+    # assert(df["is_correct"].all())
+    
+    # bench_name = df.iloc[0,0]
+    # z_score = stats.zscore(df["time_taken"])
+    # mask2 = np.abs(z_score) > 4.35
+    # if mask2.any():
+    #     print(f"({bench_name}) remove {mask2.sum()} outliers")
+    #     time = float(df[mask2]["time_taken"].iloc[0])
+    #     average = df["time_taken"].mean()
+    #     print(f"time: {time:.2f}, average: {average:.2f}")
+
+    # df = df[~mask2].copy()
+
+    if df.empty:
+        return df
+
+    def rename_bench_name(row):
+        return row["bench_name"].lower()[1:]
+
+    df["bench_name"] = df.apply(rename_bench_name, axis=1)
+
+    def process_stats(row):
+        lines = row["stats"]
+        result = {}
+        try:
+            for line in lines:
+                key, val = line.split(":")
+                val = int(val.strip())
+                if key.startswith("checkpoint triggered"):
+                    result["ckpt_trig"] = val
+                if key.startswith("checkpoint executed"):
+                    result["ckpt_exec"] = val
+                if key.startswith("no forward progress"):
+                    result["no_forward_progress"] = int(val)
+        except:
+            result["ckpt_trig"] = -2
+            result["ckpt_exec"] = -2
+            result["no_forward_progress"] = -2
+        return result
+
+    df_stats = df.apply(process_stats, axis=1, result_type="expand")
+    df = pd.concat([df, df_stats], axis=1)
+
+    drop_columns = [
+        # "start",
+        # "end",
+        "recovery",
+        "outputs",
+        "stats",
+        # "ckpt",
+        # "VC",
+        # "PC",
+        "is_correct"
+    ]
+    df = df.drop(columns = drop_columns) 
+    return df
+
+
+def get_base_df(benchmark, configs):
+    output_dir = "/home/ybkim/workspace/imc/imc_freertos_app_m33/imc/exprs/date2025/6_varying_power/output"
+
+    all_dfs = []
+    for config in configs:
+        pickle_filename = f"{output_dir}/{config}/{benchmark}.pickle"
+
+        with open(pickle_filename, "rb") as f:
+            orig_df = pickle.load(f)
+            df = validate_and_cleanup_df(orig_df)
+        df["config"] = config
+        all_dfs.append(df)
+
+    orig_df = pd.concat(all_dfs)
+
+    def rename_config(row):
+        name = row["config"]
+        d = {
+            "adaptive": "adaptive",
+            "pass_count": "counter",
+            "unroll": "unroll"
+        }
+        return d[name]
+    orig_df["config"] = orig_df.apply(rename_config, axis=1)
+
+    return orig_df
+
+
+def remove_error_stats(orig_df):
+    mask = orig_df["ckpt_trig"].abs() > 1e5 
+    df = orig_df[~mask]
+    mask = df["ckpt_exec"].abs() > 1e6
+    df = df[~mask]
+    mask = df["ckpt_trig"] < 0
+    df = df[~mask]
+    mask = df["ckpt_exec"] < 0
+    df = df[~mask]
+    return df
+
+
+def add_secondary_power_graph(ax, wait_time):
+    # ax2 = ax.twinx()
+    power_data = "data/2015-04-23-Sacramento.csv"
+    power_data = "data/2015-04-22-Sacramento.csv"
+    power_df = run_expr_6.parse_energy_trace_nrel(power_data)
+    df = power_df.reset_index()
+    df["index"] = df["index"] * wait_time
+    df = df.rename(columns={
+        "Global Horizontal [W/m^2]": "current (mA)"
+    })
+
+    g = sns.lineplot(
+        df,
+        x="index",
+        y="current (mA)",
+        color="dimgray",
+        linewidth = 0,
+        alpha=0,
+        ax=ax,
+    )
+    ax.fill_between(df["index"], df["current (mA)"], alpha=0.1)
+    ax.grid(False)
+    ax.set_ylabel("Current (mA)")
+    return ax
+
+
+def draw_graph(benchmark="vSha"):
+    configs = ["adaptive"]
+    orig_df = get_base_df(benchmark, configs)
+    # orig_df = remove_error_stats(orig_df)
+
+    wait_time = orig_df["wait_time"].unique()[0]
+    # wait_time = 1
+
+    start_time = orig_df.iloc[0]["start"]
+    start_time = orig_df.attrs["start_time"]
+    df = orig_df.copy()
+    df["time_passed"] = orig_df["end"] - start_time
+    drop_columns = ["start", "end", "time_taken", "debug_outputs", "wait_time", "config"]
+    df = df.drop(columns=drop_columns)
+
+    fig_size = (12, 3)
+    n_rows = 1
+    n_cols = 1
+    hspace = 0.05
+    fig = plt.figure(figsize=fig_size)
+    ax = fig.subplots(n_rows, n_cols, squeeze=True, sharex=True, gridspec_kw={"hspace": hspace})
+
+    linewidth = 1.8
+
+    df2 = df.melt(id_vars=["bench_name", "time_passed"], value_vars=["ckpt_trig", "ckpt_exec"])
+    mask = df["no_forward_progress"] > 0
+    # display(df)
+    print(df[mask])
+
+    plot_utils.set_theme_seaborn(kind="line")
+    sns.lineplot(
+        df,
+        x="time_passed",
+        y="ckpt_trig",
+        marker="x",
+        markeredgecolor="tomato",
+        color="tomato",
+        markersize=0,
+        markeredgewidth=1.5,
+        linewidth = linewidth,
+        # hue="config",
+        ax=ax
+    )
+    ax.set_ylim([-10, 1000])
+    ax.set_xlabel("Time (s)")
+    ax.set_ylabel("Ckpt tirggered")
+    ax.set_title("")
+
+    add_secondary_power_graph(ax.twinx(), wait_time)
+    return fig
+
+def draw_completeions(benchmark="vSha"):
+    configs = [
+        "adaptive",
+        "pass_count",
+        "unroll"
+    ]
+    orig_df = get_base_df(benchmark, configs)
+    # orig_df = remove_error_stats(orig_df)
+    wait_time = orig_df["wait_time"].unique()[0]
+
+    start_time = orig_df.iloc[0]["start"]
+    df = orig_df.copy()
+    df["time_passed"] = orig_df["end"] - start_time
+    # drop_columns = ["start", "end", "time_taken", "wait_time", "ckpt_trig", "ckpt_exec", "bench_name"]
+    # df = df.drop(columns=drop_columns)
+    start_times = {}
+    for config in configs:
+        start_time = get_base_df(benchmark, [config]).attrs["start_time"]
+        key = config if config != "pass_count" else "counter"
+        start_times[key] = start_time
+
+    def count_mapper(d):
+        start_time = d.iloc[0]["start"]
+        config = d["config"].unique()[0]
+        start_time = start_times[config]
+        d["time_passed"] = d["end"] - start_time
+        total_finished = len(d)
+        d["finished"] = list(range(1, total_finished+1))
+        return d
+    df = df.groupby(["config"], as_index=False).apply(count_mapper)
+
+    fig_size = (8, 4)
+    n_rows = 1
+    n_cols = 1
+    hspace = 0.05
+    fig = plt.figure(figsize=fig_size)
+    ax = fig.subplots(n_rows, n_cols, squeeze=True, sharex=True, gridspec_kw={"hspace": hspace})
+
+    linewidth = 1.8
+    plot_utils.set_theme_seaborn(kind="line")
+    g = sns.lineplot(
+        df,
+        x="time_passed",
+        y="finished",
+        # marker="x",
+        # markeredgecolor="none",
+        # markers=["x", "x", "x"],
+        # markersize=6,
+        # markeredgewidth=1.5,
+        linewidth = linewidth,
+        hue="config",
+        # style="config",
+        # dashes=False,
+        hue_order=["counter", "unroll", "adaptive"],
+        # legend_labels=["counter", "unroll", "FastTrack"],
+        ax=ax
+    )
+
+    colors = {
+        "counter": "dimgray",
+        "unroll": "cornflowerblue",
+        "adaptive": "tomato"
+    }
+
+
+    num_finished = {}
+
+    for key, d in df.groupby("config"):
+        key_color = colors[key]
+        sns.scatterplot(
+            d,
+            x="time_passed",
+            y="finished",
+            marker="x",
+            color=key_color,
+            s=8,
+            legend=False,
+            linewidth=0.5,
+            ax=ax
+        )
+        num_finished[key] = len(d)
+    
+    print("number of finished tasks:")
+    print(num_finished)
+    print("ratio to adaptive:")
+    print("counter:", num_finished["adaptive"]/num_finished["counter"])
+    print("unroll:", num_finished["adaptive"]/num_finished["unroll"])
+
+    for key, d in df.groupby("config"):
+        mask = d["time_passed"] < 200
+        columns = ["time_passed", "finished"]
+        d2 = d[mask]
+        print(key)
+        # print(d2[columns].tail(1))
+        finished = len(d2)
+        rate = finished / 200
+        print("finished during 0~200 secs:", finished, rate)
+
+        mask = (d["time_passed"] >= 300) & (d["time_passed"] < 500)
+        d2 = d[mask]
+        finished = len(d2)
+        rate = finished / 200
+        print("finished during 300~500 secs:", finished, rate)
+    
+
+    # ax.set_ylim([-50, 1000])
+    ax.legend(ncol=3, loc="upper center", bbox_to_anchor=(0.5, 1.4), labelspacing=0.2)
+    ax.set_xlabel("Time (s)")
+    ax.set_ylabel("Finished Tasks")
+    add_secondary_power_graph(ax.twinx(), wait_time)
+    
+    legend_labels = ["counter", "unroll", "FastTrack"]
+    for t in ax.get_legend().get_texts():
+        if t.get_text() == "adaptive":
+            t.set_text("FastTrack")
+
+    return fig
+
+
+def draw_power_trace():
+    ratio = 0.9
+    fig_width = 4.5
+    fig_size = (fig_width, fig_width * ratio)
+    n_rows = 1
+    n_cols = 1
+    hspace = 0.05
+    fig = plt.figure(figsize=fig_size)
+    ax = fig.subplots(n_rows, n_cols, squeeze=True, sharex=True, gridspec_kw={"hspace": hspace})
+
+    power_data = "data/2015-04-23-Sacramento.csv"
+    power_data = "data/2015-04-22-Sacramento.csv"
+    power_df = run_expr_6.parse_energy_trace_nrel(power_data, include_datetime=True)
+    df = power_df.reset_index()
+    df = df.rename(columns={
+        "Global Horizontal [W/m^2]": "current (mA)"
+    })
+
+    print(df)
+
+    sns.lineplot(
+        df,
+        x="PST",
+        y="current (mA)",
+        color="dimgray",
+        linewidth = 1,
+        ax=ax,
+    )
+    ax.grid(True)
+    ax.set_ylabel("Current (mA)")
+    ax.set_xlabel("Time")
+    ax.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(3))
+    ax.yaxis.grid(visible=True, which="both")
+    ax.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(4))
+    return fig

+ 198 - 0
imc/exprs/date2025/6_varying_power/run_expr_6.py

@@ -0,0 +1,198 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+import os
+import subprocess
+import pprint
+import threading
+from multiprocessing.pool import ThreadPool
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def get_build_config(benchmark, config_name):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+    bench_repeat_count = config.bench_repeat_count_small[benchmark]
+    config.bench_repeat_count = bench_repeat_count
+
+    if config_name == "original":
+        config.insert_compiler_checkpoints = False
+
+    if config_name == "pass_count":
+        config.use_checkpoint_pass_counter = True
+        config.checkpoint_pass_count = config.pass_count_10ms[benchmark]
+
+    if config_name == "adaptive":
+        config.use_checkpoint_voltage_check = True
+        config.split_loop = True
+        config.enable_adaptive_loop_pass_count = True
+        config.max_loop_ids = 20
+    
+    if config_name == "unroll":
+        config.use_checkpoint_voltage_check = True
+        config.custom_unroll = True
+
+    return config
+
+
+def parse_energy_trace_nrel(data_file, include_datetime=False):
+    df = pd.read_csv(data_file)
+    power_col = df.columns[2]
+    trace_mA = df[power_col] * 1000
+
+    target_panel_size_m2 = 0.0001 #10cm * 10cm
+    target_panel_size_m2 = 0.00013 #1cm * 1cm
+    trace_mA = trace_mA * target_panel_size_m2
+
+    target_input_voltage = 3.3
+    trace_mA = trace_mA / target_input_voltage
+
+    early = trace_mA[0:200]
+    inc1 = trace_mA[200:300]
+    high = trace_mA[300:500]
+    dec1 = trace_mA[500:600]
+    late = trace_mA[600:800]
+
+    if include_datetime:
+        df["Global Horizontal [W/m^2]"] = trace_mA
+        ret = df
+    else:
+        ret = trace_mA
+    # ret = inc1
+
+    return ret
+
+
+def simulate_current(smu, wait_s, trace_mA):
+    for i, curr in enumerate(trace_mA):
+        # pps.set_current(curr / 1000, 1)
+        smu.set_current_limit(curr/1000)
+        time.sleep(wait_s)
+        print(f"Set current to {curr:.3f}mA ({i+1}/{len(trace_mA)})")
+
+
+def watcher_thread_impl(watcher):
+    records = watcher.run()
+    return records
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=3.3)
+    config = get_default_build_config()
+    wait_s = 1
+
+    data_file = "data/2015-04-23-Sacramento.csv"
+    data_file = "data/2015-04-22-Sacramento.csv"
+    trace_mA = parse_energy_trace_nrel(data_file)
+
+    benchmarks = [
+        "vBasicMath",
+        "vCrc",
+        "vFFT",
+        "vSha",
+        "vStringSearch",
+        "vMatMul",
+        "vConv2d",
+        "vAes",
+    ]
+    benchmarks = [
+        # "vCrc",
+        # "vSha",
+        "vFFT",
+    ]
+
+    configs = ["pass_count", "adaptive", "unroll"]
+    configs = ["adaptive"]
+
+    for benchmark in benchmarks:
+        for config_name in configs:
+            all_records = []
+            config = get_build_config(benchmark, config_name)
+
+            env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+            # pps.set_voltage(3.3, 1)
+            # pps.set_current(0.1, 1)
+            # pps.output_on(1)
+            smu.set_current_limit(0.1)
+            smu.power_on()
+
+            with tempfile.TemporaryDirectory() as build_dir:
+                binary = env.build_binary(config, build_dir)
+                env.clear_nvm_and_load_binary(binary, resume=False)
+
+            # pps.set_current(0, 1)
+            smu.set_current_limit(0)
+            time.sleep(2)
+
+            watcher_pool = ThreadPool(processes=1)
+            watcher = SerialWatcher(benchmark, 9999)
+            result = watcher_pool.apply_async(watcher_thread_impl, (watcher,))
+            watcher_pool.close()
+
+            start_time = time.time()
+            env.resume_board(terminate=True)
+
+            args = (smu, wait_s, trace_mA)
+            simulate_thread = threading.Thread(target=simulate_current, args=args)
+            simulate_thread.start()
+
+            simulate_thread.join()
+            print("simulation thread finished")
+            watcher.stop_signal = True
+            watcher_pool.join()
+            print(result)
+
+            records = result.get()
+            print(records)
+            
+            for record in records:
+                record.update({
+                    "wait_time": wait_s,
+                    # "expr_start_time": start_time,
+                })
+                all_records.append(record)
+
+            df = pd.DataFrame(all_records)
+            df.attrs["start_time"] = start_time
+            print(df)
+            save_records(benchmark, config_name, df)
+    
+    # pps.output_off(1)
+    smu.power_off()
+
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = True
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = True
+    config.custom_unroll = False
+    return config
+
+
+def save_records(bench_name, config_name, df):
+    with open(f"output/{config_name}/{bench_name}.pickle", "wb") as f:
+        pickle.dump(df, f)
+
+
+if __name__ == "__main__":
+    main()

File diff suppressed because it is too large
+ 62 - 0
imc/exprs/date2025/7_latency_overhead/draw_graph_7.ipynb


+ 123 - 0
imc/exprs/date2025/7_latency_overhead/draw_graph_7.py

@@ -0,0 +1,123 @@
+import pandas as pd
+import pickle
+import seaborn as sns
+import matplotlib.pyplot as plt
+import matplotlib
+import plot_utils
+
+def draw_graph():
+    benchmarks = [
+        "vBasicMath",
+        "vCrc",
+        "vFFT",
+        "vSha",
+        "vStringSearch",
+        "vMatMul",
+        "vConv2d",
+        "vAes",
+    ]
+    rows = []
+    for benchmark in benchmarks:
+        try:
+            with open(f"output/adaptive/{benchmark}.pickle", "rb") as f:
+                df = pickle.load(f)
+        except:
+            continue
+
+        columns = ["bench_name", "init", "getCSC", "adjust", "total cycles"]
+        df = df[columns]
+
+        df["init (%)"] = df["init"] / df["total cycles"] * 100
+        df["getCSC (%)"] = df["getCSC"] / df["total cycles"] * 100
+        df["adjust (%)"] = df["adjust"] / df["total cycles"] * 100
+
+        columns = ["bench_name", "init (%)", "getCSC (%)", "adjust (%)"]
+
+        df = df[columns]
+        converge_index = 4
+        columns = ["init (%)", "getCSC (%)", "adjust (%)"]
+        row = df.loc[0:converge_index][columns].mean()
+        row["converged"] = False
+        row["benchmark"] = benchmark[1:].lower()
+        rows.append(row)
+
+        row = df.loc[converge_index:][columns].mean()
+        row["converged"] = True
+        row["benchmark"] = benchmark[1:].lower()
+        rows.append(row)
+
+    df = pd.DataFrame(rows)
+    df = df.sort_values(by=["benchmark", "converged"])
+    df = df[["benchmark", "converged", "init (%)", "getCSC (%)", "adjust (%)"]]
+
+    print(df[df["converged"] == False][columns].mean())
+    print(df[df["converged"] == True][columns].mean())
+
+    plot_utils.set_theme_seaborn()
+
+    bench_order = ["fft", "basicmath", "crc", "sha", "stringsearch", "aes", "conv2d", "matmul"]
+
+    df = df.drop(columns=["init (%)"])
+    df = df.rename(
+        columns={
+            "getCSC (%)": "csc",
+            "adjust (%)": "adjust",
+        }
+    )
+
+    df = df.pivot(
+        index="benchmark",
+        columns=["converged"],
+    )
+
+    df["adjust", False] += df["csc", False]
+    df["adjust", True] += df["csc", True]
+
+    df = df.stack(level="converged")
+    df = df.reset_index(level="converged")
+
+    print(df)
+
+    fig, ax = plt.subplots(figsize=(12, 3.5))
+
+    sns.barplot(
+        data=df,
+        x="benchmark",
+        y="adjust",
+        hue="converged",
+        order=bench_order,
+        ax=ax,
+    )
+
+    for bar in ax.patches:
+        bar.set_hatch("///")
+
+    sns.barplot(
+        data=df,
+        x="benchmark",
+        y="csc",
+        hue="converged",
+        order=bench_order,
+        ax=ax
+    )
+
+    labels = [
+        "adjust",
+        "adjust",
+        "getCSC (run #1~5)",
+        "getCSC (run #5~20)",
+    ]
+
+    new_labels = ["Before convergence (run 1~5)", "After convergence (run 6~20)"]
+
+    handles, previous_labels = ax.get_legend_handles_labels()
+    new_handles = [handles[2], handles[3]]
+    ax.legend(handles=new_handles, labels=new_labels, ncols=1, columnspacing=0.8)
+
+    ax.set_ylabel("Overhead (%)")
+    ax.set_xlabel("Benchmark")
+    ax.get_yaxis().set_minor_locator(matplotlib.ticker.AutoMinorLocator())
+    ax.grid(visible=True, which="both", axis="y")
+    ax.tick_params(left=True, length=8, width=2)
+
+    return fig

+ 111 - 0
imc/exprs/date2025/7_latency_overhead/run_expr_7.py

@@ -0,0 +1,111 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+import os
+import subprocess
+import pprint
+import threading
+from multiprocessing.pool import ThreadPool
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+def get_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    bench_repeat_count = config.bench_repeat_count_small[benchmark]
+    config.bench_repeat_count = bench_repeat_count
+
+    config.insert_compiler_checkpoints = True
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = True
+    config.print_recovery_message = True
+    config.split_loop = True
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = True
+    config.max_loop_ids = 15
+    config.print_stats = False
+    config.custom_unroll = False
+    config.print_latency_overhead = True
+    return config
+
+def main():
+
+    pps = PPS_E36311A()
+
+    target_current_limit = 0.015
+    total_iterations = 20
+
+    benchmarks = [
+        "vBasicMath",
+        "vCrc",
+        "vFFT",
+        "vSha",
+        "vStringSearch",
+        "vMatMul",
+        "vConv2d",
+        "vAes",
+    ]
+
+    # benchmarks = ["vFFT"]
+
+    for benchmark in benchmarks:
+        config = get_build_config(benchmark)
+        env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+        pps.set_voltage(3.3, 1)
+        pps.set_current(0.1, 1)
+        pps.output_on(1)
+
+        with tempfile.TemporaryDirectory() as build_dir:
+            binary = env.build_binary(config, build_dir)
+            env.clear_nvm_and_load_binary(binary, resume=False)
+        
+        pps.set_current(target_current_limit, 1)
+        time.sleep(1)
+
+        env.resume_board(terminate=True)
+        watcher = SerialWatcher(benchmark, total_iterations)
+        records = watcher.run()
+
+        all_records = []
+        for record in records:
+            stats = record["stats"]
+            for line in stats:
+                key, val = line.split(":")
+                val = int(val.strip())
+                key = key.strip()
+                record[key] = val
+            all_records.append(record)
+        
+        df = pd.DataFrame(all_records)
+        rename_columns = {
+            "cycles in init()": "init",
+            "cycles in getCSC()": "getCSC",
+            "cycles in adjust()": "adjust",
+        }
+        df = df.rename(columns=rename_columns)
+        columns = ["bench_name", "init", "getCSC", "adjust", "total cycles"]
+        print(df[columns])
+        save_records(benchmark, "adaptive", df)
+        
+    pps.output_off(1)
+
+
+def save_records(bench_name, config_name, df):
+    with open(f"output/{config_name}/{bench_name}.pickle", "wb") as f:
+        pickle.dump(df, f)
+
+
+
+if __name__ == "__main__":
+    main()

+ 13 - 0
imc/exprs/etc/measure_init_time/measure_init_time.py

@@ -0,0 +1,13 @@
+import time
+
+from imc_utils.pps_e36311a import PPS_E36311A
+
+pps = PPS_E36311A()
+wait_ms = 400
+pps.set_voltage(0, 1)
+pps.set_current(0.1, 1)
+pps.output_on(1)
+
+pps.set_voltage(3.3, 1)
+time.sleep(wait_ms / 1000)
+pps.set_voltage(0, 1)

File diff suppressed because it is too large
+ 28 - 0
imc/exprs/etc/test/scope_test.ipynb


+ 17 - 0
imc/exprs/etc/test/scope_test.py

@@ -0,0 +1,17 @@
+from imc_utils.oscilloscope_dsox1204a import DSOX1204A
+
+scope = DSOX1204A()
+r = scope.handle.ask("*IDN?")
+print(r)
+
+scope.handle.write(":TRIG:MODE EDGE")
+scope.handle.write(":TRIG:EDGE:SOUR CHAN3")
+scope.handle.write(":TRIG:EDGE:LEV 3")
+scope.handle.write(":TRIG:EDGE:SLOP POSitive")
+
+scope.handle.write(":CHAN3:SCALe 1")
+scope.handle.write(":SINGle")
+scope.handle.write(":WAVeform:SOURce CHAN3")
+scope.handle.write(":WAVeform:FORMat ASCii")
+r = scope.handle.ask(":WAVeform:DATA?")
+print(len(r))

+ 12 - 0
imc/reports/2024_ktl/draw_graph_test_1.py

@@ -0,0 +1,12 @@
+import pickle
+import pandas as pd
+
+def draw_graph(pickle_name):
+    with open(f"output/{pickle_name}.pickle", "rb") as f:
+        df = pickle.load(f)
+    currs = df
+    currs.plot()
+    mask = currs > 0.01
+    active = currs[mask]
+    secs = len(active) / 1000
+    print(f"time: {secs} s")

File diff suppressed because it is too large
+ 29 - 0
imc/reports/2024_ktl/test_1.ipynb


+ 143 - 0
imc/reports/2024_ktl/test_1.py

@@ -0,0 +1,143 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+import subprocess
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config(benchmark)
+
+    print("\n===== A. measure original program =====\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current, repeat=2)
+    with open(f"output/test_1_{benchmark}_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config(benchmark)
+    config.insert_compiler_checkpoints = False
+    config.use_checkpoint_pass_counter = False
+    config.split_loop = False
+    config.enable_adaptive_loop_pass_count = False
+    config.use_checkpoint_voltage_check = False
+    config.max_loop_ids = 15
+    config.enable_dynamic_checkpoint = True
+
+    print("\n===== B. measure checkpoint-instrumented program =====\n")
+    target_current = 0.014
+    # target_current = 0.1
+    wait_s = 1
+    currs = measure(config, pps, smu, target_current, repeat=5, wait_before_start_s=wait_s)
+    with open(f"output/test_1_{benchmark}_ckpt.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current, repeat=1, wait_before_start_s=0):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, repeat)
+
+    if wait_before_start_s > 0:
+        print(f" > wait for {wait_before_start_s} secs")
+        time.sleep(wait_before_start_s)
+        env.resume_board(terminate=True, verbose=False)
+
+    print(" > start measuring\n")
+    smu.start_measure()
+    if wait_before_start_s == 0:
+        env.resume_board(terminate=True, verbose=False)
+    records = watcher.run()
+    smu.stop_measure_only()
+    result = smu.fetch_curr()
+    print("\n > measure finished")
+    currs = pd.DataFrame(result)[0]
+    return currs
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.setup_sense()
+    smu.set_current_limit(0.1)
+
+    # benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    # benchmarks = ["vCrc"]
+
+    benchmarks = ["vFFT", "vCrc", "vBasicMath", "vSha"]
+    total = len(benchmarks)
+    for i, benchmark in enumerate(benchmarks):
+        print(f"\n+++ ({i+1}/{total}) {benchmark} +++")
+        measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print(" > build and program binary")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir, redirect_file=subprocess.DEVNULL)
+        env.clear_nvm_and_load_binary(binary, resume=False, verbose=False)
+    
+    print(" > program finished")
+    
+    return env
+
+
+def get_bench_repeat_count(benchmark):
+    d = {
+        "vFFT": 50,
+        "vConv2d": 15000,
+        "vCrc": 5000,
+        "vBasicMath": 2,
+        "vSha": 200,
+        "vStringSearch": 3000,
+        "vAes": 6000,
+        "vMatMul": 20000,
+    }
+    return d[benchmark]
+    
+
+def get_default_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.enable_dynamic_checkpoint = False
+    config.bench_repeat_count = get_bench_repeat_count(benchmark)
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 52 - 0
imc/reports/2024_ktl/test_1_analysis.py

@@ -0,0 +1,52 @@
+import pickle
+import pandas as pd
+
+
+def get_average_active_secs(df, repeat=1):
+    mask = (df > 0.005) & (df < 0.020)
+    active = df[mask]
+    secs = len(active) / 1000
+    return secs / repeat
+
+
+def analyze_benchmark(benchmark):
+    with open(f"output/test_1_{benchmark}_original.pickle", "rb") as f:
+        d1 = pickle.load(f)
+
+    with open(f"output/test_1_{benchmark}_ckpt.pickle", "rb") as f:
+        d2 = pickle.load(f)
+    
+    avg_orig = get_average_active_secs(d1, 2)
+    avg_ckpt = get_average_active_secs(d2, 5)
+    return avg_orig, avg_ckpt
+
+
+def do_analysis(benchmarks):
+    results = []
+    for benchmark in benchmarks:
+        try:
+            avg_orig, avg_ckpt = analyze_benchmark(benchmark)
+        except:
+            continue
+        results.append({
+            "benchmark": benchmark,
+            "original (s)": avg_orig,
+            "ckpt (s)": avg_ckpt,
+            "overhead (%)": ((avg_ckpt / avg_orig) - 1) * 100,
+        })
+    d = pd.DataFrame(results)
+    print(d)
+
+    avg_overhead = d["overhead (%)"].mean()
+
+    print(f"average overhead: {avg_overhead:.2f}%")
+
+
+def main():
+    benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    benchmarks = ["vFFT", "vCrc", "vBasicMath", "vSha"]
+    do_analysis(benchmarks)
+
+
+if __name__ == "__main__":
+    main()

+ 111 - 0
imc/reports/2024_ktl/test_1_current_measure.py

@@ -0,0 +1,111 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+
+    print("\n\n===== measure original program =====\n\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current)
+    with open("output/test_1_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = True
+    config.split_loop = True
+    config.enable_adaptive_loop_pass_count = True
+    config.use_checkpoint_voltage_check = True
+    config.max_loop_ids = 15
+
+    target_current = 0.02
+    currs = measure(config, pps, smu, target_current)
+    with open("output/test_1_ckpt.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, 1)
+    print("\n\n===== start measuring =====\n\n")
+    smu.start_measure()
+    env.resume_board(terminate=True)
+    records = watcher.run()
+    result = smu.stop_measure()
+    print("\n\n===== measure finished =====\n\n")
+    print(records)
+
+    currs = pd.DataFrame(result)[0]
+    return currs
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT"]
+    for benchmark in benchmarks:
+        measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print("\n===== build and program binary =====\n")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=False)
+    
+    print("\n===== program finished =====\n")
+    
+    return env
+    
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.bench_repeat_count = 100
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 122 - 0
imc/reports/2024_ktl/test_2.py

@@ -0,0 +1,122 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+
+    print("\n\n===== measure original program =====\n\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current)
+    # with open("output/test_1_original.pickle", "wb") as f:
+    #     pickle.dump(currs, f)
+
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = True
+    config.split_loop = True
+    config.enable_adaptive_loop_pass_count = True
+    config.use_checkpoint_voltage_check = True
+    config.max_loop_ids = 15
+
+    target_current = 0.02
+    records = measure(config, pps, smu, target_current)
+    mask = records["time_taken"] < 1
+    n_total = len(records)
+    n_passed = len(records[mask])
+    print(f"{n_passed}/{n_total} passed SLA (1s)")
+
+    # with open("output/test_1_ckpt.pickle", "wb") as f:
+    #     pickle.dump(currs, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current):
+    env = program_with_config(config, pps, smu)
+
+    target_iterations = 10
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, target_iterations)
+    print("\n\n===== start measuring =====\n\n")
+    # smu.start_measure()
+    env.resume_board(terminate=True)
+    records = watcher.run()
+    # result = smu.stop_measure()
+    print("\n\n===== measure finished =====\n\n")
+    records = pd.DataFrame(records)
+    columns = ["bench_name", "time_taken", "outputs", "is_correct"]
+    print(records[columns])
+    return records
+
+    # currs = pd.DataFrame(result)[0]
+    # return currs
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT"]
+    for benchmark in benchmarks:
+        # measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+    
+    smu.power_off()
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print("\n===== build and program binary =====\n")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=False)
+    
+    print("\n===== program finished =====\n")
+    
+    return env
+    
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.bench_repeat_count = 10
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 70 - 0
imc/reports/2024_ktl/test_2_analysis.py

@@ -0,0 +1,70 @@
+import pickle
+import pandas as pd
+
+
+def get_average_active_secs(df, repeat=1):
+    mask = (df > 0.005) & (df < 0.020)
+    active = df[mask]
+    secs = len(active) / 1000
+    return secs / repeat
+
+
+def analyze_benchmark(benchmark):
+    with open(f"output/test_2_{benchmark}_ckpt.pickle", "rb") as f:
+        d = pickle.load(f)
+    
+    d = d.sort_values(by=["time_taken"], ascending=False)
+    columns = ["bench_name", "time_taken", "outputs", "is_correct"]
+
+
+    sla_values = {
+        "vFFT": 1.42,
+        "vCrc": 1.48,
+        "vAes": 1.35,
+        "vSha": 1.66,
+    }
+    sla = sla_values[benchmark]
+
+    print(f"\n+++ benchmark {benchmark} +++")
+    print(f"SLA: {sla}")
+    print(d[columns])
+
+    mask = d["time_taken"] < sla
+    n_total = len(d)
+    n_passed = len(d[mask])
+    print("")
+    print(f"{n_passed} passed (total {n_total})")
+    return n_total, n_passed
+
+
+def do_analysis(benchmarks):
+    results = []
+    for benchmark in benchmarks:
+        try:
+            n_total, n_passed = analyze_benchmark(benchmark)
+        except:
+            continue
+        results.append({
+            "benchmark": benchmark,
+            "total": n_total,
+            "passed": n_passed,
+            "pass rate (%)": (n_passed / n_total) * 100,
+        })
+    d = pd.DataFrame(results)
+
+    avg_pass_rate = d["pass rate (%)"].mean()
+
+    print("\n\n+++ summary +++\n")
+    print(d)
+    print("")
+    print(f"average pass rate: {avg_pass_rate:.2f}%")
+
+
+def main():
+    benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    do_analysis(benchmarks)
+
+
+if __name__ == "__main__":
+    main()

+ 141 - 0
imc/reports/2024_ktl/test_2_new.py

@@ -0,0 +1,141 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+import subprocess
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config(benchmark)
+
+    print("\n===== A. measure original program =====\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current, repeat=2)
+    with open(f"output/test_1_{benchmark}_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config(benchmark)
+    config.insert_compiler_checkpoints = False
+    config.use_checkpoint_pass_counter = False
+    config.split_loop = False
+    config.enable_adaptive_loop_pass_count = False
+    config.use_checkpoint_voltage_check = False
+    config.max_loop_ids = 15
+    config.enable_dynamic_checkpoint = True
+
+    # print("\n===== B. measure checkpoint-instrumented program =====\n")
+    target_current = 0.015
+    wait_s = 3
+    repeat = 200
+    records = measure(config, pps, smu, target_current, repeat=repeat, wait_before_start_s=wait_s)
+    records = pd.DataFrame(records)
+    columns = ["bench_name", "time_taken", "outputs", "is_correct"]
+    print(records[columns])
+    with open(f"output/test_2_{benchmark}_ckpt.pickle", "wb") as f:
+        pickle.dump(records, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current, repeat=1, wait_before_start_s=0):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, repeat)
+
+    if wait_before_start_s > 0:
+        print(f" > wait for {wait_before_start_s} secs")
+        time.sleep(wait_before_start_s)
+        env.resume_board(terminate=True, verbose=False)
+
+    print(" > start measuring\n")
+    if wait_before_start_s == 0:
+        env.resume_board(terminate=True, verbose=False)
+    records = watcher.run()
+    print("\n > measure finished")
+    return records
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.setup_sense()
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    benchmarks = ["vSha"]
+
+    total = len(benchmarks)
+    for i, benchmark in enumerate(benchmarks):
+        print(f"\n+++ ({i+1}/{total}) {benchmark} +++")
+        # measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print(" > build and program binary")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir, redirect_file=subprocess.DEVNULL)
+        env.clear_nvm_and_load_binary(binary, resume=False, verbose=False)
+    
+    print(" > program finished")
+    
+    return env
+
+
+def get_bench_repeat_count(benchmark):
+    d = {
+        "vFFT": 10,
+        "vConv2d": 15000,
+        "vCrc": 1000,
+        "vBasicMath": 1,
+        "vSha": 40,
+        "vStringSearch": 3000,
+        "vAes": 1300,
+        "vMatMul": 20000,
+    }
+    return d[benchmark]
+    
+
+def get_default_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.enable_dynamic_checkpoint = False
+    config.bench_repeat_count = get_bench_repeat_count(benchmark)
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 134 - 0
imc/reports/2024_ktl/test_3.py

@@ -0,0 +1,134 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+
+    print("\n\n===== measure original program =====\n\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current)
+    # with open("output/test_1_original.pickle", "wb") as f:
+    #     pickle.dump(currs, f)
+
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = True
+    config.split_loop = True
+    config.enable_adaptive_loop_pass_count = True
+    config.use_checkpoint_voltage_check = True
+    config.max_loop_ids = 15
+
+    target_current = 0.02
+    records = measure(config, pps, smu, target_current)
+
+    measured_init_times = []
+
+    for messages in records["debug_outputs"]:
+        for message in messages:
+            if message.startswith("cycle"):
+                cycle = message.split()[1]
+                cycle = int(cycle)
+                freq = 50 * 1000 * 1000
+                time = cycle / freq
+                measured_init_times.append(time)
+    
+    print("\nmeasured init times:")
+    print(measured_init_times)
+
+    # with open("output/test_1_ckpt.pickle", "wb") as f:
+    #     pickle.dump(currs, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current):
+    env = program_with_config(config, pps, smu)
+
+    target_iterations = 5
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, target_iterations)
+    print("\n\n===== start measuring =====\n\n")
+    # smu.start_measure()
+    env.resume_board(terminate=True)
+    records = watcher.run()
+    # result = smu.stop_measure()
+    print("\n\n===== measure finished =====\n\n")
+    records = pd.DataFrame(records)
+    columns = ["bench_name", "time_taken", "outputs", "debug_outputs", "is_correct"]
+    print(records[columns])
+    return records
+
+    # currs = pd.DataFrame(result)[0]
+    # return currs
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT"]
+    for benchmark in benchmarks:
+        # measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+    
+    smu.power_off()
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print("\n===== build and program binary =====\n")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir)
+        env.clear_nvm_and_load_binary(binary, resume=False)
+    
+    print("\n===== program finished =====\n")
+    
+    return env
+    
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.bench_repeat_count = 10
+    config.print_init_time = True
+    return config
+
+
+if __name__ == "__main__":
+    main()
+

+ 57 - 0
imc/reports/2024_ktl/test_3_analysis.py

@@ -0,0 +1,57 @@
+import pickle
+import pandas as pd
+
+
+def get_average_active_secs(df, repeat=1):
+    mask = (df > 0.005) & (df < 0.020)
+    active = df[mask]
+    secs = len(active) / 1000
+    return secs / repeat
+
+
+def analyze_benchmark(benchmark):
+    with open(f"output/test_3_{benchmark}_ckpt.pickle", "rb") as f:
+        d = pickle.load(f)
+    
+    measured_init_times = []
+
+    for messages in d["debug_outputs"]:
+        for message in messages:
+            if message.startswith("cycle"):
+                cycle = message.split()[1]
+                cycle = int(cycle)
+                freq = 10 * 1000 * 1000
+                time = cycle / freq
+                measured_init_times.append(time)
+    
+    return measured_init_times[0]
+
+
+def do_analysis(benchmarks):
+    results = []
+    for benchmark in benchmarks:
+        try:
+            init_time = analyze_benchmark(benchmark)
+        except:
+            continue
+        results.append({
+            "benchmark": benchmark,
+            "init time (s)": init_time,
+        })
+    d = pd.DataFrame(results)
+
+    avg_init_time = d["init time (s)"].mean()
+
+    print(d)
+    print("")
+    print(f"average init time: {avg_init_time:.5f} s")
+
+
+def main():
+    benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    do_analysis(benchmarks)
+
+
+if __name__ == "__main__":
+    main()

+ 144 - 0
imc/reports/2024_ktl/test_3_new.py

@@ -0,0 +1,144 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+import subprocess
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config(benchmark)
+
+    print("\n===== A. measure original program =====\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current, repeat=2)
+    with open(f"output/test_1_{benchmark}_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config(benchmark)
+    config.insert_compiler_checkpoints = False
+    config.use_checkpoint_pass_counter = False
+    config.split_loop = False
+    config.enable_adaptive_loop_pass_count = False
+    config.use_checkpoint_voltage_check = False
+    config.max_loop_ids = 15
+    config.enable_dynamic_checkpoint = True
+    config.print_init_time = True
+
+    # print("\n===== B. measure checkpoint-instrumented program =====\n")
+    target_current = 0.02
+    wait_s = 3
+    repeat = 1
+    records = measure(config, pps, smu, target_current, repeat=repeat, wait_before_start_s=wait_s)
+    records = pd.DataFrame(records)
+    with open(f"output/test_3_{benchmark}_ckpt.pickle", "wb") as f:
+        pickle.dump(records, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current, repeat=1, wait_before_start_s=0):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, 1)
+
+    wait_time = 5
+
+    print(" > start board execution")
+    env.resume_board(terminate=True, verbose=False)
+    print(f" > wait for {wait_before_start_s} secs")
+    time.sleep(wait_before_start_s)
+    print(" > power off")
+    pps.output_off(1)
+    print(f" > wait for {wait_time} secs")
+    time.sleep(wait_time)
+    print(" > power on\n")
+    pps.output_on(1)
+    records = watcher.run()
+    print("\n > measure finished")
+    return records
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.setup_sense()
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    # benchmarks = ["vFFT"]
+
+    total = len(benchmarks)
+    for i, benchmark in enumerate(benchmarks):
+        print(f"\n+++ ({i+1}/{total}) {benchmark} +++")
+        # measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print(" > build and program binary")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir, redirect_file=subprocess.DEVNULL)
+        env.clear_nvm_and_load_binary(binary, resume=False, verbose=False)
+    
+    print(" > program finished")
+    
+    return env
+
+
+def get_bench_repeat_count(benchmark):
+    d = {
+        "vFFT": 10,
+        "vConv2d": 15000,
+        "vCrc": 1000,
+        "vBasicMath": 1,
+        "vSha": 40,
+        "vStringSearch": 3000,
+        "vAes": 1300,
+        "vMatMul": 20000,
+    }
+    return d[benchmark]
+    
+
+def get_default_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.enable_dynamic_checkpoint = False
+    config.bench_repeat_count = get_bench_repeat_count(benchmark)
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 143 - 0
imc/reports/2024_ktl_export/test_1.py

@@ -0,0 +1,143 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+import subprocess
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config(benchmark)
+
+    print("\n===== A. measure original program =====\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current, repeat=2)
+    with open(f"output/test_1_{benchmark}_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config(benchmark)
+    config.insert_compiler_checkpoints = False
+    config.use_checkpoint_pass_counter = False
+    config.split_loop = False
+    config.enable_adaptive_loop_pass_count = False
+    config.use_checkpoint_voltage_check = False
+    config.max_loop_ids = 15
+    config.enable_dynamic_checkpoint = True
+
+    print("\n===== B. measure checkpoint-instrumented program =====\n")
+    target_current = 0.014
+    # target_current = 0.1
+    wait_s = 1
+    currs = measure(config, pps, smu, target_current, repeat=5, wait_before_start_s=wait_s)
+    with open(f"output/test_1_{benchmark}_ckpt.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current, repeat=1, wait_before_start_s=0):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, repeat)
+
+    if wait_before_start_s > 0:
+        print(f" > wait for {wait_before_start_s} secs")
+        time.sleep(wait_before_start_s)
+        env.resume_board(terminate=True, verbose=False)
+
+    print(" > start measuring\n")
+    smu.start_measure()
+    if wait_before_start_s == 0:
+        env.resume_board(terminate=True, verbose=False)
+    records = watcher.run()
+    smu.stop_measure_only()
+    result = smu.fetch_curr()
+    print("\n > measure finished")
+    currs = pd.DataFrame(result)[0]
+    return currs
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.setup_sense()
+    smu.set_current_limit(0.1)
+
+    # benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    # benchmarks = ["vCrc"]
+
+    benchmarks = ["vFFT", "vCrc", "vBasicMath", "vSha"]
+    total = len(benchmarks)
+    for i, benchmark in enumerate(benchmarks):
+        print(f"\n+++ ({i+1}/{total}) {benchmark} +++")
+        measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print(" > build and program binary")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir, redirect_file=subprocess.DEVNULL)
+        env.clear_nvm_and_load_binary(binary, resume=False, verbose=False)
+    
+    print(" > program finished")
+    
+    return env
+
+
+def get_bench_repeat_count(benchmark):
+    d = {
+        "vFFT": 50,
+        "vConv2d": 15000,
+        "vCrc": 5000,
+        "vBasicMath": 2,
+        "vSha": 200,
+        "vStringSearch": 3000,
+        "vAes": 6000,
+        "vMatMul": 20000,
+    }
+    return d[benchmark]
+    
+
+def get_default_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.enable_dynamic_checkpoint = False
+    config.bench_repeat_count = get_bench_repeat_count(benchmark)
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 52 - 0
imc/reports/2024_ktl_export/test_1_analysis.py

@@ -0,0 +1,52 @@
+import pickle
+import pandas as pd
+
+
+def get_average_active_secs(df, repeat=1):
+    mask = (df > 0.005) & (df < 0.020)
+    active = df[mask]
+    secs = len(active) / 1000
+    return secs / repeat
+
+
+def analyze_benchmark(benchmark):
+    with open(f"output/test_1_{benchmark}_original.pickle", "rb") as f:
+        d1 = pickle.load(f)
+
+    with open(f"output/test_1_{benchmark}_ckpt.pickle", "rb") as f:
+        d2 = pickle.load(f)
+    
+    avg_orig = get_average_active_secs(d1, 2)
+    avg_ckpt = get_average_active_secs(d2, 5)
+    return avg_orig, avg_ckpt
+
+
+def do_analysis(benchmarks):
+    results = []
+    for benchmark in benchmarks:
+        try:
+            avg_orig, avg_ckpt = analyze_benchmark(benchmark)
+        except:
+            continue
+        results.append({
+            "benchmark": benchmark,
+            "original (s)": avg_orig,
+            "ckpt (s)": avg_ckpt,
+            "overhead (%)": ((avg_ckpt / avg_orig) - 1) * 100,
+        })
+    d = pd.DataFrame(results)
+    print(d)
+
+    avg_overhead = d["overhead (%)"].mean()
+
+    print(f"average overhead: {avg_overhead:.2f}%")
+
+
+def main():
+    benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    benchmarks = ["vFFT", "vCrc", "vBasicMath", "vSha"]
+    do_analysis(benchmarks)
+
+
+if __name__ == "__main__":
+    main()

+ 144 - 0
imc/reports/2024_ktl_export/test_2.py

@@ -0,0 +1,144 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+import subprocess
+import sys
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config(benchmark)
+
+    print("\n===== A. measure original program =====\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current, repeat=2)
+    with open(f"output/test_1_{benchmark}_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config(benchmark)
+    config.insert_compiler_checkpoints = False
+    config.use_checkpoint_pass_counter = False
+    config.split_loop = False
+    config.enable_adaptive_loop_pass_count = False
+    config.use_checkpoint_voltage_check = False
+    config.max_loop_ids = 15
+    config.enable_dynamic_checkpoint = True
+
+    # print("\n===== B. measure checkpoint-instrumented program =====\n")
+    target_current = 0.015
+    wait_s = 3
+    repeat = 200
+    records = measure(config, pps, smu, target_current, repeat=repeat, wait_before_start_s=wait_s)
+    records = pd.DataFrame(records)
+    columns = ["bench_name", "time_taken", "outputs", "is_correct"]
+    print(records[columns])
+    with open(f"output/test_2_{benchmark}_ckpt.pickle", "wb") as f:
+        pickle.dump(records, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current, repeat=1, wait_before_start_s=0):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, repeat)
+
+    if wait_before_start_s > 0:
+        print(f" > wait for {wait_before_start_s} secs")
+        time.sleep(wait_before_start_s)
+        env.resume_board(terminate=True, verbose=False)
+
+    print(" > start measuring\n")
+    if wait_before_start_s == 0:
+        env.resume_board(terminate=True, verbose=False)
+    records = watcher.run()
+    print("\n > measure finished")
+    return records
+
+
+def main(args):
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.setup_sense()
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    benchmark = args[1]
+    assert benchmark in benchmarks
+    benchmarks = [benchmark]
+
+    total = len(benchmarks)
+    for i, benchmark in enumerate(benchmarks):
+        print(f"\n+++ ({i+1}/{total}) {benchmark} +++")
+        # measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print(" > build and program binary")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir, redirect_file=subprocess.DEVNULL)
+        env.clear_nvm_and_load_binary(binary, resume=False, verbose=False)
+    
+    print(" > program finished")
+    
+    return env
+
+
+def get_bench_repeat_count(benchmark):
+    d = {
+        "vFFT": 10,
+        "vConv2d": 15000,
+        "vCrc": 1000,
+        "vBasicMath": 1,
+        "vSha": 40,
+        "vStringSearch": 3000,
+        "vAes": 1300,
+        "vMatMul": 20000,
+    }
+    return d[benchmark]
+    
+
+def get_default_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.enable_dynamic_checkpoint = False
+    config.bench_repeat_count = get_bench_repeat_count(benchmark)
+    return config
+
+
+if __name__ == "__main__":
+    main(sys.argv)

+ 70 - 0
imc/reports/2024_ktl_export/test_2_analysis.py

@@ -0,0 +1,70 @@
+import pickle
+import pandas as pd
+
+
+def get_average_active_secs(df, repeat=1):
+    mask = (df > 0.005) & (df < 0.020)
+    active = df[mask]
+    secs = len(active) / 1000
+    return secs / repeat
+
+
+def analyze_benchmark(benchmark):
+    with open(f"output/test_2_{benchmark}_ckpt.pickle", "rb") as f:
+        d = pickle.load(f)
+    
+    d = d.sort_values(by=["time_taken"], ascending=False)
+    columns = ["bench_name", "time_taken", "outputs", "is_correct"]
+
+
+    sla_values = {
+        "vFFT": 1.42,
+        "vCrc": 1.48,
+        "vAes": 1.35,
+        "vSha": 1.66,
+    }
+    sla = sla_values[benchmark]
+
+    print(f"\n+++ benchmark {benchmark} +++")
+    print(f"SLA: {sla}")
+    print(d[columns])
+
+    mask = d["time_taken"] < sla
+    n_total = len(d)
+    n_passed = len(d[mask])
+    print("")
+    print(f"{n_passed} passed (total {n_total})")
+    return n_total, n_passed
+
+
+def do_analysis(benchmarks):
+    results = []
+    for benchmark in benchmarks:
+        try:
+            n_total, n_passed = analyze_benchmark(benchmark)
+        except:
+            continue
+        results.append({
+            "benchmark": benchmark,
+            "total": n_total,
+            "passed": n_passed,
+            "pass rate (%)": (n_passed / n_total) * 100,
+        })
+    d = pd.DataFrame(results)
+
+    avg_pass_rate = d["pass rate (%)"].mean()
+
+    print("\n\n+++ summary +++\n")
+    print(d)
+    print("")
+    print(f"average pass rate: {avg_pass_rate:.2f}%")
+
+
+def main():
+    benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    do_analysis(benchmarks)
+
+
+if __name__ == "__main__":
+    main()

+ 144 - 0
imc/reports/2024_ktl_export/test_3.py

@@ -0,0 +1,144 @@
+import tempfile
+import time
+import pandas as pd
+import pickle
+import subprocess
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.smu_b2902a import SMU_B2902A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+
+def measure_original(benchmark, pps, smu):
+    config = get_default_build_config(benchmark)
+
+    print("\n===== A. measure original program =====\n")
+    target_current = 0.1
+    currs = measure(config, pps, smu, target_current, repeat=2)
+    with open(f"output/test_1_{benchmark}_original.pickle", "wb") as f:
+        pickle.dump(currs, f)
+
+
+def measure_ckpt(benchmark, pps, smu: SMU_B2902A):
+    config = get_default_build_config(benchmark)
+    config.insert_compiler_checkpoints = False
+    config.use_checkpoint_pass_counter = False
+    config.split_loop = False
+    config.enable_adaptive_loop_pass_count = False
+    config.use_checkpoint_voltage_check = False
+    config.max_loop_ids = 15
+    config.enable_dynamic_checkpoint = True
+    config.print_init_time = True
+
+    # print("\n===== B. measure checkpoint-instrumented program =====\n")
+    target_current = 0.02
+    wait_s = 3
+    repeat = 1
+    records = measure(config, pps, smu, target_current, repeat=repeat, wait_before_start_s=wait_s)
+    records = pd.DataFrame(records)
+    with open(f"output/test_3_{benchmark}_ckpt.pickle", "wb") as f:
+        pickle.dump(records, f)
+
+
+def measure(config, pps: PPS_E36311A, smu: SMU_B2902A, target_current, repeat=1, wait_before_start_s=0):
+    env = program_with_config(config, pps, smu)
+
+    benchmark = config.bench_name
+    pps.set_voltage(3.3, 1)
+    pps.set_current(target_current, 1)
+    watcher = SerialWatcher(benchmark, 1)
+
+    wait_time = 5
+
+    print(" > start board execution")
+    env.resume_board(terminate=True, verbose=False)
+    print(f" > wait for {wait_before_start_s} secs")
+    time.sleep(wait_before_start_s)
+    print(" > power off")
+    pps.output_off(1)
+    print(f" > wait for {wait_time} secs")
+    time.sleep(wait_time)
+    print(" > power on\n")
+    pps.output_on(1)
+    records = watcher.run()
+    print("\n > measure finished")
+    return records
+
+
+def main():
+    pps = PPS_E36311A()
+    smu = SMU_B2902A(voltage=0, use_external_power=True)
+    smu.setup_sense()
+    smu.set_current_limit(0.1)
+
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    # benchmarks = ["vFFT"]
+
+    total = len(benchmarks)
+    for i, benchmark in enumerate(benchmarks):
+        print(f"\n+++ ({i+1}/{total}) {benchmark} +++")
+        # measure_original(benchmark, pps, smu)
+        measure_ckpt(benchmark, pps, smu)
+
+
+def program_with_config(config, pps, smu):
+    env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+    smu.power_on()
+    pps.set_voltage(3.3, 1)
+    pps.set_current(0.1, 1)
+    pps.output_on(1)
+    time.sleep(1)
+
+    print(" > build and program binary")
+
+    with tempfile.TemporaryDirectory() as build_dir:
+        binary = env.build_binary(config, build_dir, redirect_file=subprocess.DEVNULL)
+        env.clear_nvm_and_load_binary(binary, resume=False, verbose=False)
+    
+    print(" > program finished")
+    
+    return env
+
+
+def get_bench_repeat_count(benchmark):
+    d = {
+        "vFFT": 10,
+        "vConv2d": 15000,
+        "vCrc": 1000,
+        "vBasicMath": 1,
+        "vSha": 40,
+        "vStringSearch": 3000,
+        "vAes": 1300,
+        "vMatMul": 20000,
+    }
+    return d[benchmark]
+    
+
+def get_default_build_config(benchmark):
+    config = BuildConfigM33()
+    config.bench_name = benchmark
+    config.insert_compiler_checkpoints = False
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = False
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.print_recovery_message = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.enable_adaptive_loop_pass_count = False
+    config.print_stats = False
+    config.custom_unroll = False
+    config.enable_dynamic_checkpoint = False
+    config.bench_repeat_count = get_bench_repeat_count(benchmark)
+    return config
+
+
+if __name__ == "__main__":
+    main()

+ 57 - 0
imc/reports/2024_ktl_export/test_3_analysis.py

@@ -0,0 +1,57 @@
+import pickle
+import pandas as pd
+
+
+def get_average_active_secs(df, repeat=1):
+    mask = (df > 0.005) & (df < 0.020)
+    active = df[mask]
+    secs = len(active) / 1000
+    return secs / repeat
+
+
+def analyze_benchmark(benchmark):
+    with open(f"output/test_3_{benchmark}_ckpt.pickle", "rb") as f:
+        d = pickle.load(f)
+    
+    measured_init_times = []
+
+    for messages in d["debug_outputs"]:
+        for message in messages:
+            if message.startswith("cycle"):
+                cycle = message.split()[1]
+                cycle = int(cycle)
+                freq = 10 * 1000 * 1000
+                time = cycle / freq
+                measured_init_times.append(time)
+    
+    return measured_init_times[0]
+
+
+def do_analysis(benchmarks):
+    results = []
+    for benchmark in benchmarks:
+        try:
+            init_time = analyze_benchmark(benchmark)
+        except:
+            continue
+        results.append({
+            "benchmark": benchmark,
+            "init time (s)": init_time,
+        })
+    d = pd.DataFrame(results)
+
+    avg_init_time = d["init time (s)"].mean()
+
+    print(d)
+    print("")
+    print(f"average init time: {avg_init_time:.5f} s")
+
+
+def main():
+    benchmarks = ["vFFT", "vConv2d", "vCrc", "vBasicMath", "vSha", "vStringSearch", "vAes", "vMatMul"]
+    benchmarks = ["vFFT", "vCrc", "vAes", "vSha"]
+    do_analysis(benchmarks)
+
+
+if __name__ == "__main__":
+    main()

+ 20 - 0
imc/utils/set_smu.py

@@ -0,0 +1,20 @@
+from time import sleep
+import usbtmc
+import sys
+
+from imc_utils.smu_b2902a import SMU_B2902A
+
+vol = 3.3
+instr = SMU_B2902A(voltage=vol)
+
+command = sys.argv[1]
+
+cur = 0.1
+cur = 0.015
+
+if command == "on":
+    instr.set_current_limit(cur)
+    instr.power_on()
+
+elif command == "off":
+    instr.power_off()

+ 39 - 3
imc_extension.cmake

@@ -8,8 +8,13 @@ set(IMC_LOOP_PASS_COUNT 10 CACHE BOOL "")
 set(IMC_BENCH_REPEAT_COUNT 1 CACHE BOOL "")
 set(IMC_PRINT_STATS 0 CACHE BOOL "")
 set(IMC_CUSTOM_UNROLL 0 CACHE BOOL "")
+set(IMC_LOOP_OPT_DEBUG 0 CACHE BOOL "")
+set(IMC_PRINT_INIT_TIME 0 CACHE BOOL "")
+set(IMC_PRINT_LATENCY_OVERHEAD 0 CACHE BOOL "")
+set(IMC_ENABLE_DYNAMIC_CHECKPOINT 0 CACHE BOOL "")
 
-set(AVAILABLE_BENCHES "vBasicMath" "vStringSearch" "vFFT" "vSha" "vCrc" "vMatMul" "vConv2d" "adc_demo" "vAes")
+
+set(AVAILABLE_BENCHES "vBasicMath" "vStringSearch" "vFFT" "vSha" "vCrc" "vMatMul" "vConv2d" "adc_demo" "vAes" "fmc_expr" "vrefint_expr")
 if(NOT IMC_BENCH_NAME IN_LIST AVAILABLE_BENCHES)
     message( FATAL_ERROR "incorrect benchmark name: ${IMC_BENCH_NAME}")
 endif()
@@ -21,6 +26,13 @@ endif()
 add_compile_definitions(imcBENCH_NAME=${IMC_BENCH_NAME})
 add_compile_definitions(imcBENCH_REPEAT_COUNT=${IMC_BENCH_REPEAT_COUNT})
 add_compile_definitions(imcCUSTOM_UNROLL=${IMC_CUSTOM_UNROLL})
+add_compile_definitions(imcLOOP_OPT_DEBUG=${IMC_LOOP_OPT_DEBUG})
+add_compile_definitions(imcPRINT_INIT_TIME=${IMC_PRINT_INIT_TIME})
+add_compile_definitions(imcPRINT_LATENCY_OVERHEAD=${IMC_PRINT_LATENCY_OVERHEAD})
+
+# add_compile_definitions(imcUSE_IMC_KERNEL=${IMC_INSERT_COMPILER_CHECKPOINTS})
+add_compile_definitions(imcUSE_IMC_KERNEL=1)
+add_compile_definitions(imcENABLE_DYNAMIC_CHECKPOINT=${IMC_ENABLE_DYNAMIC_CHECKPOINT})
 
 if(IMC_BENCH_INFINITE_LOOP)
     add_compile_definitions(imcBENCH_INFINITE_LOOP=1)
@@ -55,6 +67,26 @@ if(IMC_BENCH_NAME MATCHES "adc_demo")
     )
 endif()
 
+if(IMC_BENCH_NAME MATCHES "fmc_expr")
+    set(BENCHMARK_SRC_FILES
+        Core/Src/benchmarks/fmc_expr/fmc_expr.c
+    )
+    set(IMC_APP_FILES
+    )
+    set(IMC_LINK_OBJS
+    )
+endif()
+
+if(IMC_BENCH_NAME MATCHES "vrefint_expr")
+    set(BENCHMARK_SRC_FILES
+        Core/Src/benchmarks/vrefint_expr/vrefint_expr.c
+    )
+    set(IMC_APP_FILES
+    )
+    set(IMC_LINK_OBJS
+    )
+endif()
+
 if(IMC_BENCH_NAME MATCHES "vBasicMath")
     set(BENCHMARK_SRC_FILES
         Core/Src/benchmarks/basicmath/cubic.c
@@ -152,7 +184,7 @@ foreach(BENCH_SRC ${BENCHMARK_SRC_FILES})
 endforeach()
 
 function(compile_imc_files)
-    message("compile_imc_files called")
+    # message("compile_imc_files called")
     get_target_property(SRC_INCLUDES imc_freeRTOS INCLUDE_DIRECTORIES)
     foreach(dir ${SRC_INCLUDES})
         list(APPEND INCLUDE_DIRS "-I${dir}")
@@ -193,13 +225,17 @@ function(compile_imc_files)
         "-D imcCUSTOM_UNROLL=${IMC_CUSTOM_UNROLL}"
     )
 
+    set(ADDITIONAL_OPT_FLAGS
+        # "--disable-loop-unrolling"
+    )
+
     foreach(APP_SRC ${IMC_APP_FILES})
         add_custom_command(
             OUTPUT ${PROJECT_BINARY_DIR}/${APP_SRC}.s
             DEPENDS ${APP_SRC}
             COMMAND ${CMAKE_C_COMPILER} -g ${C_FLAGS} -O0 -Xclang -disable-O0-optnone ${INCLUDE_DIRS} -D USE_HAL_DRIVER -D STM32L552xx ${ADDITIONAL_DEFS} -c -emit-llvm ${PROJECT_SOURCE_DIR}/${APP_SRC} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
             COMMAND ${OPT_BIN} -o ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc ${PLUGIN_OPTIONS} -passes=${BASIC_OPT_PASSES},${IMC_OPT_PASSES} ${PROJECT_BINARY_DIR}/${APP_SRC}.bc
-            COMMAND ${OPT_BIN} ${OPT} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc
+            COMMAND ${OPT_BIN} ${OPT} ${ADDITIONAL_OPT_FLAGS} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc ${PROJECT_BINARY_DIR}/${APP_SRC}_imc.bc
             COMMAND ${LLC_BIN} ${CPU} ${OPT} -o ${PROJECT_BINARY_DIR}/${APP_SRC}.s ${PROJECT_BINARY_DIR}/${APP_SRC}.opt.bc
         )
         list(APPEND APP_OPTS ${PROJECT_BINARY_DIR}/${APP_SRC}.s)

+ 5 - 3
setup_build_dir.py

@@ -11,19 +11,21 @@ BUILD_DIR = f"{WORKSPACE_ROOT}/build"
 
 config = BuildConfigM33()
 config.bench_name = "vFFT"
-config.insert_compiler_checkpoints = True
+config.insert_compiler_checkpoints = False
 config.enable_extension = True
 config.use_checkpoint_pass_counter = False
+config.checkpoint_pass_count = 1000
 config.use_checkpoint_voltage_check = True
 config.bench_infinite_loop = True
 config.split_loop = False
 config.loop_pass_count = 30
 config.enable_static_loop_pass_count = False
 config.enable_adaptive_loop_pass_count = False
-config.max_loop_ids = 30
+config.max_loop_ids = 20
 config.bench_repeat_count = config.bench_repeat_count_small[config.bench_name]
 config.print_stats = True
-config.custom_unroll = True
+config.custom_unroll = False
+config.enable_dynamic_checkpoint = True
 
 env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
 

Some files were not shown because too many files changed in this diff