servotester.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <furi_hal_clock.h>
  4. #include <furi_hal_pwm.h>
  5. #include <gui/gui.h>
  6. #include <input/input.h>
  7. #include <notification/notification_messages.h>
  8. #include <stdio.h>
  9. #define DEFAULT_FREQ 50
  10. #define DEFAULT_DUTY 1
  11. uint16_t pWidth = 1500;
  12. int8_t dir = 1;
  13. enum Modes {
  14. Center,
  15. Manual,
  16. Auto,
  17. };
  18. const char* const modes_text[Auto + 1] = {
  19. "Center",
  20. "Manual",
  21. " Auto",
  22. };
  23. uint8_t mode = Manual;
  24. typedef enum {
  25. EventTypeTick,
  26. EventTypeInput,
  27. } EventType;
  28. typedef struct {
  29. EventType type;
  30. InputEvent input;
  31. } ServoTesterEvent;
  32. static void servotester_draw_callback(Canvas* canvas, void* ctx) {
  33. UNUSED(ctx);
  34. char temp_str[36];
  35. canvas_clear(canvas);
  36. canvas_set_font(canvas, FontPrimary);
  37. canvas_draw_frame(canvas, 0, 0, 128, 64);
  38. canvas_draw_str(canvas, 35, 10, "Servo tester");
  39. canvas_draw_line(canvas, 14, 30, 114, 30);
  40. canvas_draw_line(canvas, 14, 30, 14, 20);
  41. canvas_draw_line(canvas, 114, 30, 114, 20);
  42. canvas_draw_frame(canvas, (pWidth - 1000) / 10.2 + 14, 20, 3, 10);
  43. snprintf(temp_str, sizeof(temp_str), "%i us", pWidth);
  44. canvas_draw_str(canvas, 50, 40, temp_str);
  45. canvas_draw_str(canvas, 50, 50, modes_text[mode]);
  46. }
  47. static void servotester_input_callback(InputEvent* input_event, void* ctx) {
  48. furi_assert(ctx);
  49. FuriMessageQueue* event_queue = ctx;
  50. ServoTesterEvent event = {.type = EventTypeInput, .input = *input_event};
  51. furi_message_queue_put(event_queue, &event, FuriWaitForever);
  52. }
  53. static void servotester_timer_callback(void* ctx) {
  54. furi_assert(ctx);
  55. FuriMessageQueue* event_queue = ctx;
  56. ServoTesterEvent event = {.type = EventTypeTick};
  57. furi_message_queue_put(event_queue, &event, 0);
  58. }
  59. void servotester_set_servo_pwm(uint32_t freq, uint32_t compare) {
  60. uint32_t freq_div = 64000000LU / freq;
  61. uint32_t prescaler = freq_div / 0x10000LU;
  62. uint32_t period = freq_div / (prescaler + 1);
  63. LL_TIM_SetPrescaler(TIM1, prescaler);
  64. LL_TIM_SetAutoReload(TIM1, period - 1);
  65. LL_TIM_OC_SetCompareCH1(TIM1, compare);
  66. }
  67. void servotester_update_pwm() {
  68. servotester_set_servo_pwm(DEFAULT_FREQ, pWidth * 3.2);
  69. }
  70. int32_t servotester_app(void* p) {
  71. UNUSED(p);
  72. ServoTesterEvent event;
  73. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(ServoTesterEvent));
  74. ViewPort* view_port = view_port_alloc();
  75. // callbacks init
  76. view_port_draw_callback_set(view_port, servotester_draw_callback, NULL);
  77. view_port_input_callback_set(view_port, servotester_input_callback, event_queue);
  78. Gui* gui = furi_record_open(RECORD_GUI);
  79. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  80. // Timer for automatic mode
  81. FuriTimer* timer =
  82. furi_timer_alloc(servotester_timer_callback, FuriTimerTypePeriodic, event_queue);
  83. furi_timer_start(timer, 5);
  84. //GPIO init
  85. furi_hal_power_enable_otg(); // Turn 5V
  86. furi_hal_pwm_start(FuriHalPwmOutputIdTim1PA7, 50, 4); // Init Tim1
  87. servotester_set_servo_pwm(DEFAULT_FREQ, pWidth * 3.2); // set our PWM
  88. while(1) {
  89. furi_check(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk);
  90. if(event.type == EventTypeInput) {
  91. if(event.input.key == InputKeyBack) {
  92. break;
  93. } else if(event.input.key == InputKeyOk) {
  94. if(event.input.type == InputTypeRelease) {
  95. if(mode == Auto) {
  96. mode = Center;
  97. } else {
  98. mode++;
  99. }
  100. if(mode == Center) {
  101. pWidth = 1500;
  102. servotester_update_pwm();
  103. }
  104. }
  105. } else if(event.input.key == InputKeyLeft) {
  106. if(pWidth > 1000) pWidth--;
  107. servotester_update_pwm();
  108. } else if(event.input.key == InputKeyRight) {
  109. if(pWidth < 2000) pWidth++;
  110. servotester_update_pwm();
  111. } else if(event.input.key == InputKeyDown) {
  112. if(pWidth >= 1010) pWidth -= 10;
  113. servotester_update_pwm();
  114. } else if(event.input.key == InputKeyUp) {
  115. if(pWidth <= 1990) pWidth += 10;
  116. servotester_update_pwm();
  117. }
  118. view_port_update(view_port);
  119. } else if(event.type == EventTypeTick) {
  120. if(mode == Auto) {
  121. pWidth += dir;
  122. if(pWidth > 1990 || pWidth < 1010) {
  123. dir = dir * -1;
  124. }
  125. servotester_update_pwm();
  126. }
  127. view_port_update(view_port);
  128. }
  129. view_port_update(view_port);
  130. }
  131. furi_hal_power_disable_otg();
  132. furi_hal_pwm_stop(FuriHalPwmOutputIdTim1PA7);
  133. furi_timer_free(timer);
  134. furi_message_queue_free(event_queue);
  135. gui_remove_view_port(gui, view_port);
  136. view_port_free(view_port);
  137. furi_record_close(RECORD_GUI);
  138. return 0;
  139. }