Kaynağa Gözat

IR transmit example (#180)

* DWT-based microsecond delay

* simple ir app (work only with NEC protocol and predefined address - command)

* remove space from file name, add delay_us_init_DWT header

* float-based delay us

* init tim2 by CubeMX

* fix simple pwm functions

* simple pwm timer based ir nec protocol

* ir gui test app

Co-authored-by: aanper <mail@s3f.ru>
DrZlo13 5 yıl önce
ebeveyn
işleme
37fc47a24f

+ 8 - 0
applications/applications.h

@@ -25,6 +25,7 @@ void u8g2_qrcode(void* p);
 void fatfs_list(void* p);
 void fatfs_list(void* p);
 void gui_task(void* p);
 void gui_task(void* p);
 void backlight_control(void* p);
 void backlight_control(void* p);
+void irda(void* p);
 void app_loader(void* p);
 void app_loader(void* p);
 void cc1101_workaround(void* p);
 void cc1101_workaround(void* p);
 void nfc_task(void* p);
 void nfc_task(void* p);
@@ -52,6 +53,10 @@ const FlipperStartupApp FLIPPER_STARTUP[] = {
     {.app = cc1101_workaround, .name = "cc1101 workaround", .libs = {1, FURI_LIB{"gui_task"}}},
     {.app = cc1101_workaround, .name = "cc1101 workaround", .libs = {1, FURI_LIB{"gui_task"}}},
 #endif
 #endif
 
 
+#ifdef APP_IRDA
+    {.app = irda, .name = "irda", .libs = {1, FURI_LIB{"gui_task"}}},
+#endif
+
 #ifdef APP_NFC
 #ifdef APP_NFC
     {.app = nfc_task, .name = "nfc_task", .libs = {1, FURI_LIB{"menu_task"}}},
     {.app = nfc_task, .name = "nfc_task", .libs = {1, FURI_LIB{"menu_task"}}},
 #endif
 #endif
@@ -96,4 +101,7 @@ const FlipperStartupApp FLIPPER_APPS[] = {
 #ifdef BUILD_CC1101
 #ifdef BUILD_CC1101
     {.app = cc1101_workaround, .name = "cc1101 workaround", .libs = {1, FURI_LIB{"gui_task"}}},
     {.app = cc1101_workaround, .name = "cc1101 workaround", .libs = {1, FURI_LIB{"gui_task"}}},
 #endif
 #endif
+#ifdef BUILD_IRDA
+    {.app = irda, .name = "irda", .libs = {1, FURI_LIB{"gui_task"}}},
+#endif
 };
 };

+ 14 - 0
applications/applications.mk

@@ -10,6 +10,7 @@ APP_RELEASE ?= 0
 ifeq ($(APP_RELEASE), 1)
 ifeq ($(APP_RELEASE), 1)
 APP_MENU = 1
 APP_MENU = 1
 APP_NFC  = 1
 APP_NFC  = 1
+BUILD_IRDA  = 1
 BUILD_EXAMPLE_BLINK = 1
 BUILD_EXAMPLE_BLINK = 1
 BUILD_EXAMPLE_UART_WRITE = 1
 BUILD_EXAMPLE_UART_WRITE = 1
 BUILD_EXAMPLE_INPUT_DUMP = 1
 BUILD_EXAMPLE_INPUT_DUMP = 1
@@ -142,6 +143,19 @@ APP_INPUT = 1
 APP_GUI = 1
 APP_GUI = 1
 endif
 endif
 
 
+APP_IRDA?= 0
+ifeq ($(APP_IRDA), 1)
+CFLAGS		+= -DAPP_IRDA
+BUILD_IRDA = 1
+endif
+BUILD_IRDA ?= 0
+ifeq ($(BUILD_IRDA), 1)
+CFLAGS		+= -DBUILD_IRDA
+C_SOURCES	+= $(wildcard $(APP_DIR)/irda/*.c)
+APP_INPUT = 1
+APP_GUI = 1
+endif
+
 # device drivers
 # device drivers
 
 
 APP_GUI	?= 0
 APP_GUI	?= 0

+ 238 - 0
applications/irda/irda.c

@@ -0,0 +1,238 @@
+#include "flipper.h"
+#include "flipper_v2.h"
+#include "irda_nec.h"
+#include "irda_protocols.h"
+
+typedef enum {
+    EventTypeTick,
+    EventTypeKey,
+} EventType;
+
+typedef struct {
+    union {
+        InputEvent input;
+    } value;
+    EventType type;
+} Event;
+
+typedef struct {
+    uint8_t mode_id;
+    uint16_t carrier_freq;
+    uint8_t carrier_duty_cycle_id;
+    uint8_t nec_packet_id;
+} State;
+
+typedef void (*ModeInput)(Event*, State*);
+typedef void (*ModeRender)(CanvasApi*, State*);
+
+void input_carrier(Event* event, State* state);
+void render_carrier(CanvasApi* canvas, State* state);
+void input_nec(Event* event, State* state);
+void render_nec(CanvasApi* canvas, State* state);
+
+typedef struct {
+    ModeRender render;
+    ModeInput input;
+} Mode;
+
+typedef struct {
+    uint8_t addr;
+    uint8_t data;
+} NecPacket;
+
+const Mode modes[] = {
+    {.render = render_carrier, .input = input_carrier},
+    {.render = render_nec, .input = input_nec},
+};
+
+const NecPacket packets[] = {
+    {.addr = 0xF7, .data = 0x59},
+    {.addr = 0xFF, .data = 0x01},
+    {.addr = 0xFF, .data = 0x10},
+    {.addr = 0xFF, .data = 0x15},
+    {.addr = 0xFF, .data = 0x25},
+    {.addr = 0xFF, .data = 0xF0},
+};
+
+const float duty_cycles[] = {0.1, 0.25, 0.333, 0.5, 1.0};
+
+void render_carrier(CanvasApi* canvas, State* state) {
+    canvas->set_font(canvas, FontSecondary);
+    canvas->draw_str(canvas, 2, 25, "carrier mode >");
+    canvas->draw_str(canvas, 2, 37, "? /\\ freq | \\/ duty cycle");
+    {
+        char buf[24];
+        sprintf(buf, "frequency: %d Hz", state->carrier_freq);
+        canvas->draw_str(canvas, 2, 50, buf);
+        sprintf(
+            buf,
+            "duty cycle: %d/1000",
+            (uint32_t)(duty_cycles[state->carrier_duty_cycle_id] * 1000));
+        canvas->draw_str(canvas, 2, 62, buf);
+    }
+}
+
+void render_nec(CanvasApi* canvas, State* state) {
+    canvas->set_font(canvas, FontSecondary);
+    canvas->draw_str(canvas, 2, 25, "< nec protocol mode");
+    canvas->draw_str(canvas, 2, 37, "? /\\ \\/ packet");
+    {
+        char buf[24];
+        sprintf(
+            buf,
+            "packet: %02X %02X",
+            packets[state->nec_packet_id].addr,
+            packets[state->nec_packet_id].data);
+        canvas->draw_str(canvas, 2, 50, buf);
+    }
+}
+
+void input_carrier(Event* event, State* state) {
+    if(event->value.input.input == InputOk) {
+        if(event->value.input.state) {
+            pwm_set(
+                duty_cycles[state->carrier_duty_cycle_id],
+                state->carrier_freq,
+                &htim2,
+                TIM_CHANNEL_4);
+        } else {
+            pwm_stop(&htim2, TIM_CHANNEL_4);
+        }
+    }
+
+    if(event->value.input.state && event->value.input.input == InputUp) {
+        if(state->carrier_freq < 45000) {
+            state->carrier_freq += 1000;
+        } else {
+            state->carrier_freq = 33000;
+        }
+    }
+
+    if(event->value.input.state && event->value.input.input == InputDown) {
+        uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
+        if(state->carrier_duty_cycle_id < (duty_cycles_count - 1)) {
+            state->carrier_duty_cycle_id++;
+        } else {
+            state->carrier_duty_cycle_id = 0;
+        }
+    }
+}
+
+void input_nec(Event* event, State* state) {
+    if(event->value.input.input == InputOk) {
+        if(event->value.input.state) {
+            vTaskSuspendAll();
+            ir_nec_send(packets[state->nec_packet_id].addr, packets[state->nec_packet_id].data);
+            xTaskResumeAll();
+        }
+    }
+
+    if(event->value.input.state && event->value.input.input == InputUp) {
+        uint8_t packets_count = sizeof(packets) / sizeof(packets[0]);
+        if(state->nec_packet_id < (packets_count - 1)) {
+            state->nec_packet_id++;
+        } else {
+            state->nec_packet_id = 0;
+        }
+    }
+
+    if(event->value.input.state && event->value.input.input == InputDown) {
+        uint8_t packets_count = sizeof(packets) / sizeof(packets[0]);
+        if(state->nec_packet_id > 0) {
+            state->nec_packet_id--;
+        } else {
+            state->nec_packet_id = packets_count - 1;
+        }
+    }
+}
+
+static void render_callback(CanvasApi* canvas, void* ctx) {
+    State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
+
+    canvas->clear(canvas);
+    canvas->set_color(canvas, ColorBlack);
+    canvas->set_font(canvas, FontPrimary);
+    canvas->draw_str(canvas, 2, 12, "irda test");
+
+    modes[state->mode_id].render(canvas, state);
+
+    release_mutex((ValueMutex*)ctx, state);
+}
+
+static void input_callback(InputEvent* input_event, void* ctx) {
+    osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
+
+    Event event;
+    event.type = EventTypeKey;
+    event.value.input = *input_event;
+    osMessageQueuePut(event_queue, &event, 0, 0);
+}
+
+void irda(void* p) {
+    osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(Event), NULL);
+
+    State _state;
+    uint8_t mode_count = sizeof(modes) / sizeof(modes[0]);
+    uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
+
+    _state.carrier_duty_cycle_id = duty_cycles_count - 2;
+    _state.carrier_freq = 36000;
+    _state.mode_id = 0;
+    _state.nec_packet_id = 0;
+
+    ValueMutex state_mutex;
+    if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
+        printf("cannot create mutex\n");
+        furiac_exit(NULL);
+    }
+
+    Widget* widget = widget_alloc();
+
+    widget_draw_callback_set(widget, render_callback, &state_mutex);
+    widget_input_callback_set(widget, input_callback, event_queue);
+
+    // Open GUI and register widget
+    GuiApi* gui = (GuiApi*)furi_open("gui");
+    if(gui == NULL) {
+        printf("gui is not available\n");
+        furiac_exit(NULL);
+    }
+    gui->add_widget(gui, widget, WidgetLayerFullscreen);
+
+    Event event;
+    while(1) {
+        osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
+        State* state = (State*)acquire_mutex_block(&state_mutex);
+
+        if(event_status == osOK) {
+            if(event.type == EventTypeKey) {
+                // press events
+                if(event.value.input.state && event.value.input.input == InputBack) {
+                    printf("[irda] bye!\n");
+                    // TODO remove all widgets create by app
+                    widget_enabled_set(widget, false);
+                    furiac_exit(NULL);
+                }
+
+                if(event.value.input.state && event.value.input.input == InputLeft) {
+                    if(state->mode_id > 0) {
+                        state->mode_id--;
+                    }
+                }
+
+                if(event.value.input.state && event.value.input.input == InputRight) {
+                    if(state->mode_id < (mode_count - 1)) {
+                        state->mode_id++;
+                    }
+                }
+
+                modes[state->mode_id].input(&event, state);
+            }
+        } else {
+            // event timeout
+        }
+
+        release_mutex(&state_mutex, state);
+        widget_update(widget);
+    }
+}

+ 46 - 0
applications/irda/irda_nec.c

@@ -0,0 +1,46 @@
+#include "flipper.h"
+#include "irda_nec.h"
+#include "irda_protocols.h"
+
+void ir_nec_preambula(void) {
+    // 9ms carrier + 4.5ms pause
+    pwm_set(NEC_DUTY_CYCLE, NEC_CARRIER_FREQUENCY, &htim2, TIM_CHANNEL_4);
+    delay_us(9000);
+    pwm_stop(&htim2, TIM_CHANNEL_4);
+    delay_us(4500);
+}
+
+void ir_nec_send_bit(bool bit) {
+    // 0 is 562.5us carrier + 1687.5us pause
+    // 1 is 562.5us carrier + 562.5us pause
+    pwm_set(NEC_DUTY_CYCLE, NEC_CARRIER_FREQUENCY, &htim2, TIM_CHANNEL_4);
+    delay_us(562.5);
+    pwm_stop(&htim2, TIM_CHANNEL_4);
+    if(bit) {
+        delay_us(562.5);
+    } else {
+        delay_us(1687.5);
+    }
+}
+
+void ir_nec_send_byte(uint8_t data) {
+    for(uint8_t i = 0; i < 8; i++) {
+        ir_nec_send_bit((data & (1 << (i))) != 0);
+    }
+}
+
+void ir_nec_send(uint8_t addr, uint8_t data) {
+    // nec protocol is:
+    // preambula + addr + inverse addr + command + inverse command + bit pulse
+    //
+    // oddly enough, my analyzer (https://github.com/ukw100/IRMP) displays the reverse command
+    // and I don’t know if this is my fault or a feature of the analyzer
+    // TODO: check the dictionary and check with a known remote
+    uint8_t nec_packet[4] = {addr, ~(uint8_t)addr, ~(uint8_t)data, data};
+    ir_nec_preambula();
+    ir_nec_send_byte(nec_packet[0]);
+    ir_nec_send_byte(nec_packet[1]);
+    ir_nec_send_byte(nec_packet[2]);
+    ir_nec_send_byte(nec_packet[3]);
+    ir_nec_send_bit(1);
+}

+ 4 - 0
applications/irda/irda_nec.h

@@ -0,0 +1,4 @@
+#pragma once
+#include "flipper.h"
+
+void ir_nec_send(uint8_t addr, uint8_t data);

+ 16 - 0
applications/irda/irda_protocols.h

@@ -0,0 +1,16 @@
+#pragma once
+
+// our tx pin is TIM2_CH4
+extern TIM_HandleTypeDef htim2;
+
+#define RC5_CARRIER_FREQUENCY 36000
+#define RC5_DUTY_CYCLE 0.33
+
+#define RC6_CARRIER_FREQUENCY 36000
+#define RC6_DUTY_CYCLE 0.33
+
+#define NEC_CARRIER_FREQUENCY 38000
+#define NEC_DUTY_CYCLE 0.33
+
+#define SIRC_CARRIER_FREQUENCY 40000
+#define SIRC_DUTY_CYCLE 0.5

+ 3 - 2
firmware/targets/f2/Inc/flipper_hal.h

@@ -35,10 +35,11 @@ static inline bool app_gpio_read(GpioPin gpio) {
 
 
     return false;
     return false;
 }
 }
-
-void delay_us(uint32_t time);
+void delay_us_init_DWT(void);
+void delay_us(float time);
 
 
 void pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel);
 void pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel);
+void pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel);
 
 
 extern TIM_HandleTypeDef htim8;
 extern TIM_HandleTypeDef htim8;
 
 

+ 2 - 0
firmware/targets/f2/Inc/tim.h

@@ -30,6 +30,7 @@
 
 
 /* USER CODE END Includes */
 /* USER CODE END Includes */
 
 
+extern TIM_HandleTypeDef htim2;
 extern TIM_HandleTypeDef htim5;
 extern TIM_HandleTypeDef htim5;
 extern TIM_HandleTypeDef htim8;
 extern TIM_HandleTypeDef htim8;
 extern TIM_HandleTypeDef htim15;
 extern TIM_HandleTypeDef htim15;
@@ -38,6 +39,7 @@ extern TIM_HandleTypeDef htim15;
 
 
 /* USER CODE END Private defines */
 /* USER CODE END Private defines */
 
 
+void MX_TIM2_Init(void);
 void MX_TIM5_Init(void);
 void MX_TIM5_Init(void);
 void MX_TIM8_Init(void);
 void MX_TIM8_Init(void);
 void MX_TIM15_Init(void);
 void MX_TIM15_Init(void);

+ 54 - 4
firmware/targets/f2/Makefile

@@ -1,5 +1,5 @@
 ##########################################################################################################################
 ##########################################################################################################################
-# File automatically-generated by tool: [projectgenerator] version: [3.10.0-B14] date: [Fri Oct 02 17:54:23 MSK 2020] 
+# File automatically-generated by tool: [projectgenerator] version: [3.10.0-B14] date: [Wed Oct 21 03:57:12 VLAT 2020] 
 ##########################################################################################################################
 ##########################################################################################################################
 
 
 # ------------------------------------------------
 # ------------------------------------------------
@@ -92,7 +92,48 @@ Src/system_stm32l4xx.c \
 /Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
 /Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
 /Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \
 /Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \
 /Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
 /Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
-Src/stm32l4xx_hal_timebase_tim.c
+Src/stm32l4xx_hal_timebase_tim.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pcd.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pcd_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_ll_usb.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_adc_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_comp.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_spi.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_spi_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart_ex.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/list.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/queue.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/timers.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
+C:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c
 
 
 # ASM sources
 # ASM sources
 ASM_SOURCES =  \
 ASM_SOURCES =  \
@@ -159,8 +200,17 @@ C_INCLUDES =  \
 -I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
 -I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
 -I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \
 -I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \
 -I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Device/ST/STM32L4xx/Include \
 -I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Device/ST/STM32L4xx/Include \
--I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Include
--I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Include
+-I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Include \
+-I/Users/aku/Work/flipper/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Include \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Inc \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/STM32L4xx_HAL_Driver/Inc/Legacy \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/include \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Device/ST/STM32L4xx/Include \
+-IC:/work/cmake-stm32/projects/flipperzero-firmware-community/lib/STM32CubeL4/Drivers/CMSIS/Include
 
 
 
 
 # compile gcc flags
 # compile gcc flags

+ 16 - 7
firmware/targets/f2/Src/flipper_hal.c

@@ -34,17 +34,22 @@ void app_gpio_init(GpioPin gpio, GpioMode mode) {
     }
     }
 }
 }
 
 
