Commit 4e96bffe authored by david-cermak's avatar david-cermak Committed by Me No Dev

Initial version of rmt driver (#1525)

* rmt driver initial version

* supporting conti mode plus interrupts

* using conitnous mode for sending more data

* working continous mode

* rmt driver cleanup after conti mode

* initial version of rmt driver

* adding a simple example

* adding channel and block locks

* modified of rmt interface for simpler/easier usage

* adding header sentinels, split interface to common and additional settings

* Fixes per code review + support for rx callback mode

* renamed internal structures and enums, fixed formatting

* cmake support for rmt

* refactored tx-conti interrupts to function to make it more readable

* added Tx and Rx examples

* added license headers

* minor updates per review

* used struct access, renamed defines, corrected diagram
parent ea61563c
......@@ -16,6 +16,7 @@ set(CORE_SRCS
cores/esp32/esp32-hal-timer.c
cores/esp32/esp32-hal-touch.c
cores/esp32/esp32-hal-uart.c
cores/esp32/esp32-hal-rmt.c
cores/esp32/Esp.cpp
cores/esp32/FunctionalInterrupt.cpp
cores/esp32/HardwareSerial.cpp
......
This diff is collapsed.
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MAIN_ESP32_HAL_RMT_H_
#define MAIN_ESP32_HAL_RMT_H_
#ifdef __cplusplus
extern "C" {
#endif
// notification flags
#define RMT_FLAG_TX_DONE (1)
#define RMT_FLAG_RX_DONE (2)
#define RMT_FLAG_ERROR (4)
#define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR)
struct rmt_obj_s;
typedef enum {
RMT_MEM_64 = 1,
RMT_MEM_128 = 2,
RMT_MEM_192 = 3,
RMT_MEM_256 = 4,
RMT_MEM_320 = 5,
RMT_MEM_384 = 6,
RMT_MEM_448 = 7,
RMT_MEM_512 = 8,
} rmt_reserve_memsize_t;
typedef struct rmt_obj_s rmt_obj_t;
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len);
typedef struct {
union {
struct {
uint32_t duration0 :15;
uint32_t level0 :1;
uint32_t duration1 :15;
uint32_t level1 :1;
};
uint32_t val;
};
} rmt_data_t;
/**
* Initialize the object
*
*/
rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize);
/**
* Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds
* return the real actual tick value in ns
*/
float rmtSetTick(rmt_obj_t* rmt, float tick);
/**
* Sending data in one-go mode or continual mode
* (more data being send while updating buffers in interrupts)
*
*/
bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
/**
* Initiates async receive, event flag indicates data received
*
*/
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout);
/**
* Initiates async receive with automatic buffering
* and callback with data from ISR
*
*/
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb);
/* Additional interface */
/**
* Start reception
*
*/
bool rmtBeginReceive(rmt_obj_t* rmt);
/**
* Checks if reception completes
*
*/
bool rmtReceiveCompleted(rmt_obj_t* rmt);
/**
* Reads the data for particular channel
*
*/
bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size);
/**
* Setting threshold for Rx completed
*/
bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value);
/**
* Setting carrier
*/
bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high);
/**
* Setting input filter
*/
bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level);
// TODO:
// * uninstall interrupt when all channels are deinit
// * send only-conti mode with circular-buffer
// * put sanity checks to some macro or inlines
// * doxy comments
// * error reporting
#ifdef __cplusplus
}
#endif
#endif /* MAIN_ESP32_HAL_RMT_H_ */
......@@ -57,6 +57,7 @@ void yield(void);
#include "esp32-hal-spi.h"
#include "esp32-hal-i2c.h"
#include "esp32-hal-ledc.h"
#include "esp32-hal-rmt.h"
#include "esp32-hal-sigmadelta.h"
#include "esp32-hal-timer.h"
#include "esp32-hal-bt.h"
......
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "Arduino.h"
#include "esp32-hal.h"
rmt_data_t my_data[256];
rmt_data_t data[256];
rmt_obj_t* rmt_send = NULL;
rmt_obj_t* rmt_recv = NULL;
static EventGroupHandle_t events;
void setup()
{
Serial.begin(115200);
if ((rmt_send = rmtInit(18, true, RMT_MEM_64)) == NULL)
{
Serial.println("init sender failed\n");
}
if ((rmt_recv = rmtInit(21, false, RMT_MEM_192)) == NULL)
{
Serial.println("init receiver failed\n");
}
float realTick = rmtSetTick(rmt_send, 100);
printf("real tick set to: %fns\n", realTick);
}
void loop()
{
// Init data
int i;
for (i=0; i<255; i++) {
data[i].val = 0x80010001 + ((i%13)<<16) + 13-(i%13);
}
data[255].val = 0;
// Start receiving
rmtReadAsync(rmt_recv, my_data, 100, events, false, 0);
// Send in continous mode
rmtWrite(rmt_send, data, 100);
// Wait for data
xEventGroupWaitBits(events, RMT_FLAG_RX_DONE, 1, 1, portMAX_DELAY);
// Printout the received data plus the original values
for (i=0; i<60; i++)
{
Serial.printf("%08x=%08x ", my_data[i], data[i] );
if (!((i+1)%4)) Serial.println("\n");
}
Serial.println("\n");
delay(2000);
}
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "Arduino.h"
#include "esp32-hal.h"
//
// Note: This example uses a FrSKY device communication
// using XJT D12 protocol
//
// ; 0 bit = 6us low/10us high
// ; 1 bit = 14us low/10us high
// ;
// ; --------+ +----------+ +----------+
// ; | | | | |
// ; | 0 | | 1 | |
// ; | | | | |
// ; | | | | |
// ; +-------+ +-----------------+ +---------
// ;
// ; | 6us 10us | 14us 10us |
// ; |-------|----------|-----------------|----------|--------
// ; | 16us | 24us |
// Typedef of received frame
//
// ; 0x00 - Sync, 0x7E (sync header ID)
// ; 0x01 - Rx ID, 0x?? (receiver ID number, 0x00-0x??)
// ; 0x02 - Flags 1, 0x?? (used for failsafe and binding)
// ; 0x03 - Flags 2, 0x00 (reserved)
// ; 0x04-0x06, Channels 1/9 and 2/10
// ; 0x07-0x09, Channels 3/11 and 4/12
// ; 0x0A-0x0C, Channels 5/13 and 6/14
// ; 0x0D-0x0F, Channels 7/15 and 8/16
// ; 0x10 - 0x00, always zero
// ; 0x11 - CRC-16 High
// ; 0x12 - CRC-16 Low
// ; 0x13 - Tail, 0x7E (tail ID)
typedef union {
struct {
uint8_t head;//0x7E
uint8_t rxid;//Receiver Number
uint8_t flags;//Range:0x20, Bind:0x01
uint8_t reserved0;//0x00
union {
struct {
uint8_t ch0_l;
uint8_t ch0_h:4;
uint8_t ch1_l:4;
uint8_t ch1_h;
};
uint8_t bytes[3];
} channels[4];
uint8_t reserved1;//0x00
uint8_t crc_h;
uint8_t crc_l;
uint8_t tail;//0x7E
};
uint8_t buffer[20];
} xjt_packet_t;
#define XJT_VALID(i) (i->level0 && !i->level1 && i->duration0 >= 8 && i->duration0 <= 11)
rmt_obj_t* rmt_recv = NULL;
static uint32_t *s_channels;
static uint32_t channels[16];
static uint8_t xjt_flags = 0x0;
static uint8_t xjt_rxid = 0x0;
static bool xjtReceiveBit(size_t index, bool bit){
static xjt_packet_t xjt;
static uint8_t xjt_bit_index = 8;
static uint8_t xht_byte_index = 0;
static uint8_t xht_ones = 0;
if(!index){
xjt_bit_index = 8;
xht_byte_index = 0;
xht_ones = 0;
}
if(xht_byte_index > 19){
//fail!
return false;
}
if(bit){
xht_ones++;
if(xht_ones > 5 && xht_byte_index && xht_byte_index < 19){
//fail!
return false;
}
//add bit
xjt.buffer[xht_byte_index] |= (1 << --xjt_bit_index);
} else if(xht_ones == 5 && xht_byte_index && xht_byte_index < 19){
xht_ones = 0;
//skip bit
return true;
} else {
xht_ones = 0;
//add bit
xjt.buffer[xht_byte_index] &= ~(1 << --xjt_bit_index);
}
if ((!xjt_bit_index) || (xjt_bit_index==1 && xht_byte_index==19) ) {
xjt_bit_index = 8;
if(!xht_byte_index && xjt.buffer[0] != 0x7E){
//fail!
return false;
}
xht_byte_index++;
if(xht_byte_index == 20){
//done
if(xjt.buffer[19] != 0x7E){
//fail!
return false;
}
//check crc?
xjt_flags = xjt.flags;
xjt_rxid = xjt.rxid;
for(int i=0; i<4; i++){
uint16_t ch0 = xjt.channels[i].ch0_l | ((uint16_t)(xjt.channels[i].ch0_h & 0x7) << 8);
ch0 = ((ch0 * 2) + 2452) / 3;
uint16_t ch1 = xjt.channels[i].ch1_l | ((uint16_t)(xjt.channels[i].ch1_h & 0x7F) << 4);
ch1 = ((ch1 * 2) + 2452) / 3;
uint8_t c0n = i*2;
if(xjt.channels[i].ch0_h & 0x8){
c0n += 8;
}
uint8_t c1n = i*2+1;
if(xjt.channels[i].ch1_h & 0x80){
c1n += 8;
}
s_channels[c0n] = ch0;
s_channels[c1n] = ch1;
}
}
}
return true;
}
void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){
size_t chan = 0;
bool valid = true;
rmt_data_t* it = NULL;
if (!channels) {
log_e("Please provide data block for storing channel info");
return;
}
s_channels = channels;
it = &items[0];
for(size_t i = 0; i<len; i++){
if(!valid){
break;
}
it = &items[i];
if(XJT_VALID(it)){
if(it->duration1 >= 5 && it->duration1 <= 8){
valid = xjtReceiveBit(i, false);
} else if(it->duration1 >= 13 && it->duration1 <= 16){
valid = xjtReceiveBit(i, true);
} else {
valid = false;
}
} else if(!it->duration1 && !it->level1 && it->duration0 >= 5 && it->duration0 <= 8) {
valid = xjtReceiveBit(i, false);
}
}
}
extern "C" void receive_data(uint32_t *data, size_t len)
{
parseRmt((rmt_data_t*) data, len, channels);
}
void setup()
{
Serial.begin(115200);
// Initialize the channel to capture up to 192 items
if ((rmt_recv = rmtInit(21, false, RMT_MEM_192)) == NULL)
{
Serial.println("init receiver failed\n");
}
// Setup 1us tick
float realTick = rmtSetTick(rmt_recv, 1000);
Serial.printf("real tick set to: %fns\n", realTick);
// Ask to start reading
rmtRead(rmt_recv, receive_data);
}
void loop()
{
// printout some of the channels
Serial.printf("%04x %04x %04x %04x\n", channels[0], channels[1], channels[2], channels[3]);
delay(500);
}
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "Arduino.h"
#include "esp32-hal.h"
#define NR_OF_LEDS 8*4
#define NR_OF_ALL_BITS 24*NR_OF_LEDS
//
// Note: This example uses Neopixel LED board, 32 LEDs chained one
// after another, each RGB LED has its 24 bit value
// for color configuration (8b for each color)
//
// Bits encoded as pulses as follows:
//
// "0":
// +-------+ +--
// | | |
// | | |
// | | |
// ---| |--------------|
// + + +
// | 0.4us | 0.85 0us |
//
// "1":
// +-------------+ +--
// | | |
// | | |
// | | |
// | | |
// ---+ +-------+
// | 0.8us | 0.4us |
rmt_data_t led_data[NR_OF_ALL_BITS];
rmt_obj_t* rmt_send = NULL;
void setup()
{
Serial.begin(115200);
if ((rmt_send = rmtInit(18, true, RMT_MEM_64)) == NULL)
{
Serial.println("init sender failed\n");
}
float realTick = rmtSetTick(rmt_send, 100);
Serial.printf("real tick set to: %fns\n", realTick);
}
int color[] = { 0x55, 0x11, 0x77 }; // RGB value
int led_index = 0;
void loop()
{
// Init data with only one led ON
int led, col, bit;
int i=0;
for (led=0; led<NR_OF_LEDS; led++) {
for (col=0; col<3; col++ ) {
for (bit=0; bit<8; bit++){
if ( (color[col] & (1<<(8-bit))) && (led == led_index) ) {
led_data[i].level0 = 1;
led_data[i].duration0 = 8;
led_data[i].level1 = 0;
led_data[i].duration1 = 4;
} else {
led_data[i].level0 = 1;
led_data[i].duration0 = 4;
led_data[i].level1 = 0;
led_data[i].duration1 = 8;
}
i++;
}
}
}
// make the led travel in the pannel
if ((++led_index)>=NR_OF_LEDS) {
led_index = 0;
}
// Send the data
rmtWrite(rmt_send, led_data, NR_OF_ALL_BITS);
delay(100);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment