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, 2024 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 <driver/rmt.h>
24#include "OutputPixel.hpp"
25#include "OutputSerial.hpp"
26
27class c_OutputRmt
28{
29public:
30 enum RmtDataBitIdType_t
31 {
32 RMT_DATA_BIT_ZERO_ID = 0, // 0 UART 00
33 RMT_DATA_BIT_ONE_ID, // 1 UART 01
34 RMT_DATA_BIT_TWO_ID, // 2 UART 10
35 RMT_DATA_BIT_THREE_ID, // 3 UART 11
36 RMT_INTERFRAME_GAP_ID, // 4 UART Break / MAB
37 RMT_STARTBIT_ID, // 5
38 RMT_STOPBIT_ID, // 6 UART Stop/start bit
39 RMT_END_OF_FRAME, // 7
40 RMT_LIST_END, // 8 This must be last
41 RMT_INVALID_VALUE,
42 RMT_NUM_BIT_TYPES = RMT_LIST_END,
43 RMT_STOP_START_BIT_ID = RMT_STOPBIT_ID,
44 };
45
46 struct ConvertIntensityToRmtDataStreamEntry_t
47 {
48 rmt_item32_t Translation;
49 RmtDataBitIdType_t Id;
50 };
51 typedef ConvertIntensityToRmtDataStreamEntry_t CitrdsArray_t;
52
53 struct OutputRmtConfig_t
54 {
55 rmt_channel_t RmtChannelId = rmt_channel_t(-1);
56 gpio_num_t DataPin = gpio_num_t(-1);
57 rmt_idle_level_t idle_level = rmt_idle_level_t::RMT_IDLE_LEVEL_LOW;
58 uint32_t IntensityDataWidth = 8;
59 bool SendInterIntensityBits = false;
60 bool SendEndOfFrameBits = false;
61 uint8_t NumFrameStartBits = 1;
62 uint8_t NumFrameStopBits = 1;
63 uint8_t NumIdleBits = 6;
64 enum DataDirection_t
65 {
66 MSB2LSB = 0,
67 LSB2MSB
68 };
69 DataDirection_t DataDirection = DataDirection_t::MSB2LSB;
70 const CitrdsArray_t *CitrdsArray = nullptr;
71
72 c_OutputPixel *pPixelDataSource = nullptr;
73#if defined(SUPPORT_OutputType_DMX) || defined(SUPPORT_OutputType_Serial) || defined(SUPPORT_OutputType_Renard)
74 c_OutputSerial *pSerialDataSource = nullptr;
75#endif // defined(SUPPORT_OutputType_DMX) || defined(SUPPORT_OutputType_Serial) || defined(SUPPORT_OutputType_Renard)
76 };
77
78private:
79#define MAX_NUM_RMT_CHANNELS 8
80#define RMT_INT_TX_END (1)
81#define RMT_INT_RX_END (2)
82#define RMT_INT_ERROR (4)
83#define RMT_BITS_PER_CHAN (3)
84
85#define RMT_INT_THR_EVNT_BIT (1 << (24 + uint32_t (OutputRmtConfig.RmtChannelId)))
86
87#define RMT_INT_TX_END_BIT (RMT_INT_TX_END << (uint32_t (OutputRmtConfig.RmtChannelId)*RMT_BITS_PER_CHAN))
88#define RMT_INT_RX_END_BIT (RMT_INT_RX_END << (uint32_t (OutputRmtConfig.RmtChannelId)*RMT_BITS_PER_CHAN))
89#define RMT_INT_ERROR_BIT (RMT_INT_ERROR << (uint32_t (OutputRmtConfig.RmtChannelId)*RMT_BITS_PER_CHAN))
90#define NUM_RMT_SLOTS (sizeof(RMTMEM.chan[0].data32) / sizeof(RMTMEM.chan[0].data32[0]))
91
92 OutputRmtConfig_t OutputRmtConfig;
93
94 rmt_item32_t Intensity2Rmt[RmtDataBitIdType_t::RMT_LIST_END];
95 bool OutputIsPaused = false;
96
97 uint32_t NumRmtSlotsPerIntensityValue = 8;
98 uint32_t NumRmtSlotOverruns = 0;
99 uint32_t MaxNumRmtSlotsPerInterrupt = (NUM_RMT_SLOTS/2);
100
101 rmt_item32_t SendBuffer[NUM_RMT_SLOTS * 2];
102 uint32_t RmtBufferWriteIndex = 0;
103 uint32_t SendBufferWriteIndex = 0;
104 uint32_t SendBufferReadIndex = 0;
105 uint32_t NumUsedEntriesInSendBuffer = 0;
106
107#define MIN_FRAME_TIME_MS 25
108
109 uint32_t TxIntensityDataStartingMask = 0x80;
110 RmtDataBitIdType_t InterIntensityValueId = RMT_INVALID_VALUE;
111
112 inline void IRAM_ATTR ISR_TransferIntensityDataToRMT (uint32_t NumEntriesToTransfer);
113 inline void IRAM_ATTR ISR_CreateIntensityData ();
114 inline void IRAM_ATTR ISR_WriteToBuffer(uint32_t value);
115 inline bool IRAM_ATTR ISR_MoreDataToSend();
116 inline bool IRAM_ATTR ISR_GetNextIntensityToSend(uint32_t &DataToSend);
117 inline void IRAM_ATTR ISR_StartNewDataFrame();
118 inline void IRAM_ATTR ISR_ResetRmtBlockPointers();
119
120#ifndef HasBeenInitialized
121 bool HasBeenInitialized = false;
122#endif // ndef HasBeenInitialized
123
124 TaskHandle_t SendIntensityDataTaskHandle = NULL;
125
126public:
127 c_OutputRmt ();
128 virtual ~c_OutputRmt ();
129
130 void Begin (OutputRmtConfig_t config, c_OutputCommon * pParent);
131 bool StartNewFrame ();
132 bool StartNextFrame () { return ((nullptr != pParent) & (!OutputIsPaused)) ? pParent->RmtPoll() : false; }
133 void GetStatus (ArduinoJson::JsonObject& jsonStatus);
134 void set_pin (gpio_num_t _DataPin) { OutputRmtConfig.DataPin = _DataPin; rmt_set_gpio (OutputRmtConfig.RmtChannelId, rmt_mode_t::RMT_MODE_TX, OutputRmtConfig.DataPin, false); }
135 void PauseOutput (bool State);
136 inline uint32_t IRAM_ATTR GetRmtIntMask () { return ((RMT_INT_TX_END_BIT | RMT_INT_ERROR_BIT | RMT_INT_ERROR_BIT)); }
137 void GetDriverName (String &value) { value = CN_RMT; }
138
139#define RMT_ISR_BITS (RMT_INT_TX_END_BIT | RMT_INT_THR_EVNT_BIT)
140#define DisableRmtInterrupts RMT.int_ena.val &= ~(RMT_ISR_BITS)
141#define EnableRmtInterrupts RMT.int_ena.val |= (RMT_ISR_BITS)
142#define ClearRmtInterrupts RMT.int_clr.val = (RMT_ISR_BITS)
143#define InterrupsAreEnabled (RMT.int_ena.val & (RMT_ISR_BITS))
144
145 bool DriverIsSendingIntensityData() {return 0 != InterrupsAreEnabled;}
146
147#define RMT_ClockRate 80000000.0
148#define RMT_Clock_Divisor 2.0
149#define RMT_TickLengthNS float ( (1/ (RMT_ClockRate/RMT_Clock_Divisor)) * float(NanoSecondsInASecond))
150
151 void SetIntensity2Rmt (rmt_item32_t NewValue, RmtDataBitIdType_t ID) { Intensity2Rmt[ID] = NewValue; }
152
153 bool ThereIsDataToSend = false;
154 bool NoFrameInProgress () { return (0 == (RMT.int_ena.val & (RMT_ISR_BITS))); }
155
156 void IRAM_ATTR ISR_Handler (uint32_t isrFlags);
157 c_OutputCommon * pParent = nullptr;
158
159// #define USE_RMT_DEBUG_COUNTERS
160#ifdef USE_RMT_DEBUG_COUNTERS
161// #define IncludeBufferData
162 // debug counters
163 uint32_t DataCallbackCounter = 0;
164 uint32_t DataTaskcounter = 0;
165 uint32_t ISRcounter = 0;
166 uint32_t FrameStartCounter = 0;
167 uint32_t SendBlockIsrCounter = 0;
168 uint32_t RanOutOfData = 0;
169 uint32_t UnknownISRcounter = 0;
170 uint32_t IntTxEndIsrCounter = 0;
171 uint32_t IntTxThrIsrCounter = 0;
172 uint32_t RxIsr = 0;
173 uint32_t ErrorIsr = 0;
174 uint32_t IntensityValuesSent = 0;
175 uint32_t IntensityBitsSent = 0;
176 uint32_t IntensityValuesSentLastFrame = 0;
177 uint32_t IntensityBitsSentLastFrame = 0;
178 uint32_t IncompleteFrame = 0;
179 uint32_t BitTypeCounters[RmtDataBitIdType_t::RMT_NUM_BIT_TYPES];
180 uint32_t RmtEntriesTransfered = 0;
181 uint32_t RmtXmtFills = 0;
182 uint32_t RmtWhiteDetected = 0;
183 uint32_t FailedToSendAllData = 0;
184
185#define RMT_DEBUG_COUNTER(p) p
186
187#else
188
189#define RMT_DEBUG_COUNTER(p)
190
191#endif // def USE_RMT_DEBUG_COUNTERS
192
193};
194#endif // def #ifdef ARDUINO_ARCH_ESP32
const CN_PROGMEM char CN_RMT[]
Definition ConstNames.cpp:179
Definition OutputCommon.hpp:31
Definition OutputPixel.hpp:28
config_t config
Definition main.cpp:93
void GetDriverName(String &Name)
Definition main.cpp:115