-// TODO delay from timer
-void delay_us(uint32_t time) {
-    time *= 11.8;
+void delay_us_init_DWT(void) {
+    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+    DWT->CYCCNT = 0U;
+}
 
 
-    while(time--) {
-    }
+void delay_us(float time) {
+    uint32_t start = DWT->CYCCNT;
+    uint32_t time_ticks = time * (SystemCoreClock / 1000000);
+    while((DWT->CYCCNT - start) < time_ticks) {
+    };
 }
 }
 
 
 void pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) {
 void pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) {
     tim->Init.CounterMode = TIM_COUNTERMODE_UP;
     tim->Init.CounterMode = TIM_COUNTERMODE_UP;
-    tim->Init.Period = (uint32_t)((SystemCoreClock / tim->Init.Prescaler) / freq);
+    tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq);
     tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
     tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
     tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
     tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
     HAL_TIM_PWM_Init(tim);
     HAL_TIM_PWM_Init(tim);
@@ -52,9 +57,13 @@ void pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel)
     TIM_OC_InitTypeDef sConfigOC;
     TIM_OC_InitTypeDef sConfigOC;
 
 
     sConfigOC.OCMode = TIM_OCMODE_PWM1;
     sConfigOC.OCMode = TIM_OCMODE_PWM1;
