FabGL
ESP32 Display Controller and Graphics Library
cvbsgenerator.h
1/*
2 Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3 Copyright (c) 2019-2022 Fabrizio Di Vittorio.
4 All rights reserved.
5
6
7* Please contact fdivitto2013@gmail.com if you need a commercial license.
8
9
10* This library and related software is available under GPL v3.
11
12 FabGL is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 FabGL is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with FabGL. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26
27#pragma once
28
29#include <stdint.h>
30#include <stddef.h>
31#include <math.h>
32
33#if __has_include("esp32/rom/lldesc.h")
34 #include "esp32/rom/lldesc.h"
35#else
36 #include "rom/lldesc.h"
37#endif
38#include "soc/i2s_struct.h"
39#include "soc/sens_struct.h"
40
41#include "fabglconf.h"
42
43
44namespace fabgl {
45
46
47// Note about *frameGroupCount* and PAL:
48// It should be 4 (8 fields) to perform correct burst cycling (bruch sequence).
49// Note about *frameGroupCount* and NTSC:
50// It should be 2 (4 fields) to perfom complete subcarrier cycle
51// Note about *sampleRate_hz*:
52// Setting exactly 16000000 or 13333333.3334 will disable APLL, allowing second DAC channel to be usable
53// Other values makes second DAC not usable!
54struct CVBSParams {
55 char const * desc;
56 double sampleRate_hz; // sample rate (see note above)
57 double subcarrierFreq_hz;
58 double line_us; // line duration
59 double hline_us; // half line duration (vsync and equalization pulse)
60 double hsync_us; // horizontal sync pulse duration
61 double backPorch_us; // back porch duration
62 double frontPorch_us; // front porch duration
63 double hblank_us; // horizontal blank after back porch to keep blank (adjusts horizontal position)
64 double burstCycles; // number of color burst cycles
65 double burstStart_us; // (breeze way) time from backPorch_us to color burst
66 double fieldLines; // number of lines in a field
67 double longPulse_us; // vertical sync, long pulse duration
68 double shortPulse_us; // vertical sync, short pulse duration (equalization pulse)
69 double hsyncEdge_us; // line sync falling and rising edges duration
70 double vsyncEdge_us; // short and long syncs falling and rising edge duration
71 uint8_t blankLines; // vertical blank after vertical sync to keep blank (adjusts vertical position)
72 uint8_t frameGroupCount; // number of frames for each DMA chain. Controls how much fields are presented to getBurstPhase() function. See note above.
73 int8_t preEqualizingPulseCount; // vertical sync, number of short pulses just before vsync (at the beginning of field)
74 int8_t vsyncPulseCount; // vertical sync, number of long pulses (must be >0 to generate first ISR)
75 int8_t postEqualizingPulseCount; // vertical sync, number of short pulses just after vsync
76 int8_t endFieldEqualizingPulseCount; // verticao sync, number of short pulses at the end of field
77 uint8_t syncLevel; // DAC level of sync pulses
78 uint8_t blackLevel; // DAC level of black
79 uint8_t whiteLevel; // DAC level of white
80 int8_t burstAmp; // DAC amplitude of color burst
81 uint16_t defaultVisibleSamples; // default horizontal visible samples
82 uint16_t defaultVisibleLines; // default vertical visible lines (per field)
83 uint8_t fieldStartingLine[2]; // starting line of each field ([0]=first field, [1]=second field), in range 1..2
84 uint8_t fields; // number of fields (max 2)
85 uint8_t interlaceFactor; // 1 = progressive, 2 = interlaced
86
87 // params ranges:
88 // frame : 1 ... frameGroupCount
89 // frameLine : 1 ... fields * fieldLines
90 // ret:
91 // false = line hasn't color burst
92 virtual bool lineHasColorBurst(int frame, int frameLine) const = 0;
93
94 // phase in radians, red 0...1, green 0...1, blue 0...1
95 virtual double getComposite(bool oddLine, double phase, double red, double green, double blue, double * Y) const = 0;
96
97 // phase in radians
98 virtual double getColorBurst(bool oddLine, double phase) const = 0;
99
100};
101
102
103#define CVBS_ALLOCATED_LINES 4
104
105
106// increasing this value will require more memory available
107#define CVBS_SUBCARRIERPHASES 100
108
109#if CVBS_SUBCARRIERPHASES > 128
110 typedef uint16_t scPhases_t;
111#else
112 typedef uint8_t scPhases_t;
113#endif
114
115// value used in m_subCarrierPhases[] to indicate "no burst"
116#define CVBS_NOBURSTFLAG (CVBS_SUBCARRIERPHASES * 2 - 1)
117
118
119#if FABGLIB_CVBSCONTROLLER_PERFORMANCE_CHECK
120 extern volatile uint64_t s_cvbsctrlcycles;
121#endif
122
123
124typedef void (*CVBSDrawScanlineCallback)(void * arg, uint16_t * dest, int destSample, int scanLine);
125
126
127class CVBSGenerator {
128
129public:
130
131 CVBSGenerator();
132
133 // gpio can be:
134 // GPIO_NUM_25 : gpio 25 DAC connected to DMA, gpio 26 set using setConstDAC()
135 // GPIO_NUM_26 : gpio 26 DAC connected to DMA, gpio 25 set using setConstDAC()
136 void setVideoGPIO(gpio_num_t gpio);
137
138 void setDrawScanlineCallback(CVBSDrawScanlineCallback drawScanlineCallback, void * arg = nullptr);
139
140 void setup(char const * desc);
141 void setup(CVBSParams const * params);
142
143 static CVBSParams const * getParamsFromDesc(char const * desc);
144
145 void run(bool subCarrierOnly = false);
146
147 void stop();
148
149 // usable just when sampleRate is 16Mhz or 13.333Mhz!
150 void setConstDAC(uint8_t value) {
151 //WRITE_PERI_REG(I2S_CONF_SIGLE_DATA_REG(0), value << 24);
152 I2S0.conf_single_data = value << 24;
153 }
154
155 static bool VSync() { return s_VSync; }
156 static int field() { return s_field; }
157 static int frame() { return s_frame; }
158 static int frameLine() { return s_frameLine; }
159 static int subCarrierPhase() { return *s_subCarrierPhase; }
160 static int pictureLine() { return s_scanLine; }
161 static bool lineSwitch() { return s_lineSwitch; }
162 static scPhases_t * lineSampleToSubCarrierSample() { return (scPhases_t*) s_lineSampleToSubCarrierSample; }
163 static int firstVisibleSample() { return s_firstVisibleSample; } // first visible sample in a line
164
165 int visibleLines() { return m_visibleLines; } // visible lines in a field
166 int visibleSamples() { return s_visibleSamplesCount; } // visible samples in a line
167
168 CVBSParams const * params() { return m_params; }
169
170
171private:
172
173 void runDMA(lldesc_t volatile * dmaBuffers);
174 volatile lldesc_t * setDMANode(int index, volatile uint16_t * buf, int len);
175 void closeDMAChain(int index);
176 void buildDMAChain();
177 void buildDMAChain_subCarrierOnly();
178 void addExtraSamples(double us, double * aus, int * node);
179 static void ISRHandler(void * arg);
180
181
182 // live counters
183 static volatile int s_scanLine;
184 static volatile bool s_VSync;
185 static volatile int s_field; // current field: 0 = first field, 1 = second field
186 static volatile int s_frame; // current frame: 0 to m_params->frameGroupCount - 1
187 static volatile int s_frameLine; // current frame line: 0 to m_params->fieldLines * 2 - 1. Integer part only (ie line 200.5 will be 200). This is not equivalent to image "scanline" in case of interlaced fields.
188 static volatile int s_activeLineIndex; // current active line index: 0... active line index (reset for each field)
189 static volatile scPhases_t * s_subCarrierPhase; // ptr to current subcarrier phase: sample index in m_colorBurstLUT[] LUT, 0..CVBS_SUBCARRIERPHASES*2
190 static volatile bool s_lineSwitch; // line switch
191
192 gpio_num_t m_gpio;
193 bool m_DMAStarted;
194 lldesc_t volatile * m_DMAChain;
195
196 // signals buffers
197 volatile uint16_t * m_lsyncBuf; // vertical blank, long pulse buffer
198 volatile uint16_t * m_ssyncBuf; // vertical blank, short pulse buffer (equalizing pulse)
199 volatile uint16_t * * m_lineBuf; // hsync + back porch + line + front porch
200
201 // not allocated buffers
202 volatile uint16_t * m_blackBuffer; // derived from ending black part of m_ssyncBuf
203 int m_blackBufferLength; // number of available samples in m_blackBuffer
204
205
206 intr_handle_t m_isr_handle;
207 static volatile int16_t s_visibleSamplesCount; // visible samples in a line
208 static volatile int16_t s_firstVisibleSample; // first visible sample (0...)
209 CVBSDrawScanlineCallback m_drawScanlineCallback;
210 void * m_drawScanlineArg;
211 volatile int16_t m_visibleLines; // visible lines in a field
212 int16_t m_firstVisibleFieldLine; // 1...
213 int16_t m_lastVisibleFieldLine; // 1...
214 volatile int16_t m_firstActiveFrameLine[2]; // first active frame line for specified field (0..) in range 0..
215 volatile int16_t m_firstVisibleFrameLine[2]; // first visible frame line for specified field (0..) in range 0..
216 volatile int16_t m_lastVisibleFrameLine[2]; // last visible frame line for specified field (0..) in range 0..
217 volatile int16_t m_startingScanLine[2]; // starting scanline for each field (0..) in range 0..
218 volatile scPhases_t * m_subCarrierPhases[4]; // subcarrier phase for [frame][frameLine], in samples from start of hsync
219 volatile uint16_t m_colorBurstLUT[2][CVBS_SUBCARRIERPHASES * 2];
220 volatile uint16_t m_firstColorBurstSample; // sample where color burst starts (starting from hsync)
221 volatile uint16_t m_lastColorBurstSample; // sample where color burst ends
222 volatile int m_linesPerFrame; // number of lines in a frame
223 static volatile scPhases_t * s_lineSampleToSubCarrierSample; // converts a line sample (full line, from hsync to front porch) to m_colorBurstLUT[] item
224 double m_actualLine_us; // actual value of m_params->line_us, after samples alignment
225 double m_actualHLine_us; // actual value of m_params->hline_us, after samples alignment
226 double m_sample_us; // duration of a sample
227 bool m_firstActiveFieldLineSwitch[4][2]; // line switch state for first active line at frame (0..) and field (0..)
228
229 CVBSParams const * m_params; // decides the CVBS standard (PAL, NTSC...)
230
231};
232
233
234
235} // namespace fabgl
int16_t Y
This file contains FabGL library configuration settings, like number of supported colors,...