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
66#define MAX_NUM_RMT_CHANNELS SOC_RMT_TX_CANDIDATES_PER_GROUP
67#define NUM_RMT_SLOTS SOC_RMT_MEM_WORDS_PER_CHANNEL
68
69#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
70 rmt_channel_handle_t rmt_channel_handle;
71 rmt_encoder_handle_t rmt_encoder_handle;
72 rmt_transmit_config_t tx_config =
73 {
74 .loop_count = 0, // no transfer loop
75 .flags =
76 {
77 .eot_level = OutputRmtConfig.idle_level,
78 .queue_nonblocking = true
79 }
80 };
81#else
82 #define RMT_INT_BIT uint32_t(1 << uint32_t (OutputRmtConfig.RmtChannelId))
83 #define InterrupsAreEnabled (0 != (RMT.int_ena.val & RMT_INT_BIT))
84 rmt_item32_t * RmtChanData = nullptr;
85
86#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
87
88
89 OutputRmtConfig_t OutputRmtConfig;
90 bool OutputIsPaused = false;
91 uint32_t NumRmtSlotOverruns = 0;
92 const uint32_t MaxNumRmtSlotsPerInterrupt = (NUM_RMT_SLOTS/2);
93
94 #define NumSendBufferSlots 64
95 rmt_item32_t SendBuffer[NumSendBufferSlots];
96 uint32_t RmtBufferWriteIndex = 0;
97 uint32_t SendBufferWriteIndex = 0;
98 uint32_t SendBufferReadIndex = 0;
99 uint32_t NumUsedEntriesInSendBuffer = 0;
100
101 void ISR_TransferIntensityDataToRMT (uint32_t NumEntriesToTransfer);
102 size_t ISR_TransferIntensityDataToRMT (rmt_item32_t *symbols, uint32_t MaxNumEntriesToTransfer);
103 void ISR_CreateIntensityData ();
104 bool ISR_MoreDataToSend();
105 void StartNewDataFrame();
106 void ISR_ResetRmtBlockPointers();
107
108#ifndef HasBeenInitialized
109 bool HasBeenInitialized = false;
110#endif // ndef HasBeenInitialized
111
112 TaskHandle_t SendIntensityDataTaskHandle = NULL;
113
114public:
115 c_OutputRmt ();
116 virtual ~c_OutputRmt ();
117
118 void Begin (OutputRmtConfig_t config, c_OutputCommon * pParent);
119 bool StartNewFrame ();
120 bool StartNextFrame () { return ((nullptr != pParent) & (!OutputIsPaused)) ? pParent->RmtPoll() : false; }
121 void GetStatus (ArduinoJson::JsonObject& jsonStatus);
122 void PauseOutput (bool State);
123 void GetDriverName (String &value) { value = CN_RMT; }
124 void SetBitDuration (double BitLenNs, rmt_item32_t & OutputBit, uint32_t & OutputNumBits);
125
126#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
127__attribute__((always_inline))
128inline void DisableRmtInterrupts()
129{
130 rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
131 rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
132 rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
133} // DisableRmtInterrupts
134
135__attribute__((always_inline))
136inline void EnableRmtInterrupts()
137{
138 rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
139 rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
140 rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
141} // EnableRmtInterrupts
142
143__attribute__((always_inline))
144inline void ClearRmtInterrupts()
145{
146 rmt_ll_clear_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
147 rmt_ll_clear_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
148 rmt_ll_clear_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
149} // ClearRmtInterrupts
150#endif // ndef rmt_ll_clear_tx_thres_interrupt
151
152#define RMT_ClockRate 80000000.0
153#define RMT_Clock_Divisor 2.0
154#define RMT_TICK_RESOLUTION_HZ (RMT_ClockRate / RMT_Clock_Divisor)
155#define RMT_TickLengthNS uint32_t((1.0 / RMT_TICK_RESOLUTION_HZ) * float(NanoSecondsInASecond))
156
157 void ISR_Handler (isrTxFlags_t isrFlags);
158 size_t ISR_Handler (const void *data, size_t data_size,
159 size_t symbols_written, size_t symbols_free,
160 rmt_item32_t *symbols, bool *done);
161 c_OutputCommon * pParent = nullptr;
162
163// #define USE_RMT_DEBUG_COUNTERS
164#ifdef USE_RMT_DEBUG_COUNTERS
165// #define IncludeBufferData
166 // debug counters
167 struct RmtDebugCounters_t
168 {
169 uint32_t DataCallbackCounter = 0;
170 uint32_t DataTaskcounter = 0;
171 uint32_t ISRcounter = 0;
172 uint32_t FrameStartCounter = 0;
173 uint32_t SendBlockIsrCounter = 0;
174 uint32_t RanOutOfData = 0;
175 uint32_t UnknownISRcounter = 0;
176 uint32_t IntTxEndIsrCounter = 0;
177 uint32_t IntTxThrIsrCounter = 0;
178 uint32_t RxIsr = 0;
179 uint32_t ErrorIsr = 0;
180 uint32_t IntensityValuesSent = 0;
181 uint32_t IntensityBitsSent = 0;
182 uint32_t IntensityValuesSentLastFrame = 0;
183 uint32_t IntensityBitsSentLastFrame = 0;
184 uint32_t IncompleteFrame = 0;
185 uint32_t RmtEntriesTransfered = 0;
186 uint32_t RmtXmtFills = 0;
187 uint32_t ISRpaused = 0;
188 uint32_t RmtWhiteDetected = 0;
189 uint32_t FailedToSendAllData = 0;
190 uint32_t WriteToBuffer = 0;
191 uint32_t WriteToRmt = 0;
192 } ;
193 RmtDebugCounters_t RmtDebugCounters;
194
195#define RMT_DEBUG_INC_COUNTER(p) (++RmtDebugCounters.p)
196#define RMT_DEBUG_COUNTER(p) (RmtDebugCounters.p)
197
198#else
199
200#define RMT_DEBUG_INC_COUNTER(p)
201#define RMT_DEBUG_COUNTER(p)
202
203#endif // def USE_RMT_DEBUG_COUNTERS
204
205private:
206__attribute__((always_inline))
207inline void WriteToBuffer(rmt_item32_t value)
208{
209 RMT_DEBUG_INC_COUNTER(WriteToBuffer);
210
211 SendBuffer[SendBufferWriteIndex] = value;
212 if(++SendBufferWriteIndex >= NumSendBufferSlots) {SendBufferWriteIndex = 0;}
213 ++NumUsedEntriesInSendBuffer;
214} // WriteToBuffer
215
216};
217#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