|
| 1 | +#include "I2S.h" |
| 2 | +#include "Log.h" |
| 3 | + |
| 4 | +int I2S::blocksReceived = 0; |
| 5 | +int I2S::framesReceived = 0; |
| 6 | +int I2S::xres = 640; |
| 7 | +int I2S::yres = 480; |
| 8 | +gpio_num_t I2S::vSyncPin = (gpio_num_t)0; |
| 9 | +intr_handle_t I2S::i2sInterruptHandle = 0; |
| 10 | +intr_handle_t I2S::vSyncInterruptHandle = 0; |
| 11 | +int I2S::dmaBufferCount = 0; |
| 12 | +DMABuffer **I2S::dmaBuffer = 0; |
| 13 | +unsigned char* I2S::frame = 0; |
| 14 | +int I2S::framePointer = 0; |
| 15 | + |
| 16 | +void IRAM_ATTR I2S::i2sInterrupt(void* arg) |
| 17 | +{ |
| 18 | + I2S0.int_clr.val = I2S0.int_raw.val; |
| 19 | + blocksReceived++; |
| 20 | + //if (blocksReceived == yres) |
| 21 | + // i2sStop(); |
| 22 | +} |
| 23 | + |
| 24 | +void IRAM_ATTR I2S::vSyncInterrupt(void* arg) |
| 25 | +{ |
| 26 | + GPIO.status1_w1tc.val = GPIO.status1.val; |
| 27 | + GPIO.status_w1tc = GPIO.status; |
| 28 | + if(gpio_get_level(vSyncPin) == 0) |
| 29 | + framesReceived++; |
| 30 | +} |
| 31 | + |
| 32 | +void I2S::i2sStop() |
| 33 | +{ |
| 34 | + esp_intr_disable(i2sInterruptHandle); |
| 35 | + esp_intr_disable(vSyncInterruptHandle); |
| 36 | + i2sConfReset(); |
| 37 | + I2S0.conf.rx_start = 0; |
| 38 | +} |
| 39 | + |
| 40 | +void I2S::i2sRun() |
| 41 | +{ |
| 42 | + DEBUG_PRINTLN("I2S Run"); |
| 43 | + while (gpio_get_level(vSyncPin) == 0); |
| 44 | + while (gpio_get_level(vSyncPin) != 0); |
| 45 | + |
| 46 | + blocksReceived = 0; |
| 47 | + esp_intr_disable(i2sInterruptHandle); |
| 48 | + i2sConfReset(); |
| 49 | + |
| 50 | + DEBUG_PRINT("Sample count "); |
| 51 | + DEBUG_PRINTLN(dmaBuffer[0]->sampleCount()); |
| 52 | + I2S0.rx_eof_num = dmaBuffer[0]->sampleCount(); |
| 53 | + I2S0.in_link.addr = (uint32_t)&(dmaBuffer[0]->descriptor); |
| 54 | + I2S0.in_link.start = 1; |
| 55 | + I2S0.int_clr.val = I2S0.int_raw.val; |
| 56 | + I2S0.int_ena.val = 0; |
| 57 | + I2S0.int_ena.in_done = 1; |
| 58 | + esp_intr_enable(i2sInterruptHandle); |
| 59 | + esp_intr_enable(vSyncInterruptHandle); |
| 60 | + I2S0.conf.rx_start = 1; |
| 61 | +} |
| 62 | + |
| 63 | +bool I2S::initVSync(int pin) |
| 64 | +{ |
| 65 | + DEBUG_PRINT("Initializing VSYNC... "); |
| 66 | + vSyncPin = (gpio_num_t)pin; |
| 67 | + gpio_set_intr_type(vSyncPin, GPIO_INTR_NEGEDGE); |
| 68 | + gpio_intr_enable(vSyncPin); |
| 69 | + if(gpio_isr_register(&vSyncInterrupt, (void*)"vSyncInterrupt", ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM, &vSyncInterruptHandle) != ESP_OK) |
| 70 | + { |
| 71 | + DEBUG_PRINTLN("failed!"); |
| 72 | + return false; |
| 73 | + } |
| 74 | + DEBUG_PRINTLN("done."); |
| 75 | + return true; |
| 76 | +} |
| 77 | + |
| 78 | +void I2S::deinitVSync() |
| 79 | +{ |
| 80 | + esp_intr_disable(vSyncInterruptHandle); |
| 81 | +} |
| 82 | + |
| 83 | +bool I2S::init(const int XRES, const int YRES, const int VSYNC, const int HREF, const int XCLK, const int PCLK, const int D0, const int D1, const int D2, const int D3, const int D4, const int D5, const int D6, const int D7) |
| 84 | +{ |
| 85 | + xres = XRES; |
| 86 | + yres = YRES; |
| 87 | + ClockEnable(XCLK, 20000000); //base is 80MHz |
| 88 | + i2sInit(VSYNC, HREF, PCLK, D0, D1, D2, D3, D4, D5, D6, D7); |
| 89 | + dmaBufferInit(xres * 4); |
| 90 | + initVSync(VSYNC); |
| 91 | + i2sRun(); |
| 92 | + return true; |
| 93 | +} |
| 94 | + |
| 95 | +bool I2S::i2sInit(const int VSYNC, const int HREF, const int PCLK, const int D0, const int D1, const int D2, const int D3, const int D4, const int D5, const int D6, const int D7) |
| 96 | +{ |
| 97 | + int pins[] = {VSYNC, HREF, PCLK, D0, D1, D2, D3, D4, D5, D6, D7}; |
| 98 | + gpio_config_t conf = { |
| 99 | + .pin_bit_mask = 0, |
| 100 | + .mode = GPIO_MODE_INPUT, |
| 101 | + .pull_up_en = GPIO_PULLUP_DISABLE, |
| 102 | + .pull_down_en = GPIO_PULLDOWN_DISABLE, |
| 103 | + .intr_type = GPIO_INTR_DISABLE |
| 104 | + }; |
| 105 | + for (int i = 0; i < sizeof(pins) / sizeof(gpio_num_t); ++i) { |
| 106 | + conf.pin_bit_mask = 1LL << pins[i]; |
| 107 | + gpio_config(&conf); |
| 108 | + } |
| 109 | + |
| 110 | + // Route input GPIOs to I2S peripheral using GPIO matrix, last parameter is invert |
| 111 | + gpio_matrix_in(D0, I2S0I_DATA_IN0_IDX, false); |
| 112 | + gpio_matrix_in(D1, I2S0I_DATA_IN1_IDX, false); |
| 113 | + gpio_matrix_in(D2, I2S0I_DATA_IN2_IDX, false); |
| 114 | + gpio_matrix_in(D3, I2S0I_DATA_IN3_IDX, false); |
| 115 | + gpio_matrix_in(D4, I2S0I_DATA_IN4_IDX, false); |
| 116 | + gpio_matrix_in(D5, I2S0I_DATA_IN5_IDX, false); |
| 117 | + gpio_matrix_in(D6, I2S0I_DATA_IN6_IDX, false); |
| 118 | + gpio_matrix_in(D7, I2S0I_DATA_IN7_IDX, false); |
| 119 | + gpio_matrix_in(0x30, I2S0I_DATA_IN8_IDX, false); |
| 120 | + gpio_matrix_in(0x30, I2S0I_DATA_IN9_IDX, false); |
| 121 | + gpio_matrix_in(0x30, I2S0I_DATA_IN10_IDX, false); |
| 122 | + gpio_matrix_in(0x30, I2S0I_DATA_IN11_IDX, false); |
| 123 | + gpio_matrix_in(0x30, I2S0I_DATA_IN12_IDX, false); |
| 124 | + gpio_matrix_in(0x30, I2S0I_DATA_IN13_IDX, false); |
| 125 | + gpio_matrix_in(0x30, I2S0I_DATA_IN14_IDX, false); |
| 126 | + gpio_matrix_in(0x30, I2S0I_DATA_IN15_IDX, false); |
| 127 | + |
| 128 | + gpio_matrix_in(VSYNC, I2S0I_V_SYNC_IDX, true); |
| 129 | + gpio_matrix_in(0x38, I2S0I_H_SYNC_IDX, false); //0x30 sends 0, 0x38 sends 1 |
| 130 | + gpio_matrix_in(HREF, I2S0I_H_ENABLE_IDX, false); |
| 131 | + gpio_matrix_in(PCLK, I2S0I_WS_IN_IDX, false); |
| 132 | + |
| 133 | + // Enable and configure I2S peripheral |
| 134 | + periph_module_enable(PERIPH_I2S0_MODULE); |
| 135 | + |
| 136 | + // Toggle some reset bits in LC_CONF register |
| 137 | + // Toggle some reset bits in CONF register |
| 138 | + i2sConfReset(); |
| 139 | + // Enable slave mode (sampling clock is external) |
| 140 | + I2S0.conf.rx_slave_mod = 1; |
| 141 | + // Enable parallel mode |
| 142 | + I2S0.conf2.lcd_en = 1; |
| 143 | + // Use HSYNC/VSYNC/HREF to control sampling |
| 144 | + I2S0.conf2.camera_en = 1; |
| 145 | + // Configure clock divider |
| 146 | + /*I2S0.clkm_conf.clkm_div_a = 1; |
| 147 | + I2S0.clkm_conf.clkm_div_b = 0; |
| 148 | + I2S0.clkm_conf.clkm_div_num = 2;*/ |
| 149 | + I2S0.clkm_conf.clkm_div_a = 0; |
| 150 | + I2S0.clkm_conf.clkm_div_b = 0; |
| 151 | + I2S0.clkm_conf.clkm_div_num = 1; |
| 152 | + |
| 153 | + // FIFO will sink data to DMA |
| 154 | + I2S0.fifo_conf.dscr_en = 1; |
| 155 | + // FIFO configuration |
| 156 | + I2S0.fifo_conf.rx_fifo_mod = SM_0A0B_0C0D; //pack two bytes in one dword see :https://github.com/igrr/esp32-cam-demo/issues/29 |
| 157 | + I2S0.fifo_conf.rx_fifo_mod_force_en = 1; |
| 158 | + I2S0.conf_chan.rx_chan_mod = 1; |
| 159 | + // Clear flags which are used in I2S serial mode |
| 160 | + I2S0.sample_rate_conf.rx_bits_mod = 0; |
| 161 | + I2S0.conf.rx_right_first = 0; |
| 162 | + I2S0.conf.rx_msb_right = 0; |
| 163 | + I2S0.conf.rx_msb_shift = 0; |
| 164 | + I2S0.conf.rx_mono = 0; |
| 165 | + I2S0.conf.rx_short_sync = 0; |
| 166 | + I2S0.timing.val = 0; |
| 167 | + |
| 168 | + // Allocate I2S interrupt, keep it disabled |
| 169 | + esp_intr_alloc(ETS_I2S0_INTR_SOURCE, ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, &i2sInterrupt, NULL, &i2sInterruptHandle); |
| 170 | + return true; |
| 171 | +} |
| 172 | + |
| 173 | +bool I2S::dmaBufferInit(int bytes) |
| 174 | +{ |
| 175 | + dmaBufferCount = 2; |
| 176 | + dmaBuffer = (DMABuffer**) malloc(sizeof(DMABuffer*) * dmaBufferCount); |
| 177 | + for(int i = 0; i < dmaBufferCount; i++) |
| 178 | + { |
| 179 | + dmaBuffer[i] = new DMABuffer(bytes); |
| 180 | + if(i) |
| 181 | + dmaBuffer[i-1]->next(dmaBuffer[i]); |
| 182 | + } |
| 183 | + dmaBuffer[dmaBufferCount - 1]->next(dmaBuffer[0]); |
| 184 | +} |
| 185 | + |
| 186 | +void I2S::dmaBufferDeinit() |
| 187 | +{ |
| 188 | + if (!dmaBuffer) return; |
| 189 | + for(int i = 0; i < dmaBufferCount; i++) |
| 190 | + delete(dmaBuffer[i]); |
| 191 | + delete(dmaBuffer); |
| 192 | + dmaBuffer = 0; |
| 193 | + dmaBufferCount = 0; |
| 194 | +} |
0 commit comments