Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby jesseb » Fri Apr 28, 2017 1:45 pm

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.

ESP_igrr
Posts: 2067
Joined: Tue Dec 01, 2015 8:37 am

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby ESP_igrr » Fri Apr 28, 2017 2:20 pm

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.

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby jesseb » Fri Apr 28, 2017 2:29 pm

Ok, I'll look into it. Get back to you if I have questions. Thanks!
Last edited by jesseb on Wed May 03, 2017 6:15 pm, edited 2 times in total.

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby jesseb » Fri Apr 28, 2017 2:34 pm

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.

Hans Dorn
Posts: 62
Joined: Tue Feb 21, 2017 2:21 am

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby Hans Dorn » Fri Apr 28, 2017 5:29 pm

Hi Jesse,

what resolution do you need for your pulse width measurement?

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby jesseb » Fri Apr 28, 2017 6:03 pm

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.

ESP_Sprite
Posts: 8884
Joined: Thu Nov 26, 2015 4:08 am

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby ESP_Sprite » Sat Apr 29, 2017 3:12 pm

I think the motor PWM unit may actually be able to do it. Not sure if that's in the TRM yet, though...

jesseb
Posts: 29
Joined: Tue Jan 10, 2017 5:36 pm

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby jesseb » Mon May 01, 2017 6:52 pm

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;
    }
}

ESP_igrr
Posts: 2067
Joined: Tue Dec 01, 2015 8:37 am

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby ESP_igrr » Tue May 02, 2017 1:20 am

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.

cjsm74x
Posts: 12
Joined: Wed Nov 25, 2015 10:16 pm

Re: Urgent Need for Pulse Width Measurement, Register/Hardware Descriptions Would Work

Postby cjsm74x » Tue May 02, 2017 1:49 am

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?

Who is online

Users browsing this forum: No registered users and 62 guests