ESPixelStick Firmware
Firmware for the ESPixelStick
Loading...
Searching...
No Matches
OutputRmt.hpp
Go to the documentation of this file.
1#pragma once
2/*
3* OutputRmt.hpp - RMT driver code for ESPixelStick RMT Channel
4*
5* Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver
6* Copyright (c) 2015, 2026 Shelby Merrick
7* http://www.forkineye.com
8*
9* This program is provided free for you to use in any way that you wish,
10* subject to the laws and regulations where you are using it. Due diligence
11* is strongly suggested before using this code. Please give credit where due.
12*
13* The Author makes no warranty of any kind, express or implied, with regard
14* to this program or the documentation contained in this document. The
15* Author shall not be liable in any event for incidental or consequential
16* damages in connection with, or arising out of, the furnishing, performance
17* or use of these programs.
18*
19*/
20
21#include "ESPixelStick.h"
22#ifdef ARDUINO_ARCH_ESP32
23#include "OutputPixel.hpp"
24#include "OutputSerial.hpp"
25
26#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
27 #include <driver/rmt_tx.h>
28 #include "driver/rmt_common.h"
29 #include "driver/rmt_encoder.h"
30 #define rmt_item32_t rmt_symbol_word_t
31 typedef enum
32 {
33 RMT_IDLE_LEVEL_LOW,
34 RMT_IDLE_LEVEL_HIGH,
35 RMT_IDLE_LEVEL_MAX,
36 } rmt_idle_level_t;
37#else
38 #include <driver/rmt.h>
39 #include <hal/rmt_ll.h>
40#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
41
42class c_OutputRmt
43{
44public:
45 struct OutputRmtConfig_t
46 {
47 uint32_t RmtChannelId = uint32_t(-1);
48 gpio_num_t DataPin = gpio_num_t(-1);
49 rmt_idle_level_t idle_level = rmt_idle_level_t::RMT_IDLE_LEVEL_LOW;
50 void *arg = nullptr;
51 bool (*ISR_GetNextIntensityBit) (void*arg, rmt_item32_t&data) = nullptr;
52 void (*StartNewDataFrame) (void*arg) = nullptr;
53 void *BufferStart = nullptr;
54 size_t NumBytesInFrame = 0;
55 };
56
57 struct isrTxFlags_t
58 {
59 uint32_t End = 0;
60 uint32_t Err = 0;
61 uint32_t Thres = 0;
62 };
63
64private:
65#ifdef CONFIG_IDF_TARGET_ESP32S3
66# define MAX_NUM_RMT_CHANNELS 4
67#else
68# define MAX_NUM_RMT_CHANNELS 8
69#endif // def CONFIG_IDF_TARGET_ESP32S3
70
71#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
72 #define _NUM_RMT_SLOTS 64
73 rmt_channel_handle_t rmt_channel_handle;
74 rmt_encoder_handle_t rmt_encoder_handle;
75 rmt_transmit_config_t tx_config =
76 {
77 .loop_count = 0, // no transfer loop
78 .flags =
79 {
80 .eot_level = OutputRmtConfig.idle_level,
81 .queue_nonblocking = true
82 }
83 };
84#else
85 #define RMT_INT_BIT uint32_t(1 << uint32_t (OutputRmtConfig.RmtChannelId))
86 #define InterrupsAreEnabled (0 != (RMT.int_ena.val & RMT_INT_BIT))
87
88 #define _NUM_RMT_SLOTS (sizeof(RMTMEM.chan[0].data32) / sizeof(RMTMEM.chan[0].data32[0]))
89
90#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
91
92
93 const uint32_t NUM_RMT_SLOTS = _NUM_RMT_SLOTS;
94 OutputRmtConfig_t OutputRmtConfig;
95 bool OutputIsPaused = false;
96 uint32_t NumRmtSlotOverruns = 0;
97 const uint32_t MaxNumRmtSlotsPerInterrupt = (_NUM_RMT_SLOTS/2);
98
99 #define NumSendBufferSlots _NUM_RMT_SLOTS
100 rmt_item32_t SendBuffer[NumSendBufferSlots];
101 uint32_t RmtBufferWriteIndex = 0;
102 uint32_t SendBufferWriteIndex = 0;
103 uint32_t SendBufferReadIndex = 0;
104 uint32_t NumUsedEntriesInSendBuffer = 0;
105
106 void ISR_TransferIntensityDataToRMT (uint32_t NumEntriesToTransfer);
107 size_t ISR_TransferIntensityDataToRMT (rmt_item32_t *symbols, uint32_t MaxNumEntriesToTransfer);
108 void ISR_CreateIntensityData ();
109 void ISR_WriteToBuffer(rmt_item32_t value);
110 bool ISR_MoreDataToSend();
111 void StartNewDataFrame();
112 void ISR_ResetRmtBlockPointers();
113
114#ifndef HasBeenInitialized
115 bool HasBeenInitialized = false;
116#endif // ndef HasBeenInitialized
117
118 TaskHandle_t SendIntensityDataTaskHandle = NULL;
119
120public:
121 c_OutputRmt ();
122 virtual ~c_OutputRmt ();
123
124 void Begin (OutputRmtConfig_t config, c_OutputCommon * pParent);
125 bool StartNewFrame ();
126 bool StartNextFrame () { return ((nullptr != pParent) & (!OutputIsPaused)) ? pParent->RmtPoll() : false; }
127 void GetStatus (ArduinoJson::JsonObject& jsonStatus);
128 void PauseOutput (bool State);
129 void GetDriverName (String &value) { value = CN_RMT; }
130 void SetBitDuration (double BitLenNs, rmt_item32_t & OutputBit, uint32_t & OutputNumBits);
131
132__attribute__((always_inline))
133inline void IRAM_ATTR DisableRmtInterrupts()
134{
135 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
136 rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
137 rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
138 rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
139 ClearRmtInterrupts();
140 #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
141}
142
143__attribute__((always_inline))
144inline void IRAM_ATTR EnableRmtInterrupts()
145{
146 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
147 rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
148 rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
149 rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
150 #endif // ndef rmt_ll_clear_tx_thres_interrupt
151}
152
153__attribute__((always_inline))
154inline void IRAM_ATTR ClearRmtInterrupts()
155{
156 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
157 rmt_ll_clear_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
158 rmt_ll_clear_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
159 rmt_ll_clear_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
160 #endif // ndef rmt_ll_clear_tx_thres_interrupt
161}
162
163#define RMT_ClockRate 80000000.0
164#define RMT_Clock_Divisor 2.0
165#define RMT_TICK_RESOLUTION_HZ (RMT_ClockRate / RMT_Clock_Divisor)
166#define RMT_TickLengthNS uint32_t((1.0 / RMT_TICK_RESOLUTION_HZ) * float(NanoSecondsInASecond))
167
168 void ISR_Handler (isrTxFlags_t isrFlags);
169 size_t ISR_Handler (const void *data, size_t data_size,
170 size_t symbols_written, size_t symbols_free,
171 rmt_item32_t *symbols, bool *done);
172 c_OutputCommon * pParent = nullptr;
173
174#define USE_RMT_DEBUG_COUNTERS
175#ifdef USE_RMT_DEBUG_COUNTERS
176// #define IncludeBufferData
177 // debug counters
178 uint32_t DataCallbackCounter = 0;
179 uint32_t DataTaskcounter = 0;
180 uint32_t ISRcounter = 0;
181 uint32_t FrameStartCounter = 0;
182 uint32_t SendBlockIsrCounter = 0;
183 uint32_t RanOutOfData = 0;
184 uint32_t UnknownISRcounter = 0;
185 uint32_t IntTxEndIsrCounter = 0;
186 uint32_t IntTxThrIsrCounter = 0;
187 uint32_t RxIsr = 0;
188 uint32_t ErrorIsr = 0;
189 uint32_t IntensityValuesSent = 0;
190 uint32_t IntensityBitsSent = 0;
191 uint32_t IntensityValuesSentLastFrame = 0;
192 uint32_t IntensityBitsSentLastFrame = 0;
193 uint32_t IncompleteFrame = 0;
194 uint32_t RmtEntriesTransfered = 0;
195 uint32_t RmtXmtFills = 0;
196 uint32_t ISRpaused = 0;
197 uint32_t RmtWhiteDetected = 0;
198 uint32_t FailedToSendAllData = 0;
199 uint32_t WriteToBuffer = 0;
200 uint32_t WriteToRmt = 0;
201
202#define RMT_DEBUG_COUNTER(p) p
203
204#else
205
206#define RMT_DEBUG_COUNTER(p)
207
208#endif // def USE_RMT_DEBUG_COUNTERS
209
210};
211#endif // def #ifdef ARDUINO_ARCH_ESP32
const CN_PROGMEM char CN_RMT[]
Definition ConstNames.cpp:193
Definition OutputCommon.hpp:32
struct FSEQParsedRangeEntry __attribute__
config_t config
Definition main.cpp:98
void GetDriverName(String &Name)
Definition main.cpp:121