RuiViana

Freq_Count.ino

Jul 5th, 2020
1,523
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. /*===================================================================================================*/
  3. // Counter_esp32_example.ino --> https://github.com/DavidAntliff/esp32-freqcount/pull/3/files
  4. // Frequency-count.c -->  https://github.com/DavidAntliff/esp32-freqcount/pull/3/files
  5. // Frequency-count.h --> https://github.com/DavidAntliff/esp32-freqcount/tree/master/include
  6.  
  7. // Funciona alterando a linha 176 para enable
  8. // Esta linha libera a contagem se controle
  9. // Estudar a liberacao do port RMT
  10. /*===================================================================================================*/
  11.  
  12. #include "frequency_count.h"
  13.  
  14. #define TAG "app"
  15.  
  16. char message[200];
  17.  
  18. #define CONFIG_FREQ_SIGNAL_GPIO 23
  19. #define CONFIG_SAMPLING_WINDOW_GPIO 2
  20.  
  21. #define GPIO_SIGNAL_INPUT ((gpio_num_t)CONFIG_FREQ_SIGNAL_GPIO)
  22. #define GPIO_RMT_GATE     (CONFIG_SAMPLING_WINDOW_GPIO)
  23. #define GPIO_LED          (25) //CONFIG_LED_GPIO)
  24.  
  25. // internal signals for GPIO constant levels
  26. #define GPIO_CONSTANT_LOW   0x30
  27. #define GPIO_CONSTANT_HIGH  0x38
  28.  
  29. #define PCNT_UNIT         (PCNT_UNIT_0)
  30. #define PCNT_CHANNEL      (PCNT_CHANNEL_0)
  31. #define RMT_CHANNEL       (RMT_CHANNEL_0)
  32. #define RMT_MAX_BLOCKS    (2)   // allow up to 2 * 64 * (2 * 32767) RMT periods in window
  33. //#define RMT_CLK_DIV       160   // results in 2us steps (80MHz / 160 = 0.5 MHz
  34. //#define RMT_CLK_DIV       20    // results in 0.25us steps (80MHz / 20 = 4 MHz
  35. #define RMT_CLK_DIV       1     // results in 25ns steps (80MHz / 2 / 1 = 40 MHz)
  36.  
  37. #define SAMPLE_PERIOD 1.2  // seconds
  38.  
  39. // The counter is signed 16-bit, so maximum positive value is 32767
  40. // The filter is unsigned 10-bit, maximum value is 1023. Use full period of maximum frequency.
  41. // For higher expected frequencies, the sample period and filter must be reduced.
  42.  
  43. // suitable up to 16,383.5 Hz
  44. //#define WINDOW_DURATION 1.0  // seconds
  45. //#define FILTER_LENGTH 1023  // APB @ 80MHz, limits to < 39,100 Hz
  46.  
  47. // suitable up to 163,835 Hz
  48. //#define WINDOW_DURATION 0.1  // seconds
  49. //#define FILTER_LENGTH 122  // APB @ 80MHz, limits to < 655,738 Hz
  50.  
  51. // suitable up to 1,638,350 Hz
  52. //#define WINDOW_DURATION 0.01  // seconds
  53. //#define FILTER_LENGTH 12  // APB @ 80MHz, limits to < 3,333,333 Hz
  54.  
  55. // suitable up to 16,383,500 Hz - no filter
  56. //#define WINDOW_DURATION 0.001  // seconds
  57. //#define FILTER_LENGTH 1  // APB @ 80MHz, limits to < 40 MHz
  58.  
  59. // suitable up to 163,835,000 Hz - no filter
  60. #define WINDOW_DURATION 0.0001  // seconds
  61. #define FILTER_LENGTH 0  // APB @ 80MHz, limits to < 40 MHz
  62. //--------------------------------------------------------------------------------
  63. static void window_start_callback(void)
  64. {
  65.   ESP_LOGI(TAG, "Begin sampling");
  66.   gpio_matrix_in(GPIO_SIGNAL_INPUT, SIG_IN_FUNC228_IDX, false);
  67. }
  68. //--------------------------------------------------------------------------------
  69. static volatile double frequency;
  70. static void frequency_callback(double hz)
  71. {
  72.   gpio_matrix_in(GPIO_CONSTANT_LOW, SIG_IN_FUNC228_IDX, false);
  73.   frequency = hz;
  74.   ESP_LOGI(TAG, "Frequency %f Hz", hz);
  75. }
  76. //--------------------------------------------------------------------------------
  77. static void config_led(void)
  78. {
  79.   gpio_pad_select_gpio(GPIO_LED);
  80.   gpio_set_direction((gpio_num_t)GPIO_LED, GPIO_MODE_OUTPUT);
  81.  
  82.   // route incoming frequency signal to onboard LED when sampling
  83.   gpio_matrix_out(GPIO_LED, SIG_IN_FUNC228_IDX, false, false);
  84. }
  85. //--------------------------------------------------------------------------------
  86. void setup()
  87. {
  88.   Serial.begin(115200);
  89.   Serial.println("Frequency counter starting");
  90.   delay(500);
  91.  
  92.   config_led();
  93.  
  94.   frequency_count_configuration_t * config = (frequency_count_configuration_t*)malloc(sizeof(*config));
  95.   config->pcnt_gpio = GPIO_SIGNAL_INPUT;
  96.   config->pcnt_unit = PCNT_UNIT;
  97.   config->pcnt_channel = PCNT_CHANNEL;
  98.   config->rmt_gpio = (gpio_num_t)GPIO_RMT_GATE;
  99.   config->rmt_channel = RMT_CHANNEL;
  100.   config->rmt_clk_div = RMT_CLK_DIV;
  101.   config->rmt_max_blocks = RMT_MAX_BLOCKS;
  102.   config->sampling_period_seconds = SAMPLE_PERIOD;
  103.   config->sampling_window_seconds = WINDOW_DURATION;
  104.   config->filter_length = FILTER_LENGTH;
  105.   config->window_start_callback = &window_start_callback;
  106.   config->frequency_update_callback = &frequency_callback;
  107.  
  108.   // task takes ownership of allocated memory
  109.   xTaskCreate(&frequency_count_task_function, "frequency_count_task", 4096, config, 5, NULL);
  110. }
  111. //--------------------------------------------------------------------------------
  112. void loop() {
  113.  
  114.   sprintf(message, "F=%9.0f Hz", frequency);
  115.   Serial.println(message);
  116.  
  117.   delay(100);
  118. }
  119. //--------------------------------------------------------------------------------
  120. static void init_rmt(gpio_num_t tx_gpio, rmt_channel_t channel, uint8_t clk_div)
  121. {
  122.   ESP_LOGD(TAG, "%s", __FUNCTION__);
  123.  
  124.   rmt_config_t rmt_tx;
  125.   rmt_tx.rmt_mode = RMT_MODE_TX;
  126.   rmt_tx.channel = channel;
  127.   rmt_tx.gpio_num = tx_gpio;
  128.   rmt_tx.mem_block_num = 1;  // single block
  129.   rmt_tx.clk_div = clk_div;
  130.  
  131.   rmt_tx.tx_config.loop_en = false;
  132.   rmt_tx.tx_config.carrier_en = false;
  133.   rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
  134.   rmt_tx.tx_config.idle_output_en = true;
  135.  
  136.   ESP_ERROR_CHECK(rmt_config(&rmt_tx));
  137.   ESP_ERROR_CHECK(rmt_driver_install(rmt_tx.channel, 0, 0));
  138. }
  139. //-------------------------------------------------------------------------------------------------------------------------
  140. static int create_rmt_window(rmt_item32_t * items, double sampling_window_seconds, double rmt_period)
  141. {
  142.   ESP_LOGD(TAG, "%s", __FUNCTION__);
  143.   int num_items = 0;
  144.   // enable counter for exactly x seconds:
  145.   int32_t total_duration = (uint32_t)(sampling_window_seconds / rmt_period);
  146.   ESP_LOGD(TAG, "total_duration %f seconds = %d * %g seconds", sampling_window_seconds, total_duration, rmt_period);
  147.   // max duration per item is 2^15-1 = 32767
  148.   while (total_duration > 0)
  149.   {
  150.     uint32_t duration = total_duration > 32767 ? 32767 : total_duration;
  151.     items[num_items].level0 = 1;
  152.     items[num_items].duration0 = duration;
  153.     total_duration -= duration;
  154.     ESP_LOGD(TAG, "duration %d", duration);
  155.     if (total_duration > 0)
  156.     {
  157.       uint32_t duration = total_duration > 32767 ? 32767 : total_duration;
  158.       items[num_items].level1 = 1;
  159.       items[num_items].duration1 = duration;
  160.       total_duration -= duration;
  161.     }
  162.     else
  163.     {
  164.       items[num_items].level1 = 0;
  165.       items[num_items].duration1 = 0;
  166.     }
  167.     ESP_LOGD(TAG, "[%d].level0 %d", num_items, items[num_items].level0);
  168.     ESP_LOGD(TAG, "[%d].duration0 %d", num_items, items[num_items].duration0);
  169.     ESP_LOGD(TAG, "[%d].level1 %d", num_items, items[num_items].level1);
  170.     ESP_LOGD(TAG, "[%d].duration1 %d", num_items, items[num_items].duration1);
  171.     ++num_items;
  172.   }
  173.   ESP_LOGD(TAG, "num_items %d", num_items);
  174.   return num_items;
  175. }
  176. //----------------------------------------------------------------------------------------------
  177. static void init_pcnt(gpio_num_t pulse_gpio, uint8_t ctrl_gpio, pcnt_unit_t unit, pcnt_channel_t channel, uint16_t filter_length)
  178. {
  179.   ESP_LOGD(TAG, "%s", __FUNCTION__);
  180.  
  181.   // set up counter
  182.   pcnt_config_t pcnt_config = {
  183.     .pulse_gpio_num = pulse_gpio,
  184.     .ctrl_gpio_num = ctrl_gpio,
  185.     .lctrl_mode = PCNT_MODE_KEEP,   //  <<<<<<<<<<<
  186.     .hctrl_mode = PCNT_MODE_KEEP,
  187.     .pos_mode = PCNT_COUNT_INC,  // count both rising and falling edges
  188.     .neg_mode = PCNT_COUNT_INC,
  189.     .counter_h_lim = 0,
  190.     .counter_l_lim = 0,
  191.     .unit = unit,
  192.     .channel = channel,
  193.   };
  194.   ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));
  195.   // set the GPIO back to high-impedance, as pcnt_unit_config sets it as pull-up
  196.   ESP_ERROR_CHECK(gpio_set_pull_mode(pulse_gpio, GPIO_FLOATING));
  197.   // enable counter filter - at 80MHz APB CLK, 1000 pulses is max 80,000 Hz, so ignore pulses less than 12.5 us.
  198.   ESP_ERROR_CHECK(pcnt_set_filter_value(unit, filter_length));
  199.   ESP_ERROR_CHECK(pcnt_filter_enable(unit));
  200. }
  201. //-------------------------------------------------------------------------------------------------------------------------
  202. void frequency_count_task_function(void * pvParameter)
  203. {
  204.   frequency_count_configuration_t configuration;
  205.   assert(pvParameter);
  206.   ESP_LOGI(TAG, "Core ID %d", xPortGetCoreID());
  207.   configuration = *(frequency_count_configuration_t*)pvParameter;
  208.   frequency_count_configuration_t *task_inputs = &configuration;
  209.   ESP_LOGI(TAG, "pcnt_gpio %d, pcnt_unit %d, pcnt_channel %d, rmt_gpio %d, rmt_clk_div %d, sampling_period_seconds %f, sampling_window_seconds %f, filter_length %d",
  210.            task_inputs->pcnt_gpio,
  211.            task_inputs->pcnt_unit,
  212.            task_inputs->pcnt_channel,
  213.            task_inputs->rmt_gpio,
  214.            task_inputs->rmt_clk_div,
  215.            task_inputs->sampling_period_seconds,
  216.            task_inputs->sampling_window_seconds,
  217.            task_inputs->filter_length);
  218.   init_rmt(task_inputs->rmt_gpio, task_inputs->rmt_channel, task_inputs->rmt_clk_div);
  219.   init_pcnt(task_inputs->pcnt_gpio, task_inputs->rmt_gpio, task_inputs->pcnt_unit, task_inputs->pcnt_channel, task_inputs->filter_length);
  220.   // assuming 80MHz APB clock
  221.   const double rmt_period = (double)(task_inputs->rmt_clk_div) / 80000000.0;
  222.  
  223.   const size_t items_size = RMT_MEM_BLOCK_BYTE_NUM * task_inputs->rmt_max_blocks;
  224.   rmt_item32_t * rmt_items = (rmt_item32_t *) malloc(items_size);
  225.   assert(rmt_items);
  226.   memset(rmt_items, 0, items_size);
  227.   int num_rmt_items = create_rmt_window(rmt_items, task_inputs->sampling_window_seconds, rmt_period);
  228.   assert(num_rmt_items <= task_inputs->rmt_max_blocks * RMT_MEM_ITEM_NUM);
  229.   TickType_t last_wake_time = xTaskGetTickCount();
  230.  
  231.  
  232.   Serial.print(" items_size "); Serial.println(items_size );
  233.    printf(" rmt_items: %d\n", *rmt_items);
  234.   Serial.print(" num_rmt_items "); Serial.println(num_rmt_items );
  235.  
  236.   double frequency_hz;
  237.   while (1)
  238.   {
  239.     last_wake_time = xTaskGetTickCount();
  240.     //Serial.println(last_wake_time);    ///   <<<<<<<<<<<<<<<<
  241.     // clear counter
  242.     ESP_ERROR_CHECK(pcnt_counter_clear(task_inputs->pcnt_unit));
  243.     // start sampling window
  244.     ESP_ERROR_CHECK(rmt_write_items(task_inputs->rmt_channel, rmt_items, num_rmt_items, false));
  245.     // call wndow-start callback if set
  246.     if (task_inputs->window_start_callback)
  247.     {
  248.       (task_inputs->window_start_callback)();
  249.     }
  250.     // wait for window to finish
  251.     ESP_ERROR_CHECK(rmt_wait_tx_done(task_inputs->rmt_channel, portMAX_DELAY));
  252.     // read counter
  253.  
  254.  
  255.     int16_t count = 0;
  256.     ESP_ERROR_CHECK(pcnt_get_counter_value(task_inputs->pcnt_unit, &count));
  257.  
  258.     // TODO: check for overflow?
  259.     //frequency_hz = count;
  260.     frequency_hz = (count >> 1) / task_inputs->sampling_window_seconds;
  261.  
  262.     // call the frequency update callback
  263.     if (task_inputs->frequency_update_callback)
  264.     {
  265.       (task_inputs->frequency_update_callback)(frequency_hz);
  266.     }
  267.     ESP_LOGD(TAG, "counter %d, frequency %f Hz", count, frequency_hz);
  268.     int delay_time = task_inputs->sampling_period_seconds * 1000 / portTICK_PERIOD_MS;
  269.     if (delay_time > 0)
  270.     {
  271.       vTaskDelayUntil(&last_wake_time, delay_time);
  272.     }
  273.   }
  274.   free(rmt_items);
  275.   free(task_inputs);  // TODO: avoid this if not dynamically allocated
  276.   vTaskDelete(NULL);
  277. }
RAW Paste Data