30 #include "freertos/FreeRTOS.h" 31 #include "freertos/task.h" 33 #include "soc/i2s_struct.h" 34 #include "soc/i2s_reg.h" 35 #include "driver/periph_ctrl.h" 43 #pragma GCC optimize ("O2") 53 void GPIOStream::begin()
56 m_DMABuffer =
nullptr;
61 void 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)
66 setupGPIO(GPIO_NUM_0, -1, GPIO_MODE_OUTPUT);
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);
76 m_DMAData = (
volatile uint8_t *) heap_caps_malloc(256, MALLOC_CAP_DMA);
77 for (
int i = 0; i < 256; ++i)
80 m_DMABuffer = (
volatile lldesc_t *) heap_caps_malloc(
sizeof(lldesc_t), MALLOC_CAP_DMA);
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;
92 void GPIOStream::end()
101 void GPIOStream::setupGPIO(gpio_num_t gpio,
int bit, gpio_mode_t mode)
103 if (gpio != GPIO_UNUSED) {
107 WRITE_PERI_REG(PIN_CTRL, 0xF);
108 PIN_FUNC_SELECT(GPIO_PIN_REG_0, FUNC_GPIO0_CLK_OUT1);
110 configureGPIO(gpio, mode);
111 gpio_matrix_out(gpio, I2S1O_DATA_OUT0_IDX + bit,
false,
false);
118 void GPIOStream::play(
int freq, lldesc_t
volatile * dmaBuffers)
123 periph_module_enable(PERIPH_I2S1_MODULE);
126 I2S1.conf.tx_reset = 1;
127 I2S1.conf.tx_reset = 0;
130 I2S1.lc_conf.out_rst = 1;
131 I2S1.lc_conf.out_rst = 0;
134 I2S1.conf.tx_fifo_reset = 1;
135 I2S1.conf.tx_fifo_reset = 0;
139 I2S1.conf2.lcd_en = 1;
140 I2S1.conf2.lcd_tx_wrx2_en = 1;
141 I2S1.conf2.lcd_tx_sdx2_en = 0;
143 I2S1.sample_rate_conf.val = 0;
144 I2S1.sample_rate_conf.tx_bits_mod = 8;
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;
156 I2S1.conf1.tx_stop_en = 0;
157 I2S1.conf1.tx_pcm_bypass = 1;
159 I2S1.conf_chan.val = 0;
160 I2S1.conf_chan.tx_chan_mod = 1;
162 I2S1.conf.tx_right_first = 1;
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;
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;
184 void GPIOStream::stop()
187 rtc_clk_apll_enable(
false, 0, 0, 0, 0);
188 periph_module_disable(PERIPH_I2S1_MODULE);
190 m_DMAStarted =
false;
206 #if FABGLIB_USE_APLL_AB_COEF 207 void floatToFraction(
double value,
int maxDen,
int * num,
int * den)
209 int64_t a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 };
211 while (value != floor(value)) {
216 for (
int i = 0; i < 64; ++i) {
224 if (k[1] * a + k[0] >= maxDen) {
225 x = (maxDen - k[0]) / k[1];
226 if (x * 2 >= a || k[1] >= maxDen)
231 h[2] = x * h[1] + h[0];
234 k[2] = x * k[1] + k[0];
353 static void APLLCalcParams(
double freq, APLLParams * params, uint8_t * a, uint8_t * b,
double * out_freq,
double * error)
359 double apll_freq = freq * 2;
361 for (
int o_div = 0; o_div <= 31; ++o_div) {
363 int idivisor = (2 * o_div + 4);
365 for (
int sdm2 = 4; sdm2 <= 8; ++sdm2) {
368 int minSDM1 = (sdm2 == 4 ? 192 : 0);
369 int maxSDM1 = (sdm2 == 8 ? 128 : 255);
371 int startSDM1 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2) * 256.0 / FXTAL);
372 #if FABGLIB_USE_APLL_AB_COEF 373 for (
int isdm1 = tmax(minSDM1, startSDM1); isdm1 <= maxSDM1; ++isdm1) {
375 int isdm1 = startSDM1; {
379 sdm1 = tmax(minSDM1, sdm1);
380 sdm1 = tmin(maxSDM1, sdm1);
383 int sdm0 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2 - FXTAL * sdm1 / 256.0) * 65536.0 / FXTAL);
385 sdm0 = (sdm2 == 8 && sdm1 == 128 ? 0 : tmin(255, sdm0));
386 sdm0 = tmax(0, sdm0);
389 double dividend = FXTAL * (4.0 + sdm2 + sdm1 / 256.0 + sdm0 / 65536.0);
390 if (dividend >= 350000000 && dividend <= 500000000) {
392 double oapll_freq = dividend / idivisor;
398 uint8_t oa = 1, ob = 0;
399 #if FABGLIB_USE_APLL_AB_COEF 400 double abr = oapll_freq / freq - 2.0;
401 if (abr > 0 && abr < 1) {
403 floatToFraction(abr, 63, &num, &den);
404 ob = tclamp(num, 0, 63);
405 oa = tclamp(den, 0, 63);
410 double ofreq = oapll_freq / (2.0 + (double)ob / oa);
411 double err = freq - ofreq;
412 if (abs(err) < abs(*error)) {
413 *params = (APLLParams){(uint8_t)sdm0, (uint8_t)sdm1, (uint8_t)sdm2, (uint8_t)o_div};
429 void GPIOStream::setupClock(
int freq)
431 APLLParams p = {0, 0, 0, 0};
432 double error, out_freq;
433 uint8_t a = 1, b = 0;
434 APLLCalcParams(freq, &p, &a, &b, &out_freq, &error);
436 I2S1.clkm_conf.val = 0;
437 I2S1.clkm_conf.clkm_div_b = b;
438 I2S1.clkm_conf.clkm_div_a = a;
439 I2S1.clkm_conf.clkm_div_num = 2;
441 I2S1.sample_rate_conf.tx_bck_div_num = 1;
443 rtc_clk_apll_enable(
true, p.sdm0, p.sdm1, p.sdm2, p.o_div);
445 I2S1.clkm_conf.clka_en = 1;
This file contains fabgl::GPIOStream definition.
This file contains some utility classes and functions.