Page 1 of 2
Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Fri Apr 28, 2017 1:45 pm
by jesseb
I read that you would have support for input capture on esp32.
viewtopic.php?f=2&t=890
I’ve been waiting on this for a while, performing other tasks as I did so.
Now I have an urgent need of some documentation and/or example code.
I need this for pulse width measurement. I haven't been able to get high enough resolution by using interrupts and timers.
I also thought I might use the pulse counter with my control being the input (pulse I am measuring) and the counted signal being the output of pwm or timer on another gpio. The problem there is that I am actually already using all other gpios. If there was a way to map a timer signal to that internally then it would work.
If I could at least get some register info on how to mux timers and signals, I could get it working. If there is something out there on this already I have missed it.
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Fri Apr 28, 2017 2:20 pm
by ESP_igrr
I have had success using RMT peripheral to do accurate pulse width measurement. My use case was to digitize a PPM signal. RMT writes pulse widths to a block of RAM, so using it is very straightforward.
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Fri Apr 28, 2017 2:29 pm
by jesseb
Ok, I'll look into it. Get back to you if I have questions. Thanks!
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Fri Apr 28, 2017 2:34 pm
by jesseb
Would I be able to run rx line continuously and interrupt only on pulse widths equal to or greater than certain values? I am doing this for detecting short circuits in a board that powers valves. The higher the pulse width on my input signal the greater the current. If at or above a certain threshold I need to cut the power asap. I also have a lower threshold that I need to only allow pulses on for a certain period of time. Is there a way I can get rmt module to work for this. Sorry, should have explained better in the beginning.
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Fri Apr 28, 2017 5:29 pm
by Hans Dorn
Hi Jesse,
what resolution do you need for your pulse width measurement?
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Fri Apr 28, 2017 6:03 pm
by jesseb
I only need microsecond resolution and I thought I would get that with gpio isr and timer and interrupts but it wasn't quick enough every time.
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Sat Apr 29, 2017 3:12 pm
by ESP_Sprite
I think the motor PWM unit may actually be able to do it. Not sure if that's in the TRM yet, though...
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Mon May 01, 2017 6:52 pm
by jesseb
I have tried using the remote peripheral in some test code but can't get it working. The input signal on pin 36 is running at 60 hz but could be anywhere from 0 % duty cycle to 50 % duty cycle. I want to measure fairly accurately even the small pulses.
Right now I get an interrupt on every edge I see. I know this because I toggle a different IO represented by outputEnableMask and see both signals on a logic analyzer. The problem is that the length that is returned from rmt_get_mem_len is 0 and I also only get 0s in index one and two for item
.duration and junk in all of the rest.
If there is a way to get this working let me know. I'm not sure if I've messed something up i the initialization.
Code: Select all
//rmtTest.c
//
//Testing to see if we can use rmt module for pulse width measurement
// and quick response for short circuit detect
//
#include "myConfig.h"
#include "myOs.h"
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/rmt.h"
#include "driver/periph_ctrl.h"
#include "soc/rmt_reg.h"
#define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */
#define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */
#define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */
#define RMT_RX_GPIO_NUM 36 /*!< GPIO number for receiver */
#define RMT_CLK_DIV 160 /*!< RMT counter clock divider */
#define PW_PULSE_COUNT_MAX 10
static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel)
{
int block_num = RMT.conf_ch[channel].conf0.mem_size;
int item_block_len = block_num * RMT_MEM_ITEM_NUM;
volatile rmt_item32_t* data = RMTMEM.chan[channel].data32;
int idx;
for(idx = 0; idx < item_block_len; idx++) {
if(data[idx].duration0 == 0) {
return idx;
} else if(data[idx].duration1 == 0) {
return idx + 1;
}
}
return idx;
}
uint16_t recvBuffer[128];
uint32_t intCount = 0;
void IRAM_ATTR rmt_isr_handler(void* arg)
{
static uint8_t DRAM_ATTR toggle = 0;
//read RMT interrupt status
uint32_t intr_st = RMT.int_st.val;
if( RMT.int_st.ch0_rx_end )
{
RMT.conf_ch[RMT_RX_CHANNEL].conf1.rx_en = 0;
int item_len = rmt_get_mem_len(RMT_RX_CHANNEL);
//change memory owner to protect data.
RMT.conf_ch[RMT_RX_CHANNEL].conf1.mem_owner = RMT_MEM_OWNER_TX;
rmt_item16_t *item = RMTMEM.chan[RMT_RX_CHANNEL].data16;
if( toggle )
{
GPIO.out_w1tc = outputEnableMask;
}
else
{
GPIO.out_w1ts = outputEnableMask;
}
toggle ^= 1;
for(int i = 0; i < 8; ++i)
{
TRACE_ISR(("RX %d: %d %d %d\n", i, item[i].level, item[i].duration, !(GPIO.in1.data & shiftRegister_zeroCrossingMask)));
}
TRACE_ISR(("RX %d %X %X\n", ++intCount, intr_st, RMT.status_ch[RMT_RX_CHANNEL]));
RMT.conf_ch[RMT_RX_CHANNEL].conf1.mem_wr_rst = 1;
RMT.conf_ch[RMT_RX_CHANNEL].conf1.mem_owner = RMT_MEM_OWNER_RX;
RMT.conf_ch[RMT_RX_CHANNEL].conf1.rx_en = 1;
}
else if( RMT.int_st.ch0_err )
{
TRACE_ISR(("RMT ERR STATUS %X\n", RMT.status_ch[RMT_RX_CHANNEL]));
if( toggle )
{
GPIO.out_w1tc = outputEnableMask;
}
else
{
GPIO.out_w1ts = outputEnableMask;
}
toggle ^= 1;
}
RMT.int_clr.val = intr_st;
}
/*
* @brief RMT receiver initialization
*/
static void rx_init()
{
rmt_item16_t *item = RMTMEM.chan[RMT_RX_CHANNEL].data16;
rmt_config_t rmt_rx;
rmt_rx.channel = RMT_RX_CHANNEL;
rmt_rx.gpio_num = RMT_RX_GPIO_NUM;
rmt_rx.clk_div = RMT_CLK_DIV;
rmt_rx.mem_block_num = 1;
rmt_rx.rmt_mode = RMT_MODE_RX;
rmt_rx.rx_config.filter_en = true;
rmt_rx.rx_config.filter_ticks_thresh = 0xFF;
rmt_rx.rx_config.idle_threshold = 4000;
if( rmt_config(&rmt_rx) )
{
TRACE(("rmt config did not work\n"));
}
if( rmt_isr_register(rmt_isr_handler, NULL, ESP_INTR_FLAG_LEVEL1, 0) )
{
TRACE(("rmt interrupt could not be allocated\n"));
}
else
{
if(rmt_set_rx_intr_en(RMT_RX_CHANNEL, 1) || rmt_set_err_intr_en(RMT_RX_CHANNEL, 1))
{
TRACE(("rmt interrupt could not be enabled\n"));
}
}
RMT.apb_conf.fifo_mask = RMT_DATA_MODE_MEM;
TRACE_LINE;
}
void test_rmt(void)
{
gpio_config_t io_conf;
// Configure renesas reset line
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = outputEnableMask;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
if( gpio_config(&io_conf) )
{
TRACE(("ERROR SETTING UP IO\n"));
}
GPIO.out_w1ts = outputEnableMask;
rx_init();
rmt_rx_start(RMT_RX_CHANNEL, 1);
for(;;)
{
vpOs_delay_ms(2000);
intCount = 0;
TRACE_LINE;
}
}
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Tue May 02, 2017 1:20 am
by ESP_igrr
The input signal half-period seems to be longer than the timeout threshold:
#define RMT_CLK_DIV 160 /*!< RMT counter clock divider */
rmt_rx.rx_config.idle_threshold = 4000;
This means that one (divided) RMT clock cycle is 2us, and timeout is 8ms. At 60 Hz you need the timeout to be at least 8.33ms.
Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work
Posted: Tue May 02, 2017 1:49 am
by cjsm74x
In components/driver/include/driver/rmt.h I see this line:
Code: Select all
rmt_rx.rx_config.idle_threshold = 0xffff;
Is 65.535 the upper limit of the idle threshold?