FabGL
ESP32 Display Controller and Graphics Library
swgenerator.cpp
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
28#include <alloca.h>
29
30#include "freertos/FreeRTOS.h"
31#include "freertos/task.h"
32
33#include "soc/i2s_struct.h"
34#include "soc/i2s_reg.h"
35#include "driver/periph_ctrl.h"
36#include "soc/rtc.h"
37
38#include "fabutils.h"
39#include "swgenerator.h"
40
41
42
43#pragma GCC optimize ("O2")
44
45
46namespace fabgl {
47
48
49
50/*************************************************************************************/
51/* GPIOStream definitions */
52
53void GPIOStream::begin()
54{
55 m_DMAStarted = false;
56 m_DMABuffer = nullptr;
57 m_DMAData = nullptr;
58}
59
60
61void GPIOStream::begin(bool div1_onGPIO0, gpio_num_t div2, gpio_num_t div4, gpio_num_t div8, gpio_num_t div16, gpio_num_t div32, gpio_num_t div64, gpio_num_t div128, gpio_num_t div256)
62{
63 m_DMAStarted = false;
64
65 if (div1_onGPIO0)
66 setupGPIO(GPIO_NUM_0, -1, GPIO_MODE_OUTPUT); // note: GPIO_NUM_0 cannot be changed!
67 setupGPIO(div2, 0, GPIO_MODE_OUTPUT);
68 setupGPIO(div4, 1, GPIO_MODE_OUTPUT);
69 setupGPIO(div8, 2, GPIO_MODE_OUTPUT);
70 setupGPIO(div16, 3, GPIO_MODE_OUTPUT);
71 setupGPIO(div32, 4, GPIO_MODE_OUTPUT);
72 setupGPIO(div64, 5, GPIO_MODE_OUTPUT);
73 setupGPIO(div128, 6, GPIO_MODE_OUTPUT);
74 setupGPIO(div256, 7, GPIO_MODE_OUTPUT);
75
76 m_DMAData = (volatile uint8_t *) heap_caps_malloc(256, MALLOC_CAP_DMA);
77 for (int i = 0; i < 256; ++i)
78 m_DMAData[i] = i;
79
80 m_DMABuffer = (volatile lldesc_t *) heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA);
81 m_DMABuffer->eof = 0;
82 m_DMABuffer->sosf = 0;
83 m_DMABuffer->owner = 1;
84 m_DMABuffer->qe.stqe_next = (lldesc_t *) m_DMABuffer;
85 m_DMABuffer->offset = 0;
86 m_DMABuffer->size = 256;
87 m_DMABuffer->length = 256;
88 m_DMABuffer->buf = (uint8_t*) m_DMAData;
89}
90
91
92void GPIOStream::end()
93{
94 stop();
95}
96
97
98
99// if bit is -1 = clock signal
100// gpio = GPIO_UNUSED means not set
101void GPIOStream::setupGPIO(gpio_num_t gpio, int bit, gpio_mode_t mode)
102{
103 if (gpio != GPIO_UNUSED) {
104
105 if (bit == -1) {
106 // I2S1 clock out to CLK_OUT1 (fixed to GPIO0)
107 WRITE_PERI_REG(PIN_CTRL, 0xF);
108 PIN_FUNC_SELECT(GPIO_PIN_REG_0, FUNC_GPIO0_CLK_OUT1);
109 } else {
110 configureGPIO(gpio, mode);
111 gpio_matrix_out(gpio, I2S1O_DATA_OUT0_IDX + bit, false, false);
112 }
113
114 }
115}
116
117
118void GPIOStream::play(int freq, lldesc_t volatile * dmaBuffers)
119{
120 if (!m_DMAStarted) {
121
122 // Power on device
123 periph_module_enable(PERIPH_I2S1_MODULE);
124
125 // Initialize I2S device
126 I2S1.conf.tx_reset = 1;
127 I2S1.conf.tx_reset = 0;
128
129 // Reset DMA
130 I2S1.lc_conf.out_rst = 1;
131 I2S1.lc_conf.out_rst = 0;
132
133 // Reset FIFO
134 I2S1.conf.tx_fifo_reset = 1;
135 I2S1.conf.tx_fifo_reset = 0;
136
137 // LCD mode
138 I2S1.conf2.val = 0;
139 I2S1.conf2.lcd_en = 1;
140 I2S1.conf2.lcd_tx_wrx2_en = 1;
141 I2S1.conf2.lcd_tx_sdx2_en = 0;
142
143 I2S1.sample_rate_conf.val = 0;
144 I2S1.sample_rate_conf.tx_bits_mod = 8;
145
146 setupClock(freq);
147
148 I2S1.fifo_conf.val = 0;
149 I2S1.fifo_conf.tx_fifo_mod_force_en = 1;
150 I2S1.fifo_conf.tx_fifo_mod = 1;
151 I2S1.fifo_conf.tx_fifo_mod = 1;
152 I2S1.fifo_conf.tx_data_num = 32;
153 I2S1.fifo_conf.dscr_en = 1;
154
155 I2S1.conf1.val = 0;
156 I2S1.conf1.tx_stop_en = 0;
157 I2S1.conf1.tx_pcm_bypass = 1;
158
159 I2S1.conf_chan.val = 0;
160 I2S1.conf_chan.tx_chan_mod = 1;
161
162 I2S1.conf.tx_right_first = 1;
163
164 I2S1.timing.val = 0;
165
166 // Reset AHB interface of DMA
167 I2S1.lc_conf.ahbm_rst = 1;
168 I2S1.lc_conf.ahbm_fifo_rst = 1;
169 I2S1.lc_conf.ahbm_rst = 0;
170 I2S1.lc_conf.ahbm_fifo_rst = 0;
171
172 // Start DMA
173 I2S1.lc_conf.val = I2S_OUT_DATA_BURST_EN | I2S_OUTDSCR_BURST_EN;
174 I2S1.out_link.addr = (uint32_t) (dmaBuffers ? &dmaBuffers[0] : m_DMABuffer);
175 I2S1.out_link.start = 1;
176 I2S1.conf.tx_start = 1;
177
178 m_DMAStarted = true;
179
180 }
181}
182
183
184void GPIOStream::stop()
185{
186 if (m_DMAStarted) {
187 rtc_clk_apll_enable(false, 0, 0, 0, 0);
188 periph_module_disable(PERIPH_I2S1_MODULE);
189
190 m_DMAStarted = false;
191 }
192}
193
194
195void GPIOStream::setupClock(int freq)
196{
197 APLLParams p = {0, 0, 0, 0};
198 double error, out_freq;
199 uint8_t a = 1, b = 0;
200 APLLCalcParams(freq, &p, &a, &b, &out_freq, &error);
201
202 I2S1.clkm_conf.val = 0;
203 I2S1.clkm_conf.clkm_div_b = b;
204 I2S1.clkm_conf.clkm_div_a = a;
205 I2S1.clkm_conf.clkm_div_num = 2; // not less than 2
206
207 I2S1.sample_rate_conf.tx_bck_div_num = 1; // this makes I2S1O_BCK = I2S1_CLK
208
209 rtc_clk_apll_enable(true, p.sdm0, p.sdm1, p.sdm2, p.o_div);
210
211 I2S1.clkm_conf.clka_en = 1;
212}
213
214
215
216
217
218
219} // end of namespace
220
221
This file contains some utility classes and functions.
This file contains fabgl::GPIOStream definition.