-    sConfigOC.Pulse = (uint16_t)(291 * value);
+    sConfigOC.Pulse = (uint16_t)(tim->Init.Period * value);
     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     HAL_TIM_PWM_ConfigChannel(tim, &sConfigOC, channel);
     HAL_TIM_PWM_ConfigChannel(tim, &sConfigOC, channel);
     HAL_TIM_PWM_Start(tim, channel);
     HAL_TIM_PWM_Start(tim, channel);
+}
+
+void pwm_stop(TIM_HandleTypeDef* tim, uint32_t channel) {
+    HAL_TIM_PWM_Stop(tim, channel);
 }
 }

+ 3 - 3
firmware/targets/f2/Src/gpio.c

@@ -59,7 +59,7 @@ void MX_GPIO_Init(void)
   HAL_GPIO_WritePin(GPIOB, LED_BLUE_Pin|LED_GREEN_Pin, GPIO_PIN_SET);
   HAL_GPIO_WritePin(GPIOB, LED_BLUE_Pin|LED_GREEN_Pin, GPIO_PIN_SET);
 
 
   /*Configure GPIO pin Output Level */
   /*Configure GPIO pin Output Level */
-  HAL_GPIO_WritePin(GPIOB, DISPLAY_RST_Pin|IR_TX_Pin|DISPLAY_BACKLIGHT_Pin, GPIO_PIN_RESET);
+  HAL_GPIO_WritePin(GPIOB, DISPLAY_RST_Pin|DISPLAY_BACKLIGHT_Pin, GPIO_PIN_RESET);
 
 
   /*Configure GPIO pin Output Level */
   /*Configure GPIO pin Output Level */
   HAL_GPIO_WritePin(GPIOC, VIBRO_Pin|DISPLAY_CS_Pin, GPIO_PIN_RESET);
   HAL_GPIO_WritePin(GPIOC, VIBRO_Pin|DISPLAY_CS_Pin, GPIO_PIN_RESET);
