From d85591c41eeaa9109c8118601ecdf63cb9594085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 22 Oct 2022 00:16:33 +0200 Subject: [PATCH] Further implement modes --- Makefile | 4 + animation.c | 106 +++++++++++++++++ dmx.c | 2 +- gamma.c | 20 ++++ include/animation.h | 36 ++++++ include/gamma.h | 13 ++ include/i2c.h | 2 +- include/pca9555.h | 28 +++++ main.c | 282 ++++++++++++++++++++++++++++---------------- pca9555.c | 63 ++++++++++ poti.c | 11 +- systick.c | 4 +- 12 files changed, 462 insertions(+), 109 deletions(-) create mode 100644 animation.c create mode 100644 gamma.c create mode 100644 include/animation.h create mode 100644 include/gamma.h create mode 100644 include/pca9555.h create mode 100644 pca9555.c diff --git a/Makefile b/Makefile index bec72c9..67ee007 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,10 @@ CFILES := main.c setup/system_init.c startup/startup_stm32f0xx.c systick.c CFILES += i2c.c CFILES += dmx.c CFILES += poti.c +CFILES += gamma.c +CFILES += pca9555.c +CFILES += animation.c + ASFILES = INCLUDEPATH = -Iinclude -Iinclude/cmsis diff --git a/animation.c b/animation.c new file mode 100644 index 0000000..9c11a41 --- /dev/null +++ b/animation.c @@ -0,0 +1,106 @@ +#include +#include +#include + +void animation_reset(struct animation *ani) +{ + if (!ani) + return; + + ani->state = ANI_RED; + ani->step = 0u; + ani->last_tick = systick_get_global_tick(); + ani->next_interval = 0ul; +} + +static void clear_dmx_universe(uint8_t *universe, uint32_t len) +{ + uint32_t idx; + + for (idx = 0; idx < len; idx++) { + universe[idx] = 0u; + } +} + +static enum animation_state next_col_state(enum animation_state current) +{ + enum animation_state next; + + switch (current) { + case ANI_RED: + next = ANI_GREEN; + break; + case ANI_GREEN: + next = ANI_BLUE; + break; + case ANI_BLUE: + next = ANI_RAINBOW; + break; + default: + next = ANI_RED; + break; + } + + return next; +} + +void animation_process(struct animation *ani, uint8_t *dmx_universe) +{ + uint32_t tick; + uint32_t new_tick; + uint32_t i; + + if (!ani || !dmx_universe) + return; + + /* Check if time for next step is reached */ + tick = systick_get_global_tick(); + /* Calculate next tick. Overflow expected */ + new_tick = ani->last_tick + ani->next_interval; + if (new_tick < ani->last_tick) { + /* Tick overflowed. */ + if (!(tick >= new_tick && tick < ani->last_tick)) + return; + } else { + if (tick < new_tick) + return; + } + + ani->last_tick = tick; + + switch (ani->state) { + case ANI_RED: + case ANI_GREEN: + case ANI_BLUE: + for (i = 0; i < 32; i++) { + dmx_universe[i * 4 + 0] = ani->state == ANI_RED ? (uint8_t)ani->step : 0u; + dmx_universe[i * 4 + 1] = ani->state == ANI_GREEN ? (uint8_t)ani->step : 0u; + dmx_universe[i * 4 + 2] = ani->state == ANI_BLUE ? (uint8_t)ani->step : 0u; + dmx_universe[i * 4 + 3] = 0u; + } + if (ani->step + 10 > 0xFFul) { + ani->step = 0; + ani->state = next_col_state(ani->state); + } else { + ani->step += 10; + } + ani->next_interval = 20; + break; + case ANI_RAINBOW: + /* TODO: Implement Rainbow mode */ + ani->next_interval = 10; + clear_dmx_universe(dmx_universe, 129u); + ani->state = ANI_FLASH_WHITE; + break; + case ANI_FLASH_WHITE: + dmx_universe[128] = ani->step & 1 ? 0xFF : 0; + ani->next_interval = ani->step & 1 ? 60 : 260; + ani->step += 1u; + + if (ani->step >= 11u) { + ani->state = ANI_RED; + ani->step = 0u; + } + break; + } +} \ No newline at end of file diff --git a/dmx.c b/dmx.c index da87503..e1ccfba 100644 --- a/dmx.c +++ b/dmx.c @@ -64,7 +64,7 @@ void dmx_init(uint8_t *data, uint32_t universe_length, GPIO_TypeDef *tx_port, ui /* Configure TIM14 to count in 10 us steps */ - TIM14->PSC = 480u; + TIM14->PSC = 480u - 1u; /* Configure the reload value. Must be higher or equal to 200 */ if (dmx_delay < 2000) diff --git a/gamma.c b/gamma.c new file mode 100644 index 0000000..a4da15c --- /dev/null +++ b/gamma.c @@ -0,0 +1,20 @@ +#include + +const uint8_t global_gamma_correction_table[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, + 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, + 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, + 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, + 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, + 90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114, + 115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142, + 144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, + 177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, + 215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 +}; \ No newline at end of file diff --git a/include/animation.h b/include/animation.h new file mode 100644 index 0000000..d694b9a --- /dev/null +++ b/include/animation.h @@ -0,0 +1,36 @@ +#ifndef _ANIMATION_H_ +#define _ANIMATION_H_ + +#include + +enum animation_state { + ANI_RED, + ANI_GREEN, + ANI_BLUE, + ANI_RAINBOW, + ANI_FLASH_WHITE, +}; + +struct animation { + enum animation_state state; + uint32_t step; + uint32_t last_tick; + uint32_t next_interval; +}; + +/** + * @brief Reset aniamtion to start conditions + * + * @param ani Animation + */ +void animation_reset(struct animation *ani); + +/** + * @brief Poll animation + * + * @param ani Animation + * @param dmx_universe Target universe to play animation into. Must be big enough + */ +void animation_process(struct animation *ani, uint8_t *dmx_universe); + +#endif /* _ANIMATION_H_ */ \ No newline at end of file diff --git a/include/gamma.h b/include/gamma.h new file mode 100644 index 0000000..6ed2ef8 --- /dev/null +++ b/include/gamma.h @@ -0,0 +1,13 @@ +#ifndef _GAMMA_H_ +#define _GAMMA_H_ + +#include + +extern const uint8_t global_gamma_correction_table[256]; + +static inline uint8_t gamma_corr(uint8_t raw) +{ + return global_gamma_correction_table[raw]; +} + +#endif /* _GAMMA_H_ */ \ No newline at end of file diff --git a/include/i2c.h b/include/i2c.h index d2ffa61..605cf7b 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -9,6 +9,6 @@ void i2c_reset(void); int i2c_write(uint8_t i2c_addr, const uint8_t *data, uint8_t len); -int i2c_read(uint8_t i2c_addr, uint8_t command, uint8_t *data, uint8_t len); +int i2c_read(uint8_t i2c_addr, uint8_t command, uint8_t *data, uint8_t len); #endif /* _I2C_H_ */ \ No newline at end of file diff --git a/include/pca9555.h b/include/pca9555.h new file mode 100644 index 0000000..620b7ca --- /dev/null +++ b/include/pca9555.h @@ -0,0 +1,28 @@ +#ifndef _PCA9555_H_ +#define _PCA9555_H_ + +#include + +#define PCA9555_I2C_ADDR (0x40) +#define PCA9555_REG_IN_PORT0 (0x0) +#define PCA9555_REG_IN_PORT1 (0x1) +#define PCA9555_REG_OUT_PORT0 (0x2) +#define PCA9555_REG_OUT_PORT1 (0x3) +#define PCA9555_REG_POLARITY0 (0x4) +#define PCA9555_REG_POLARITY1 (0x5) +#define PCA9555_REG_CONFIG0 (0x6) +#define PCA9555_REG_CONFIG1 (0x7) + +/** + * @brief Init I2C and port expander + */ +void port_expander_init(void); + +uint8_t port_expander_get_buttons(void); + +void port_expander_set_leds(uint8_t leds); + +uint8_t port_expander_get_leds(void); + +void port_expander_set_single_led(uint8_t pos, uint8_t val); +#endif /* _PCA9555_H */ \ No newline at end of file diff --git a/main.c b/main.c index bf072d0..1fbefb5 100644 --- a/main.c +++ b/main.c @@ -1,42 +1,17 @@ #include -#include +#include #include #include #include #include #include - -#define PCA9555_ADDR (0x40) -#define PCA9555_REG_IN_PORT0 (0x0) -#define PCA9555_REG_IN_PORT1 (0x1) -#define PCA9555_REG_OUT_PORT0 (0x2) -#define PCA9555_REG_OUT_PORT1 (0x3) -#define PCA9555_REG_POLARITY0 (0x4) -#define PCA9555_REG_POLARITY1 (0x5) -#define PCA9555_REG_CONFIG0 (0x6) -#define PCA9555_REG_CONFIG1 (0x7) - - -static const uint8_t gamma8[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, - 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, - 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, - 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, - 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, - 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, - 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, - 90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114, - 115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142, - 144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, - 177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, - 215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 -}; +#include +#include +#include +#include static uint8_t dmx_universe[129]; +static struct animation led_animation; enum color_mode { MODE_RED, @@ -44,6 +19,10 @@ enum color_mode { MODE_BLUE, MODE_RGB, MODE_WHITE_DISCRETE, + MODE_WHITE_ANGLE, + MODE_RED_BLUE_RING, + MODE_ANIMATION, + MODE_DMX_SHUTDOWN, }; static void setup_pins(void) @@ -87,103 +66,202 @@ static void setup_pins(void) GPIOB->PUPDR = PULLUP(1); } +static void process_mode(enum color_mode mode, const struct poti_values *poti_vals) +{ + uint32_t odr; + static uint32_t last_tick = 0ul; + uint32_t tick; + int i; + + odr = GPIOA->ODR; + odr &= ~((1<<5) | (1<<6) | (1<<7)); + + tick = systick_get_global_tick(); + + switch (mode) { + case MODE_RED: + case MODE_GREEN: + case MODE_BLUE: + for (i = 0; i < 32; i++) { + dmx_universe[i*4] = mode == MODE_RED ? poti_vals->pot_vals_filtered[0] : 0; + dmx_universe[i*4+1] = mode == MODE_GREEN ? poti_vals->pot_vals_filtered[0] : 0; + dmx_universe[i*4+2] = mode == MODE_BLUE ? poti_vals->pot_vals_filtered[0] : 0; + dmx_universe[i*4+3] = 0x0; + } + dmx_universe[128] = 0; + odr |= (1<<5); + break; + case MODE_RGB: + odr |= (1<<5) | (1<<6) | (1<<7); + for (i = 0; i < 32; i++) { + dmx_universe[i*4] =poti_vals->pot_vals_filtered[0]; + dmx_universe[i*4+1] = poti_vals->pot_vals_filtered[1]; + dmx_universe[i*4+2] = poti_vals->pot_vals_filtered[2]; + dmx_universe[i*4+3] = 0x0; + } + dmx_universe[128] = 0; + break; + case MODE_WHITE_DISCRETE: + odr |= (1<<5); + for (i = 0; i < 32; i++) { + dmx_universe[i*4] = 0; + dmx_universe[i*4+1] = 0; + dmx_universe[i*4+2] = 0; + dmx_universe[i*4+3] = 0; + } + dmx_universe[128] = gamma_corr(poti_vals->pot_vals_filtered[0]); + break; + case MODE_ANIMATION: + animation_process(&led_animation, dmx_universe); + break; + case MODE_DMX_SHUTDOWN: + port_expander_set_leds(0xFF); + break; + default: + + break; + } + + last_tick = tick; + GPIOA->ODR = odr; +} + +static bool filtered_poti_vals_equal(const struct poti_values *p1, const struct poti_values *p2) +{ + uint32_t i; + bool ret = true; + + for (i = 0; i < POTI_COUNT; i++) { + if (p1->pot_vals_filtered[i] != p2->pot_vals_filtered[i]) { + ret = false; + break; + } + } + + return ret; +} + +/** + * @brief Check if a color mode requires continous updates + * + * @param mode Color mode input + * @return true Color mode requires continous updates + * @return false Color mode does not reuqire continuous update + */ +static bool mode_is_continuous(enum color_mode mode) +{ + bool ret = false; + + switch (mode) { + case MODE_ANIMATION: + ret = true; + break; + default: + ret = false; + break; + } + + return ret; +} + int main(void) { - uint8_t i2c_command[2]; + int i; uint8_t port; - uint32_t odr; - enum color_mode mode = MODE_RED; + uint8_t button_pressed; + enum color_mode mode = MODE_WHITE_DISCRETE; + enum color_mode old_mode = MODE_BLUE; struct poti_values poti_vals; + struct poti_values old_poti_vals; + bool buttons_released_since_dual_press = true; setup_pins(); - i2c_init(); - dmx_init(dmx_universe, sizeof(dmx_universe), GPIOA, 2u, 2300u, 10u, 5u); + dmx_init(dmx_universe, sizeof(dmx_universe), GPIOA, 2u, 2000u, 10u, 5u); poti_init_adc(); + port_expander_init(); + + port_expander_set_leds(1 << 4); /* Setup Systick for 1ms ticks */ SysTick_Config(48000000UL/1000); - - GPIOA->ODR |= (1<<5) | (1<<7); - /* Setup PCA */ - i2c_command[0] = PCA9555_REG_CONFIG1; - i2c_command[1] = 0x00; - i2c_write(PCA9555_ADDR, i2c_command, 2u); - - i2c_command[0] = PCA9555_REG_CONFIG0; - i2c_command[1] = 0xFF; - i2c_write(PCA9555_ADDR, i2c_command, 2u); + for (i = 0; i < sizeof(dmx_universe); i++) { + dmx_universe[i] = 0x00; + } dmx_stream_start(); - dmx_universe[0] = 0x55; - dmx_universe[1] = 0x50; - - /* Blink the LEDs */ while (1) { - systick_wait_ms(10); + systick_wait_ms(20); poti_get_values(&poti_vals); - i2c_read(PCA9555_ADDR, PCA9555_REG_IN_PORT0, &port, 1u); - i2c_command[0] = PCA9555_REG_OUT_PORT1; - i2c_command[1] = ~port; - i2c_write(PCA9555_ADDR, i2c_command, 2u); - odr = GPIOA->ODR; - odr &= ~((1<<5) | (1<<6) | (1<<7)); - if (port & (1<<0)) { + port = port_expander_get_buttons(); + + /* Isolate lowest set bit. This prevents edge cases where multipe switches are pressed */ + button_pressed = 0u; + for (i = 0; i < 8; i++) { + if (port & 0x1) { + button_pressed = i + 1u; + break; + } + port >>= 1; + } + + if (button_pressed) { + if (!buttons_released_since_dual_press) + button_pressed = 0u; + } else { + buttons_released_since_dual_press = true; + } + + switch (button_pressed) { + case 1: mode = MODE_RED; - } - if (port & (1<<1)) { + break; + case 2: mode = MODE_GREEN; - } - if (port & (1<<2)) { + break; + case 3: mode = MODE_BLUE; - } - if (port & (1<<3)) { + break; + case 4: mode = MODE_RGB; - } - if (port & (1<<4)) { + break; + case 5: mode = MODE_WHITE_DISCRETE; - } - - - switch (mode) { - case MODE_RED: - case MODE_GREEN: - case MODE_BLUE: - for (int i = 0; i < 32; i++) { - dmx_universe[i*4] = mode == MODE_RED ? poti_vals.pot_vals_filtered[0] : 0; - dmx_universe[i*4+1] = mode == MODE_GREEN ? poti_vals.pot_vals_filtered[0] : 0; - dmx_universe[i*4+2] = mode == MODE_BLUE ? poti_vals.pot_vals_filtered[0] : 0; - dmx_universe[i*4+3] = 0x0; - } - dmx_universe[128] = 0; - odr |= (1<<5); break; - case MODE_RGB: - odr |= (1<<5) | (1<<6) | (1<<7); - for (int i = 0; i < 32; i++) { - dmx_universe[i*4] =poti_vals.pot_vals_filtered[0]; - dmx_universe[i*4+1] = poti_vals.pot_vals_filtered[1]; - dmx_universe[i*4+2] = poti_vals.pot_vals_filtered[2]; - dmx_universe[i*4+3] = 0x0; - } - dmx_universe[128] = 0; - break; - case MODE_WHITE_DISCRETE: - odr |= (1<<5); - for (int i = 0; i < 32; i++) { - dmx_universe[i*4] = 0; - dmx_universe[i*4+1] = 0; - dmx_universe[i*4+2] = 0; - dmx_universe[i*4+3] = 0; - } - dmx_universe[128] = gamma8[poti_vals.pot_vals_filtered[0]]; + case 8: + animation_reset(&led_animation); + mode = MODE_ANIMATION; break; default: break; } - GPIOA->ODR = odr; - + /* Check for special case: 1 + 5 pressed simultaneously*/ + if ((port & ((1<<0 | (1<<4)))) == ((1<<4) | (1<<0))) { + /* Prevent nomal logic from triggering on this */ + button_pressed = 0; + + /* set mode to DMX off and disable DMX */ + mode = MODE_DMX_SHUTDOWN; + buttons_released_since_dual_press = false; + dmx_stream_stop(); + } else if (mode != old_mode && old_mode == MODE_DMX_SHUTDOWN && buttons_released_since_dual_press) { + /* Wakeup DMX */ + dmx_stream_start(); + } + + if (button_pressed) + port_expander_set_leds((1 << (button_pressed - 1))); + + if (mode != old_mode || !filtered_poti_vals_equal(&poti_vals, &old_poti_vals) || + mode_is_continuous(mode)) { + /* The values changed. Update the DMX frame */ + process_mode(mode, &poti_vals); + } + + /* Move to old values. Used to detect changes */ + old_mode = mode; + memcpy(&old_poti_vals, &poti_vals, sizeof(struct poti_values)); } } diff --git a/pca9555.c b/pca9555.c new file mode 100644 index 0000000..a844d92 --- /dev/null +++ b/pca9555.c @@ -0,0 +1,63 @@ +#include +#include + +static void pca_write_register(uint8_t reg, uint8_t value) +{ + uint8_t i2c_command[2]; + + i2c_command[0] = reg; + i2c_command[1] = value; + i2c_write(PCA9555_I2C_ADDR, i2c_command, 2u); +} + +static uint8_t pca_read_register(uint8_t reg) +{ + uint8_t val = 0; + + i2c_read(PCA9555_I2C_ADDR, reg, &val, 1u); + + return val; +} + +void port_expander_init(void) +{ + i2c_init(); + + /* Port 0: Input for buttons */ + pca_write_register(PCA9555_REG_CONFIG0, 0xFF); + + /* Port 1: Output for LEDs */ + pca_write_register(PCA9555_REG_CONFIG1, 0x00); +} + +uint8_t port_expander_get_buttons(void) +{ + return pca_read_register(PCA9555_REG_IN_PORT0); +} + +void port_expander_set_leds(uint8_t leds) +{ + pca_write_register(PCA9555_REG_OUT_PORT1, ~leds); +} + +uint8_t port_expander_get_leds(void) +{ + return ~pca_read_register(PCA9555_REG_OUT_PORT1); +} + +void port_expander_set_single_led(uint8_t pos, uint8_t val) +{ + uint8_t port_reg = 0; + + if (pos > 7) + return; + + val = val ? 1 : 0; + val = (val << pos); + + port_reg = port_expander_get_leds(); + port_reg &= ~(1 << pos); + port_reg |= val; + + port_expander_set_leds(port_reg); +} \ No newline at end of file diff --git a/poti.c b/poti.c index faea0ce..1779cc8 100644 --- a/poti.c +++ b/poti.c @@ -50,8 +50,8 @@ void poti_init_adc(void) } ADC1->CHSELR = reg; - /* Setup sample time (71.5 cycles) */ - ADC1->SMPR = ADC_SMPR_SMP_2 | ADC_SMPR_SMP_1; + /* Setup sample time (239.5 cycles) */ + ADC1->SMPR = ADC_SMPR_SMP_2 | ADC_SMPR_SMP_1 | ADC_SMPR1_SMPR_0; /* Setup ADC clock (PCLK / 4) */ ADC1->CFGR2 = ADC_CFGR2_CKMODE_1; @@ -73,6 +73,8 @@ void poti_init_adc(void) DMA_CCR_CIRC | DMA_CCR_TCIE | DMA_CCR_EN; + /* Enable Interrupt with lower priority. Prevents jitter on the DMX lines */ + NVIC_SetPriority(DMA1_Channel1_IRQn, 1); NVIC_EnableIRQ(DMA1_Channel1_IRQn); /* Start the conversion */ @@ -87,8 +89,9 @@ void poti_get_values(struct poti_values *out_val) return; for (i = 0; i < POTI_COUNT; i++) { - out_val->current_pot_vals[i] = adc_raw_values[i]; - out_val->pot_vals_filtered[i] = adc_moving_avg_out[i]; + /* return iverted values, because of potentiometer polarities */ + out_val->current_pot_vals[i] = ~adc_raw_values[i]; + out_val->pot_vals_filtered[i] = ~adc_moving_avg_out[i]; } } diff --git a/systick.c b/systick.c index 061493a..b779051 100644 --- a/systick.c +++ b/systick.c @@ -1,4 +1,5 @@ #include +#include volatile uint32_t global_systick = 0; volatile uint32_t systick_wait_counter; @@ -7,7 +8,8 @@ void systick_wait_ms(uint32_t ms) { systick_wait_counter = ms; - while (systick_wait_counter > 0); + while (systick_wait_counter > 0) + __WFI(); } uint32_t systick_get_global_tick(void)