servotester.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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(FuriMessageQueue* event_queue) {
  54. furi_assert(event_queue);
  55. ServoTesterEvent event = {.type = EventTypeTick};
  56. furi_message_queue_put(event_queue, &event, 0);
  57. }
  58. void servotester_set_servo_pwm(uint32_t freq, uint32_t compare) {
  59. uint32_t freq_div = 64000000LU / freq;
  60. uint32_t prescaler = freq_div / 0x10000LU;
  61. uint32_t period = freq_div / (prescaler + 1);
  62. LL_TIM_SetPrescaler(TIM1, prescaler);
  63. LL_TIM_SetAutoReload(TIM1, period - 1);
  64. LL_TIM_OC_SetCompareCH1(TIM1, compare);
  65. }
  66. void servotester_update_pwm() {
  67. servotester_set_servo_pwm(DEFAULT_FREQ, pWidth * 3.2);
  68. }
  69. int32_t servotester_app(void* p) {
  70. UNUSED(p);
  71. ServoTesterEvent event;
  72. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(ServoTesterEvent));
  73. ViewPort* view_port = view_port_alloc();
  74. // callbacks init
  75. view_port_draw_callback_set(view_port, servotester_draw_callback, NULL);
  76. view_port_input_callback_set(view_port, servotester_input_callback, event_queue);
  77. Gui* gui = furi_record_open(RECORD_GUI);
  78. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  79. // Timer for automatic mode
  80. FuriTimer* timer =
  81. furi_timer_alloc(servotester_timer_callback, FuriTimerTypePeriodic, event_queue);
  82. furi_timer_start(timer, 5);
  83. //GPIO init
  84. furi_hal_power_enable_otg(); // Turn 5V
  85. furi_hal_pwm_start(FuriHalPwmOutputIdTim1PA7, 50, 4); // Init Tim1
  86. servotester_set_servo_pwm(DEFAULT_FREQ, pWidth * 3.2); // set our PWM
  87. while(1) {
  88. furi_check(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk);
  89. if(event.type == EventTypeInput) {
  90. if(event.input.key == InputKeyBack) {
  91. break;
  92. } else if(event.input.key == InputKeyOk) {
  93. if(event.input.type == InputTypeRelease) {
  94. if(mode == Auto) {
  95. mode = Center;
  96. } else {
  97. mode++;
  98. }
  99. if(mode == Center) {
  100. pWidth = 1500;
  101. servotester_update_pwm();
  102. }
  103. }
  104. } else if(event.input.key == InputKeyLeft) {
  105. if(pWidth > 1000) pWidth--;
  106. servotester_update_pwm();
  107. } else if(event.input.key == InputKeyRight) {
  108. if(pWidth < 2000) pWidth++;
  109. servotester_update_pwm();
  110. } else if(event.input.key == InputKeyDown) {
  111. if(pWidth >= 1010) pWidth -= 10;
  112. servotester_update_pwm();
  113. } else if(event.input.key == InputKeyUp) {
  114. if(pWidth <= 1990) pWidth += 10;
  115. servotester_update_pwm();
  116. }
  117. view_port_update(view_port);
  118. } else if(event.type == EventTypeTick) {
  119. if(mode == Auto) {
  120. pWidth += dir;
  121. if(pWidth > 1990 || pWidth < 1010) {
  122. dir = dir * -1;
  123. }
  124. servotester_update_pwm();
  125. }
  126. view_port_update(view_port);
  127. }
  128. view_port_update(view_port);
  129. }
  130. furi_hal_power_disable_otg();
  131. furi_hal_pwm_stop(FuriHalPwmOutputIdTim1PA7);
  132. furi_timer_free(timer);
  133. furi_message_queue_free(event_queue);
  134. gui_remove_view_port(gui, view_port);
  135. view_port_free(view_port);
  136. furi_record_close(RECORD_GUI);
  137. return 0;
  138. }