Index

auto-plow / 1b2c8f0

A wheelchair motor-propelled battery-powered ESP32-driven remote control snow plow.

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
8514 Jan 2023 16:171b2c8f0Update PPM interrupt handler to not use RTOS queues, write data directlyJosh Stockin13951G

Blob @ auto-plow / src / input.c

text/plain4581 bytesdownload raw
1// espy Copyright (c) 2023 Josh Stockin <josh@joshstock.in>
2// [https://joshstock.in] [https://github.com/joshuas3]
3//
4// This software is licensed and distributed under the terms of the MIT License.
5// See the MIT License in the LICENSE file of this project's root folder.
6//
7// This comment block and its contents, including this disclaimer, MUST be
8// preserved in all copies or distributions of this software's source.
9
10
11// Filename: input.c
12// Description: Handlers for radio receiver, rotary encoder
13
14
15#include "esp_attr.h"
16#include "esp_err.h"
17#include "esp_check.h"
18#include "esp_log.h"
19#include "freertos/FreeRTOS.h"
20#include "freertos/queue.h"
21#include "driver/gpio.h"
22#include "driver/gptimer.h"
23
24#include "input.h"
25#include "pins.h"
26
27
28static const char* TAG = "input.c";
29
30static uint8_t current_radio_channel = 0;
31static uint16_t radio_channels[NUM_RADIO_CHANNELS + 1] = {0};
32static bool updated = false;
33
34QueueHandle_t xInputQueue;
35gptimer_handle_t pulse_timer = NULL;
36
37esp_err_t setup_radio_and_rotenc_input( void ) {
38
39 ESP_LOGI( TAG, "creating input queue" );
40
41 xInputQueue = xQueueCreate( 400, sizeof( xInputEvent ) ); // xInputEvent from input.h
42 ESP_RETURN_ON_FALSE( xInputQueue != 0, ESP_FAIL, TAG, "xQueueCreate failed" );
43
44 ESP_LOGI( TAG, "configuring RADIO_PPM pin for input, pull_down_en" );
45
46 gpio_config_t radio_pin_conf = {
47 .pin_bit_mask = (1ULL << RADIO_PPM),
48 .mode = GPIO_MODE_INPUT,
49 .pull_down_en = 1,
50 .pull_up_en = 0,
51 };
52 ESP_RETURN_ON_ERROR( gpio_config( &radio_pin_conf ), TAG, "gpio_config failed" );
53
54 ESP_LOGI( TAG, "configuring and starting hardware gptimer (1MHz)" );
55
56 gptimer_config_t timer_config = {
57 .clk_src = GPTIMER_CLK_SRC_DEFAULT,
58 .direction = GPTIMER_COUNT_UP,
59 .resolution_hz = 1000000, // 1MHz, microsecond precision
60 };
61 ESP_RETURN_ON_ERROR( gptimer_new_timer( &timer_config, &pulse_timer ), TAG, "gptimer_new_timer failed" );
62 ESP_RETURN_ON_ERROR( gptimer_enable( pulse_timer ), TAG, "gptimer_enable failed" );
63 ESP_RETURN_ON_ERROR( gptimer_start( pulse_timer ), TAG, "gptimer_start failed" );
64
65 ESP_LOGI( TAG, "creating positive edge RADIO_PPM interrupt for radio_pulse callback" );
66
67 ESP_RETURN_ON_ERROR( gpio_set_intr_type( RADIO_PPM, GPIO_INTR_POSEDGE ), TAG, "gpio_set_intr_type failed" );
68 ESP_RETURN_ON_ERROR( gpio_isr_handler_add( RADIO_PPM, radio_pulse, NULL ), TAG, "gpio_isr_handler_add failed" );
69 ESP_RETURN_ON_ERROR( gpio_intr_enable( RADIO_PPM ), TAG, "gpio_intr_enable failed" );
70
71 // wakeup_enable not allowed for rising edge interrupts
72 // TODO: move to sleep handler
73 // ESP_RETURN_ON_ERROR( gpio_wakeup_enable( RADIO_PPM, GPIO_INTR_POSEDGE ), TAG, "gpio_wakeup_enable failed" );
74
75 ESP_LOGI( TAG, "creating input handler task" );
76
77 TaskHandle_t input_task = NULL;
78 xTaskCreate( input_handler_task, "input_handler_task", 2048, NULL, 20, &input_task ); // stack size 400 bytes, priority 2
79
80 ESP_LOGI( TAG, "input setup done" );
81
82 return ESP_OK;
83
84}
85
86void IRAM_ATTR radio_pulse( void* arg ) {
87
88 // get pulse timer value
89 uint64_t offset = 0;
90 gptimer_get_raw_count( pulse_timer, &offset );
91
92 if (offset >= RADIO_PULSE_STOPGAP_US || current_radio_channel == NUM_RADIO_CHANNELS) {
93 radio_channels[NUM_RADIO_CHANNELS] = offset;
94 current_radio_channel = 0;
95 } else {
96 radio_channels[current_radio_channel++] = offset;
97 }
98 updated = true;
99
100 // reset timer
101 gptimer_set_raw_count( pulse_timer, 0 );
102
103}
104
105void input_handler_task( void* arg ) {
106 // clears input event queue
107
108 //xInputEvent event;
109 for ( ;; ) {
110 /*
111 while ( xQueueReceive( xInputQueue, &event, 2 ) ) {
112
113 if ( event.type == INPUT_EVENT_RADIOPULSE ) {
114 // ppm radio receiver handling
115
116 } else if ( event.type == INPUT_EVENT_ROTENCSW ) {
117
118 // TODO
119
120 } else if ( event.type == INPUT_EVENT_ROTENCTURN ) {
121
122 // TODO
123
124 }
125
126 }*/
127 if (updated) {
128 ESP_LOGD( TAG, "\nCHANNELS\nch1: %u\nch2: %u\nch3: %u\nch4: %u\nch5: %u\nch6: %u\nch7: %u\nch8: %u\nch9: %u\nch10: %u\ngap dist: %u\n", radio_channels[0], radio_channels[1], radio_channels[2], radio_channels[3], radio_channels[4], radio_channels[5], radio_channels[6], radio_channels[7], radio_channels[8], radio_channels[9], radio_channels[10] );
129 updated = false;
130 }
131
132 vTaskDelay(10);
133 taskYIELD(); // queue is empty, don't waste anymore processor time
134 }
135
136}
137