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 <hal/rmt_ll.h>
24#include "OutputPixel.hpp"
25#include "OutputSerial.hpp"
26
27#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
28 #include <driver/rmt_tx.h>
29 #include "driver/rmt_common.h"
30 #include "driver/rmt_encoder.h"
31 #define rmt_item32_t rmt_symbol_word_t
32 typedef enum
33 {
34 RMT_IDLE_LEVEL_LOW,
35 RMT_IDLE_LEVEL_HIGH,
36 RMT_IDLE_LEVEL_MAX,
37 } rmt_idle_level_t;
38#else
39 #include <driver/rmt.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 };
54
55 struct isrTxFlags_t
56 {
57 uint32_t End = 0;
58 uint32_t Err = 0;
59 uint32_t Thres = 0;
60 };
61
62private:
63#ifdef CONFIG_IDF_TARGET_ESP32S3
64#define MAX_NUM_RMT_CHANNELS 4
65#else
66#define MAX_NUM_RMT_CHANNELS 8
67#endif // def CONFIG_IDF_TARGET_ESP32S3
68
69#define RMT_INT_BIT uint32_t(1 << uint32_t (OutputRmtConfig.RmtChannelId))
70#define InterrupsAreEnabled (0 != (RMT.int_ena.val & RMT_INT_BIT))
71
72#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
73 #define _NUM_RMT_SLOTS 48
74#else
75 #define _NUM_RMT_SLOTS (sizeof(RMTMEM.chan[0].data32) / sizeof(RMTMEM.chan[0].data32[0]))
76#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
77
78
79 const uint32_t NUM_RMT_SLOTS = _NUM_RMT_SLOTS;
80 OutputRmtConfig_t OutputRmtConfig;
81 bool OutputIsPaused = false;
82 uint32_t NumRmtSlotOverruns = 0;
83 const uint32_t MaxNumRmtSlotsPerInterrupt = (_NUM_RMT_SLOTS/2);
84
85 #define NumSendBufferSlots 64
86 rmt_item32_t SendBuffer[NumSendBufferSlots];
87 uint32_t RmtBufferWriteIndex = 0;
88 uint32_t SendBufferWriteIndex = 0;
89 uint32_t SendBufferReadIndex = 0;
90 uint32_t NumUsedEntriesInSendBuffer = 0;
91
92 uint32_t TxIntensityDataStartingMask = 0x80;
93
94 inline void IRAM_ATTR ISR_TransferIntensityDataToRMT (uint32_t NumEntriesToTransfer);
95 inline void IRAM_ATTR ISR_CreateIntensityData ();
96 inline void IRAM_ATTR ISR_WriteToBuffer(uint32_t value);
97 inline bool IRAM_ATTR ISR_MoreDataToSend();
98// inline bool IRAM_ATTR ISR_GetNextIntensityToSend(uint32_t &DataToSend);
99 inline void StartNewDataFrame();
100 inline void ISR_ResetRmtBlockPointers();
101
102#ifndef HasBeenInitialized
103 bool HasBeenInitialized = false;
104#endif // ndef HasBeenInitialized
105
106 TaskHandle_t SendIntensityDataTaskHandle = NULL;
107
108public:
109 c_OutputRmt ();
110 virtual ~c_OutputRmt ();
111
112 void Begin (OutputRmtConfig_t config, c_OutputCommon * pParent);
113 bool StartNewFrame ();
114 bool StartNextFrame () { return ((nullptr != pParent) & (!OutputIsPaused)) ? pParent->RmtPoll() : false; }
115 void GetStatus (ArduinoJson::JsonObject& jsonStatus);
116 void PauseOutput (bool State);
117 void GetDriverName (String &value) { value = CN_RMT; }
118 void SetBitDuration (double BitLenNs, rmt_item32_t & OutputBit, uint32_t & OutputNumBits);
119
120#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
121#define RMT_TX_BITS RMT_LL_EVENT_TX_THRES(OutputRmtConfig.RmtChannelId) | \
122 RMT_LL_EVENT_TX_DONE(OutputRmtConfig.RmtChannelId) | \
123 RMT_LL_EVENT_TX_ERROR(OutputRmtConfig.RmtChannelId)
124#endif // ndef rmt_ll_clear_tx_thres_interrupt
125
126__attribute__((always_inline))
127inline void IRAM_ATTR DisableRmtInterrupts()
128{
129#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
130 rmt_ll_enable_interrupt(&RMT, RMT_TX_BITS, false);
131#else
132 rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
133 rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
134 rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false);
135#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
136
137 ClearRmtInterrupts();
138}
139
140__attribute__((always_inline))
141inline void IRAM_ATTR EnableRmtInterrupts()
142{
143#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
144 rmt_ll_enable_interrupt(&RMT, RMT_TX_BITS, true);
145#else
146 rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
147 rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
148 rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true);
149#endif // ndef rmt_ll_clear_tx_thres_interrupt
150}
151
152__attribute__((always_inline))
153inline void IRAM_ATTR ClearRmtInterrupts()
154{
155#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
156 rmt_ll_clear_interrupt_status(&RMT, RMT_TX_BITS);
157#else
158 rmt_ll_clear_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
159 rmt_ll_clear_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
160 rmt_ll_clear_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId);
161#endif // ndef rmt_ll_clear_tx_thres_interrupt
162}
163
164 bool DriverIsSendingIntensityData() {return 0 != InterrupsAreEnabled;}
165
166#define RMT_ClockRate 80000000.0
167#define RMT_Clock_Divisor 2.0
168#define RMT_TickLengthNS float ( (1/ (RMT_ClockRate/RMT_Clock_Divisor)) * float(NanoSecondsInASecond))
169
170 bool ThereIsDataToSend = false;
171
172 void IRAM_ATTR ISR_Handler (isrTxFlags_t isrFlags);
173 c_OutputCommon * pParent = nullptr;
174
175// #define USE_RMT_DEBUG_COUNTERS
176#ifdef USE_RMT_DEBUG_COUNTERS
177// #define IncludeBufferData
178 // debug counters
179 uint32_t DataCallbackCounter = 0;
180 uint32_t DataTaskcounter = 0;
181 uint32_t ISRcounter = 0;
182 uint32_t FrameStartCounter = 0;
183 uint32_t SendBlockIsrCounter = 0;
184 uint32_t RanOutOfData = 0;
185 uint32_t UnknownISRcounter = 0;
186 uint32_t IntTxEndIsrCounter = 0;
187 uint32_t IntTxThrIsrCounter = 0;
188 uint32_t RxIsr = 0;
189 uint32_t ErrorIsr = 0;
190 uint32_t IntensityValuesSent = 0;
191 uint32_t IntensityBitsSent = 0;
192 uint32_t IntensityValuesSentLastFrame = 0;
193 uint32_t IntensityBitsSentLastFrame = 0;
194 uint32_t IncompleteFrame = 0;
195 uint32_t RmtEntriesTransfered = 0;
196 uint32_t RmtXmtFills = 0;
197 uint32_t RmtWhiteDetected = 0;
198 uint32_t FailedToSendAllData = 0;
199
200#define RMT_DEBUG_COUNTER(p) p
201
202#else
203
204#define RMT_DEBUG_COUNTER(p)
205
206#endif // def USE_RMT_DEBUG_COUNTERS
207
208};
209#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