@@ -130,8 +130,8 @@ void MX_GPIO_Init(void)
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
 
-  /*Configure GPIO pins : PBPin PBPin PBPin */
-  GPIO_InitStruct.Pin = DISPLAY_RST_Pin|IR_TX_Pin|DISPLAY_BACKLIGHT_Pin;
+  /*Configure GPIO pins : PBPin PBPin */
+  GPIO_InitStruct.Pin = DISPLAY_RST_Pin|DISPLAY_BACKLIGHT_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

+ 3 - 0
firmware/targets/f2/Src/main.c

@@ -31,6 +31,7 @@
 /* Private includes ----------------------------------------------------------*/
 /* Private includes ----------------------------------------------------------*/
 /* USER CODE BEGIN Includes */
 /* USER CODE BEGIN Includes */
 #include "fatfs/fatfs.h"
 #include "fatfs/fatfs.h"
+#include "flipper_hal.h"
 /* USER CODE END Includes */
 /* USER CODE END Includes */
 
 
 /* Private typedef -----------------------------------------------------------*/
 /* Private typedef -----------------------------------------------------------*/
@@ -100,8 +101,10 @@ int main(void)
   MX_TIM15_Init();
   MX_TIM15_Init();
   MX_USART1_UART_Init();
   MX_USART1_UART_Init();
   MX_TIM8_Init();
   MX_TIM8_Init();
