I have connected the function generator to esp to give frequency and changed the code as below to only receive the data.
i am giving 46hz frequency from generator [ i have mesured with CRO, it is as expected ].
Code sample :
/* NEC remote infrared RMT example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#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"
static const char* NEC_TAG = "NEC";
//CHOOSE SELF TEST OR NORMAL TEST
#define RMT_RX_SELF_TEST 0 /// changed to 0
/******************************************************/
/***** SELF TEST: *****/
/*Connect RMT_TX_GPIO_NUM with RMT_RX_GPIO_NUM */
/*TX task will send NEC data with carrier disabled */
/*RX task will print NEC data it receives. */
/******************************************************/
#if RMT_RX_SELF_TEST
#define RMT_RX_ACTIVE_LEVEL 1 /*!< Data bit is active high for self test mode */
#define RMT_TX_CARRIER_EN 0 /*!< Disable carrier for self test mode */
#else
//Test with infrared LED, we have to enable carrier for transmitter
//When testing via IR led, the receiver waveform is usually active-low.
#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 */
#endif
#define RMT_TX_CHANNEL 1 /*!< RMT channel for transmitter */
#define RMT_TX_GPIO_NUM 18 /*!< GPIO number for transmitter signal */
#define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */
#define RMT_RX_GPIO_NUM 19 /*!< GPIO number for receiver */
#define RMT_CLK_DIV 100 /*!< RMT counter clock divider */
#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */
#define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */
#define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/
#define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */
#define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */
#define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */
#define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */
#define NEC_BIT_END 560 /*!< NEC protocol end: positive 0.56ms */
#define NEC_BIT_MARGIN 20 /*!< NEC parse margin time */
#define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */
#define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */
#define RMT_TX_DATA_NUM 100 /*!< NEC tx test data number */
#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */
/*
* @brief Build register value of waveform for NEC one data bit
*/
static inline void nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us)
{
item->level0 = 1;
item->duration0 = (high_us) / 10 * RMT_TICK_10_US;
item->level1 = 0;
item->duration1 = (low_us) / 10 * RMT_TICK_10_US;
}
/*
* @brief Generate NEC header value: active 9ms + negative 4.5ms
*/
static void nec_fill_item_header(rmt_item32_t* item)
{
nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US);
}
/*
* @brief Generate NEC data bit 1: positive 0.56ms + negative 1.69ms
*/
static void nec_fill_item_bit_one(rmt_item32_t* item)
{
nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US);
}
/*
* @brief Generate NEC data bit 0: positive 0.56ms + negative 0.56ms
*/
static void nec_fill_item_bit_zero(rmt_item32_t* item)
{
nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US);
}
/*
* @brief Generate NEC end signal: positive 0.56ms
*/
static void nec_fill_item_end(rmt_item32_t* item)
{
nec_fill_item_level(item, NEC_BIT_END, 0x7fff);
}
/*
* @brief Check whether duration is around target_us
*/
inline bool nec_check_in_range(int duration_ticks, int target_us, int margin_us)
{
if(( NEC_ITEM_DURATION(duration_ticks) < (target_us + margin_us))
&& ( NEC_ITEM_DURATION(duration_ticks) > (target_us - margin_us))) {
return true;
} else {
return false;
}
}
/*
* @brief Check whether this value represents an NEC header
*/
static bool nec_header_if(rmt_item32_t* item)
{
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
&& nec_check_in_range(item->duration0, NEC_HEADER_HIGH_US, NEC_BIT_MARGIN)
&& nec_check_in_range(item->duration1, NEC_HEADER_LOW_US, NEC_BIT_MARGIN)) {
return true;
}
return false;
}
/*
* @brief Check whether this value represents an NEC data bit 1
*/
static bool nec_bit_one_if(rmt_item32_t* item)
{
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
&& nec_check_in_range(item->duration0, NEC_BIT_ONE_HIGH_US, NEC_BIT_MARGIN)
&& nec_check_in_range(item->duration1, NEC_BIT_ONE_LOW_US, NEC_BIT_MARGIN)) {
return true;
}
return false;
}
/*
* @brief Check whether this value represents an NEC data bit 0
*/
static bool nec_bit_zero_if(rmt_item32_t* item)
{
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
&& nec_check_in_range(item->duration0, NEC_BIT_ZERO_HIGH_US, NEC_BIT_MARGIN)
&& nec_check_in_range(item->duration1, NEC_BIT_ZERO_LOW_US, NEC_BIT_MARGIN)) {
return true;
}
return false;
}
/*
* @brief Parse NEC 32 bit waveform to address and command.
*/
static int nec_parse_items(rmt_item32_t* item, int item_num, uint16_t* addr, uint16_t* data)
{
int w_len = item_num;
if(w_len < NEC_DATA_ITEM_NUM) {
return -1;
}
int i = 0, j = 0;
if(!nec_header_if(item++)) {
return -1;
}
uint16_t addr_t = 0;
for(j = 0; j < 16; j++) {
if(nec_bit_one_if(item)) {
addr_t |= (1 << j);
} else if(nec_bit_zero_if(item)) {
addr_t |= (0 << j);
} else {
return -1;
}
item++;
i++;
}
uint16_t data_t = 0;
for(j = 0; j < 16; j++) {
if(nec_bit_one_if(item)) {
data_t |= (1 << j);
} else if(nec_bit_zero_if(item)) {
data_t |= (0 << j);
} else {
return -1;
}
item++;
i++;
}
*addr = addr_t;
*data = data_t;
return i;
}
/*
* @brief Build NEC 32bit waveform.
*/
static int nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16_t addr, uint16_t cmd_data)
{
int i = 0, j = 0;
if(item_num < NEC_DATA_ITEM_NUM) {
return -1;
}
nec_fill_item_header(item++);
i++;
for(j = 0; j < 16; j++) {
if(addr & 0x1) {
nec_fill_item_bit_one(item);
} else {
nec_fill_item_bit_zero(item);
}
item++;
i++;
addr >>= 1;
}
for(j = 0; j < 16; j++) {
if(cmd_data & 0x1) {
nec_fill_item_bit_one(item);
} else {
nec_fill_item_bit_zero(item);
}
item++;
i++;
cmd_data >>= 1;
}
nec_fill_item_end(item);
i++;
return i;
}
/*
* @brief RMT transmitter initialization
*/
static void nec_tx_init()
{
rmt_config_t rmt_tx;
rmt_tx.channel = RMT_TX_CHANNEL;
rmt_tx.gpio_num = RMT_TX_GPIO_NUM;
rmt_tx.mem_block_num = 1;
rmt_tx.clk_div = RMT_CLK_DIV;
rmt_tx.tx_config.loop_en = false;
rmt_tx.tx_config.carrier_duty_percent = 50;
rmt_tx.tx_config.carrier_freq_hz = 38000;
rmt_tx.tx_config.carrier_level = 1;
rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
rmt_tx.tx_config.idle_level = 0;
rmt_tx.tx_config.idle_output_en = true;
rmt_tx.rmt_mode = 0;
rmt_config(&rmt_tx);
rmt_driver_install(rmt_tx.channel, 0, 0);
}
/*
* @brief RMT receiver initialization
*/
static void nec_rx_init()
{
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 = 100;
rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
rmt_config(&rmt_rx);
rmt_driver_install(rmt_rx.channel, 1000, 0);
}
/**
* @brief RMT receiver demo, this task will print each received NEC data.
*
*/
static void rmt_example_nec_rx_task()
{
int channel = RMT_RX_CHANNEL;
nec_rx_init();
RingbufHandle_t rb = NULL;
//get RMT RX ringbuffer
rmt_get_ringbuf_handle(channel, &rb);
rmt_rx_start(channel, 1);
while(rb) {
size_t rx_size = 0;
//try to receive data from ringbuffer.
//RMT driver will push all the data it receives to its ringbuffer.
//We just need to parse the value and return the spaces of ringbuffer.
rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000);
if(item) {
ESP_LOGI(NEC_TAG, "rx_size : %d",rx_size);
/// commented parsing logic
/*
uint16_t rmt_addr;
uint16_t rmt_cmd;
int offset = 0;
while(1) {
//parse data value from ringbuffer.
int res = nec_parse_items(item + offset, rx_size / 4 - offset, &rmt_addr, &rmt_cmd);
if(res > 0) {
offset += res + 1;
ESP_LOGI(NEC_TAG, "RMT RCV --- addr: 0x%04x cmd: 0x%04x", rmt_addr, rmt_cmd);
} else {
break;
}
}*/
//after parsing the data, return spaces to ringbuffer.
vRingbufferReturnItem(rb, (void*) item);
} else {
break;
}
}
vTaskDelete(NULL);
}
/**
* @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.)
*
*/
static void rmt_example_nec_tx_task()
{
vTaskDelay(10);
nec_tx_init();
esp_log_level_set(NEC_TAG, ESP_LOG_INFO);
int channel = RMT_TX_CHANNEL;
uint16_t cmd = 0x0;
uint16_t addr = 0x11;
int nec_tx_num = RMT_TX_DATA_NUM;
for(;;) {
ESP_LOGI(NEC_TAG, "RMT TX DATA");
size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num);
//each item represent a cycle of waveform.
rmt_item32_t* item = (rmt_item32_t*) malloc(size);
int item_num = NEC_DATA_ITEM_NUM * nec_tx_num;
memset((void*) item, 0, size);
int i, offset = 0;
while(1) {
//To build a series of waveforms.
i = nec_build_items(channel, item + offset, item_num - offset, ((~addr) << 8) | addr, ((~cmd) << 8) | cmd);
if(i < 0) {
break;
}
cmd++;
addr++;
offset += i;
}
//To send data according to the waveform items.
rmt_write_items(channel, item, item_num, true);
//Wait until sending is done.
rmt_wait_tx_done(channel, portMAX_DELAY);
//before we free the data, make sure sending is already done.
free(item);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
void app_main()
{
xTaskCreate(rmt_example_nec_rx_task, "rmt_nec_rx_task", 2048, NULL, 10, NULL);
//~ xTaskCreate(rmt_example_nec_tx_task, "rmt_nec_tx_task", 2048, NULL, 10, NULL); /// commented
}
For this code i am getting following output.
rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5800
load:0x40078000,len:7684
load:0x40080000,len:7392
entry 0x4008039c
I (28) boot: ESP-IDF v3.2-dev-57-ge75628b 2nd stage bootloader
I (29) boot: compile time 10:38:17
I (29) boot: Enabling RNG early entropy source...
I (34) boot: SPI Speed : 40MHz
I (38) boot: SPI Mode : DIO
I (42) boot: SPI Flash Size : 4MB
I (46) boot: Partition Table:
I (50) boot: ## Label Usage Type ST Offset Length
I (57) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (65) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (72) boot: 2 factory factory app 00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x070a4 ( 28836) map
I (103) esp_image: segment 1: paddr=0x000170cc vaddr=0x3ffb0000 size=0x022f0 ( 8944) load
I (107) esp_image: segment 2: paddr=0x000193c4 vaddr=0x3ffb22f0 size=0x00000 ( 0) load
I (111) esp_image: segment 3: paddr=0x000193cc vaddr=0x40080000 size=0x00400 ( 1024) load
I (120) esp_image: segment 4: paddr=0x000197d4 vaddr=0x40080400 size=0x0683c ( 26684) load
I (140) esp_image: segment 5: paddr=0x00020018 vaddr=0x400d0018 size=0x12818 ( 75800) map
I (166) esp_image: segment 6: paddr=0x00032838 vaddr=0x40086c3c size=0x02dd4 ( 11732) load
I (172) esp_image: segment 7: paddr=0x00035614 vaddr=0x400c0000 size=0x00000 ( 0) load
I (173) esp_image: segment 8: paddr=0x0003561c vaddr=0x50000000 size=0x00000 ( 0) load
I (188) boot: Loaded app from partition at offset 0x10000
I (188) boot: Disabling RNG early entropy source...
I (194) cpu_start: Pro cpu up.
I (197) cpu_start: Starting app cpu, entry point is 0x40080ef8
I (0) cpu_start: App cpu up.
I (208) heap_init: Initializing. RAM available for dynamic allocation:
I (215) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (221) heap_init: At 3FFB3370 len 0002CC90 (179 KiB): DRAM
I (227) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (233) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (240) heap_init: At 40089A10 len 000165F0 (89 KiB): IRAM
I (246) cpu_start: Pro cpu start user code
I (264) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (10) NEC: rx_size : 0
I (20) NEC: rx_size : 0
I (30) NEC: rx_size : 0
I (40) NEC: rx_size : 0
I (50) NEC: rx_size : 0
I (60) NEC: rx_size : 0
I (70) NEC: rx_size : 0
I (80) NEC: rx_size : 0
I (90) NEC: rx_size : 0
I (485) NEC: rx_size : 0
So , i am not able to receive any data in ring buffer.
Also , if i give frequency above 55 Hz then i am getting following error.
E (1040) rmt: RMT[0] ERR
E (1040) rmt: status: 0x13000040
How to overcome from this issue?
thanks in advance.
RMT iterface is not working when giving the pulse from outside
-
- Posts: 2
- Joined: Wed Oct 24, 2018 1:54 pm
Re: RMT iterface is not working when giving the pulse from outside
Hi ESP_Angus, WiFive and SDK Developers,
Would you please check below thread with few queries regarding RMT Interface Validation? We have requirement to measure 10 msec to 800 msec pulses into different I/O pins.
But, We are facing some issues and also getting error while reading data from Ring Buffer.
Will RMT Interface worked really to measure continuous pulses as per mentioned intervals (10-700 msec)? I need your guidance and feedback for same with more details regarding same.
Would you please check below thread with few queries regarding RMT Interface Validation? We have requirement to measure 10 msec to 800 msec pulses into different I/O pins.
But, We are facing some issues and also getting error while reading data from Ring Buffer.
Will RMT Interface worked really to measure continuous pulses as per mentioned intervals (10-700 msec)? I need your guidance and feedback for same with more details regarding same.
Regards,
Ritesh Prajapati
Ritesh Prajapati
Re: RMT iterface is not working when giving the pulse from outside
Hi ESP_Angus, WiFive and SDK Developers,
Do you have any idea or any information regarding RMT Interface details with example how it is working? Also, I have posted few requirements for Pulse Timing Measurement which we require into our project.
So, Would you please check it and provide suggestions for same from your end? So that it will helpful for us to take decision as early as possible before starting project development.
Do you have any idea or any information regarding RMT Interface details with example how it is working? Also, I have posted few requirements for Pulse Timing Measurement which we require into our project.
So, Would you please check it and provide suggestions for same from your end? So that it will helpful for us to take decision as early as possible before starting project development.
Regards,
Ritesh Prajapati
Ritesh Prajapati
Re: RMT iterface is not working when giving the pulse from outside
Hi Ritesh, sorry I have not read all your post so hope this is helpful, but I measure 30-200Hz frequency and pulse width using RMT. I realised that if you want to do this on a continuous pulse train you have to empty the buffer yourself or you will get no result and get a timer overflow.
Re: RMT iterface is not working when giving the pulse from outside
Hi,jcsbanks wrote:Hi Ritesh, sorry I have not read all your post so hope this is helpful, but I measure 30-200Hz frequency and pulse width using RMT. I realised that if you want to do this on a continuous pulse train you have to empty the buffer yourself or you will get no result and get a timer overflow.
Thanks for Reply.
Right now, We have bypassed Ring Buffer component which is being used to read readings measured on configured channel over RMT Interface and we are getting some positive results with that.
So, We have also updated few configurations specific for RMT Interface but we want to read pulses between 1 msec to 800 msec over different I/O channels
Regards,
Ritesh Prajapati
Ritesh Prajapati
-
- Posts: 2
- Joined: Wed Oct 24, 2018 1:54 pm
Re: RMT iterface is not working when giving the pulse from outside
I have tested the RMT interface with following test cases.
1. frequency 80 mhz [ APB Clock ]
- with limited pulses we are getting the data on ring buffer.
- with continuous pulses we are not getting the data on ring buffer.
- But, if we by pass the buffer we are able to achive the results.
2. frequency 1 mhz
- with limited / continuous pulses we are not getting the data on ring buffer.
- But, if we by pass the buffer we are able to achive the results.
So , is it expected behavior ?
For bypass the buffer, i have use following code.
rmt_config_t rmt_rx =
{
.channel = 5,
.gpio_num = 2,
.clk_div = 20,
.mem_block_num = 1,
.rmt_mode = RMT_MODE_RX,
.rx_config.filter_en = true,
.rx_config.filter_ticks_thresh = 255,
.rx_config.idle_threshold = 65535
};
rmt_config(&rmt_rx);
int i=0;
memset(RMT_CHANNEL_MEM(rmt_rx.channel),0,32);
while (1)
{
i++;
rmt_rx_start(rmt_rx.channel, 1);
vTaskDelay(50 / portTICK_PERIOD_MS);
rmt_item32_t* item = (rmt_item32_t*) (RMT_CHANNEL_MEM(rmt_rx.channel));
if((item)->duration0 == 0 || (item)->duration1 == 0)
{
memset(RMT_CHANNEL_MEM(rmt_rx.channel),0,32);
}
else
{
printStatus(5,(item)->duration0,(item)->duration1);
}
}
Also , i have set clock to RMT_BASECLK_REF in driver to set 1mhz frequency.
1. frequency 80 mhz [ APB Clock ]
- with limited pulses we are getting the data on ring buffer.
- with continuous pulses we are not getting the data on ring buffer.
- But, if we by pass the buffer we are able to achive the results.
2. frequency 1 mhz
- with limited / continuous pulses we are not getting the data on ring buffer.
- But, if we by pass the buffer we are able to achive the results.
So , is it expected behavior ?
For bypass the buffer, i have use following code.
rmt_config_t rmt_rx =
{
.channel = 5,
.gpio_num = 2,
.clk_div = 20,
.mem_block_num = 1,
.rmt_mode = RMT_MODE_RX,
.rx_config.filter_en = true,
.rx_config.filter_ticks_thresh = 255,
.rx_config.idle_threshold = 65535
};
rmt_config(&rmt_rx);
int i=0;
memset(RMT_CHANNEL_MEM(rmt_rx.channel),0,32);
while (1)
{
i++;
rmt_rx_start(rmt_rx.channel, 1);
vTaskDelay(50 / portTICK_PERIOD_MS);
rmt_item32_t* item = (rmt_item32_t*) (RMT_CHANNEL_MEM(rmt_rx.channel));
if((item)->duration0 == 0 || (item)->duration1 == 0)
{
memset(RMT_CHANNEL_MEM(rmt_rx.channel),0,32);
}
else
{
printStatus(5,(item)->duration0,(item)->duration1);
}
}
Also , i have set clock to RMT_BASECLK_REF in driver to set 1mhz frequency.
Who is online
Users browsing this forum: No registered users and 100 guests