+  MX_TIM2_Init();
   /* USER CODE BEGIN 2 */
   /* USER CODE BEGIN 2 */
   MX_FATFS_Init();
   MX_FATFS_Init();
+  delay_us_init_DWT();
   /* USER CODE END 2 */
   /* USER CODE END 2 */
 
 
   /* Init scheduler */
   /* Init scheduler */

+ 2 - 4
firmware/targets/f2/Src/stm32l4xx_it.c

@@ -239,9 +239,8 @@ void EXTI9_5_IRQHandler(void)
 void TIM1_TRG_COM_TIM17_IRQHandler(void)
 void TIM1_TRG_COM_TIM17_IRQHandler(void)
 {
 {
   /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 0 */
   /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 0 */
-
-  /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 0 */
   HAL_TIM_IRQHandler(&htim17);
   HAL_TIM_IRQHandler(&htim17);
+  /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 0 */
   /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 1 */
   /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 1 */
 
 
   /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */
   /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */
@@ -282,9 +281,8 @@ void TIM8_CC_IRQHandler(void)
 void OTG_FS_IRQHandler(void)
 void OTG_FS_IRQHandler(void)
 {
 {
   /* USER CODE BEGIN OTG_FS_IRQn 0 */
   /* USER CODE BEGIN OTG_FS_IRQn 0 */
-
-  /* USER CODE END OTG_FS_IRQn 0 */
   HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
   HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
+  /* USER CODE END OTG_FS_IRQn 0 */
   /* USER CODE BEGIN OTG_FS_IRQn 1 */
   /* USER CODE BEGIN OTG_FS_IRQn 1 */
 
 
   /* USER CODE END OTG_FS_IRQn 1 */
   /* USER CODE END OTG_FS_IRQn 1 */

+ 116 - 29
firmware/targets/f2/Src/tim.c

@@ -24,10 +24,54 @@
 
 
 /* USER CODE END 0 */
 /* USER CODE END 0 */
 
 
+TIM_HandleTypeDef htim2;
 TIM_HandleTypeDef htim5;
 TIM_HandleTypeDef htim5;
 TIM_HandleTypeDef htim8;
 TIM_HandleTypeDef htim8;
 TIM_HandleTypeDef htim15;
 TIM_HandleTypeDef htim15;
 
 
+/* TIM2 init function */
+void MX_TIM2_Init(void)
+{
+  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
+  TIM_MasterConfigTypeDef sMasterConfig = {0};
+  TIM_OC_InitTypeDef sConfigOC = {0};
+
+  htim2.Instance = TIM2;
+  htim2.Init.Prescaler = 0;
+  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
+  htim2.Init.Period = 1684;
+  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
+  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
+  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sConfigOC.OCMode = TIM_OCMODE_PWM1;
+  sConfigOC.Pulse = 842;
+  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
+  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
+  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  HAL_TIM_MspPostInit(&htim2);
+
+}
 /* TIM5 init function */
 /* TIM5 init function */
 void MX_TIM5_Init(void)
 void MX_TIM5_Init(void)
 {
 {
@@ -155,27 +199,22 @@ void MX_TIM15_Init(void)
 
 
 }
 }
 
 
-void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
+void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
 {
 {
 
 
-  if(tim_pwmHandle->Instance==TIM5)
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(tim_baseHandle->Instance==TIM2)
   {
   {
-  /* USER CODE BEGIN TIM5_MspInit 0 */
+  /* USER CODE BEGIN TIM2_MspInit 0 */
 
 
-  /* USER CODE END TIM5_MspInit 0 */
-    /* TIM5 clock enable */
-    __HAL_RCC_TIM5_CLK_ENABLE();
-  /* USER CODE BEGIN TIM5_MspInit 1 */
+  /* USER CODE END TIM2_MspInit 0 */
+    /* TIM2 clock enable */
+    __HAL_RCC_TIM2_CLK_ENABLE();
+  /* USER CODE BEGIN TIM2_MspInit 1 */
 
 
-  /* USER CODE END TIM5_MspInit 1 */
+  /* USER CODE END TIM2_MspInit 1 */
   }
   }
-}
-
-void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
-{
-
-  GPIO_InitTypeDef GPIO_InitStruct = {0};
-  if(tim_baseHandle->Instance==TIM8)
+  else if(tim_baseHandle->Instance==TIM8)
   {
   {
   /* USER CODE BEGIN TIM8_MspInit 0 */
   /* USER CODE BEGIN TIM8_MspInit 0 */
 
 
@@ -203,6 +242,22 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
   }
   }
 }
 }
 
 
+void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
+{
+
+  if(tim_pwmHandle->Instance==TIM5)
+  {
+  /* USER CODE BEGIN TIM5_MspInit 0 */
+
+  /* USER CODE END TIM5_MspInit 0 */
+    /* TIM5 clock enable */
+    __HAL_RCC_TIM5_CLK_ENABLE();
+  /* USER CODE BEGIN TIM5_MspInit 1 */
+
+  /* USER CODE END TIM5_MspInit 1 */
+  }
+}
+
 void HAL_TIM_OC_MspInit(TIM_HandleTypeDef* tim_ocHandle)
 void HAL_TIM_OC_MspInit(TIM_HandleTypeDef* tim_ocHandle)
 {
 {
 
 
@@ -222,11 +277,32 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
 {
 {
 
 
   GPIO_InitTypeDef GPIO_InitStruct = {0};
   GPIO_InitTypeDef GPIO_InitStruct = {0};
-  if(timHandle->Instance==TIM5)
+  if(timHandle->Instance==TIM2)
+  {
+  /* USER CODE BEGIN TIM2_MspPostInit 0 */
+
+  /* USER CODE END TIM2_MspPostInit 0 */
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**TIM2 GPIO Configuration
+    PB11     ------> TIM2_CH4
+    */
+    GPIO_InitStruct.Pin = IR_TX_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
+    HAL_GPIO_Init(IR_TX_GPIO_Port, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN TIM2_MspPostInit 1 */
+
+  /* USER CODE END TIM2_MspPostInit 1 */
+  }
+  else if(timHandle->Instance==TIM5)
   {
   {
   /* USER CODE BEGIN TIM5_MspPostInit 0 */
   /* USER CODE BEGIN TIM5_MspPostInit 0 */
 
 
   /* USER CODE END TIM5_MspPostInit 0 */
   /* USER CODE END TIM5_MspPostInit 0 */
+
     __HAL_RCC_GPIOA_CLK_ENABLE();
     __HAL_RCC_GPIOA_CLK_ENABLE();
     /**TIM5 GPIO Configuration
     /**TIM5 GPIO Configuration
     PA3     ------> TIM5_CH4
     PA3     ------> TIM5_CH4
@@ -266,26 +342,21 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
 
 
 }
 }
 
 
-void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
+void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
 {
 {
 
 
-  if(tim_pwmHandle->Instance==TIM5)
+  if(tim_baseHandle->Instance==TIM2)
   {
   {
-  /* USER CODE BEGIN TIM5_MspDeInit 0 */
+  /* USER CODE BEGIN TIM2_MspDeInit 0 */
 
 
-  /* USER CODE END TIM5_MspDeInit 0 */
+  /* USER CODE END TIM2_MspDeInit 0 */
     /* Peripheral clock disable */
     /* Peripheral clock disable */
-    __HAL_RCC_TIM5_CLK_DISABLE();
-  /* USER CODE BEGIN TIM5_MspDeInit 1 */
+    __HAL_RCC_TIM2_CLK_DISABLE();
+  /* USER CODE BEGIN TIM2_MspDeInit 1 */
 
 
-  /* USER CODE END TIM5_MspDeInit 1 */
+  /* USER CODE END TIM2_MspDeInit 1 */
   }
   }
-}
-
-void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
-{
-
-  if(tim_baseHandle->Instance==TIM8)
+  else if(tim_baseHandle->Instance==TIM8)
   {
   {
   /* USER CODE BEGIN TIM8_MspDeInit 0 */
   /* USER CODE BEGIN TIM8_MspDeInit 0 */
 
 
@@ -306,6 +377,22 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
   }
   }
 }
 }
 
 
+void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
+{
+
+  if(tim_pwmHandle->Instance==TIM5)
+  {
+  /* USER CODE BEGIN TIM5_MspDeInit 0 */
+
+  /* USER CODE END TIM5_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_TIM5_CLK_DISABLE();
+  /* USER CODE BEGIN TIM5_MspDeInit 1 */
+
+  /* USER CODE END TIM5_MspDeInit 1 */
+  }
+}
+
 void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef* tim_ocHandle)
 void HAL_TIM_OC_MspDeInit(TIM_HandleTypeDef* tim_ocHandle)
 {
 {