Skip to content

Commit 024257a

Browse files
committed
first commit
0 parents  commit 024257a

File tree

9 files changed

+427
-0
lines changed

9 files changed

+427
-0
lines changed

DMABuffer.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#pragma once
2+
3+
class DMABuffer
4+
{
5+
public:
6+
lldesc_t descriptor;
7+
unsigned char* buffer;
8+
DMABuffer(int bytes)
9+
{
10+
buffer = (unsigned char *)malloc(bytes);
11+
descriptor.length = bytes;
12+
descriptor.size = descriptor.length;
13+
descriptor.owner = 1;
14+
descriptor.sosf = 1;
15+
descriptor.buf = (uint8_t*) buffer;
16+
descriptor.offset = 0;
17+
descriptor.empty = 0;
18+
descriptor.eof = 1;
19+
descriptor.qe.stqe_next = 0;
20+
}
21+
22+
void next(DMABuffer *next)
23+
{
24+
descriptor.qe.stqe_next = &(next->descriptor);
25+
}
26+
27+
int sampleCount() const
28+
{
29+
return descriptor.length / 4;
30+
}
31+
32+
~DMABuffer()
33+
{
34+
if(buffer)
35+
delete(buffer);
36+
}
37+
};
38+

ESP32_I2S_Camera.ino

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//#include Camera.h
2+
#include "soc/soc.h"
3+
#include "soc/gpio_sig_map.h"
4+
#include "soc/i2s_reg.h"
5+
#include "soc/i2s_struct.h"
6+
#include "soc/io_mux_reg.h"
7+
8+
#include <driver/dac.h>
9+
10+
#include "I2S.h"
11+
12+
//esp32 mini kit
13+
//boot 0 2 5
14+
//flash 6(clk) 7(sd0) 8(sd1) 9(sd2) 10(sd3) 11(cmd)
15+
//UART 1(tx) 3(rx)
16+
//free pins 4 12(tdi) 13(tck) 14(tms) 15(tdo) 16 17 27 32 33
17+
//spi 18(sck) 19(miso) 23(mosi) 5(ss)
18+
//i2c 21(sda) 22(scl)
19+
//dac 25 26
20+
//input only 34 35 36(svp) 39(svn)
21+
22+
//pins 0 2 5 are used for boot.. only connect hi-z. can still be used as output without external pullups
23+
//free pins 4 12 13 14 15 16 17 27 32 33
24+
//input only 34, 35, 36(VP), 39(VN)
25+
//dac 25, 26
26+
27+
const int SIOD = 21; //SDA
28+
const int SIOC = 22; //SCL
29+
30+
const int VSYNC = 34;//25;
31+
const int HREF = 35;//23;
32+
33+
const int XCLK = 32;//21;
34+
const int PCLK = 33;
35+
36+
const int D0 = 4;
37+
const int D1 = 12;
38+
const int D2 = 13;
39+
const int D3 = 14;
40+
const int D4 = 15;
41+
const int D5 = 16;
42+
const int D6 = 17;
43+
const int D7 = 27;
44+
45+
const int DC = 2;
46+
47+
//const int DAC1 = 25;
48+
//const int DAC2 = 26;
49+
#include <math.h>
50+
51+
const int XRES = 640;
52+
const int YRES = 480;
53+
54+
void setup()
55+
{
56+
Serial.begin(115200);
57+
I2S::init(XRES, YRES, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7);
58+
//dac_output_enable(DAC_CHANNEL_1); //25
59+
//dac_output_enable(DAC_CHANNEL_2); //26
60+
61+
}
62+
63+
64+
void loop()
65+
{
66+
Serial.print(I2S::blocksReceived);
67+
Serial.print(' ');
68+
Serial.println(I2S::framesReceived);
69+
Serial.print(' ');
70+
for(int i = 0; i < 16; i++)
71+
{
72+
if(I2S::dmaBuffer[0]->buffer[i] < 16) Serial.print('0');
73+
Serial.print(I2S::dmaBuffer[0]->buffer[i], HEX);
74+
}
75+
Serial.println();
76+
delay(1000);
77+
}

I2S.cpp

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
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+
}

I2S.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#pragma once
2+
3+
#include "soc/soc.h"
4+
#include "soc/gpio_sig_map.h"
5+
#include "soc/i2s_reg.h"
6+
#include "soc/i2s_struct.h"
7+
#include "soc/io_mux_reg.h"
8+
#include "driver/gpio.h"
9+
#include "driver/periph_ctrl.h"
10+
#include "rom/lldesc.h"
11+
#include "XClk.h"
12+
#include "DMABuffer.h"
13+
14+
class I2S
15+
{
16+
public:
17+
static gpio_num_t vSyncPin;
18+
static int blocksReceived;
19+
static int framesReceived;
20+
static int xres;
21+
static int yres;
22+
static intr_handle_t i2sInterruptHandle;
23+
static intr_handle_t vSyncInterruptHandle;
24+
static int dmaBufferCount;
25+
static DMABuffer **dmaBuffer;
26+
static unsigned char* frame;
27+
static int framePointer;
28+
29+
typedef enum {
30+
/* camera sends byte sequence: s1, s2, s3, s4, ...
31+
* fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ...
32+
*/
33+
SM_0A0B_0B0C = 0,
34+
/* camera sends byte sequence: s1, s2, s3, s4, ...
35+
* fifo receives: 00 s1 00 s2, 00 s3 00 s4, ...
36+
*/
37+
SM_0A0B_0C0D = 1,
38+
/* camera sends byte sequence: s1, s2, s3, s4, ...
39+
* fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ...
40+
*/
41+
SM_0A00_0B00 = 3,
42+
} i2s_sampling_mode_t;
43+
44+
45+
static inline void i2sConfReset()
46+
{
47+
const uint32_t lc_conf_reset_flags = I2S_IN_RST_M | I2S_AHBM_RST_M | I2S_AHBM_FIFO_RST_M;
48+
I2S0.lc_conf.val |= lc_conf_reset_flags;
49+
I2S0.lc_conf.val &= ~lc_conf_reset_flags;
50+
51+
const uint32_t conf_reset_flags = I2S_RX_RESET_M | I2S_RX_FIFO_RESET_M | I2S_TX_RESET_M | I2S_TX_FIFO_RESET_M;
52+
I2S0.conf.val |= conf_reset_flags;
53+
I2S0.conf.val &= ~conf_reset_flags;
54+
while (I2S0.state.rx_fifo_reset_back);
55+
}
56+
57+
static void i2sStop();
58+
static void i2sRun();
59+
60+
static bool dmaBufferInit(int bytes);
61+
static void dmaBufferDeinit();
62+
63+
static bool initVSync(int pin);
64+
static void deinitVSync();
65+
66+
static void IRAM_ATTR i2sInterrupt(void* arg);
67+
static void IRAM_ATTR vSyncInterrupt(void* arg);
68+
69+
static bool 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);
70+
71+
static bool 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);
72+
};

Log.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#pragma once
2+
#include "Arduino.h"
3+
4+
#define DEBUG_PRINTLN(a) Serial.println(a)
5+
#define DEBUG_PRINT(a) Serial.print(a)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# ESP32_DMA_Camera

0 commit comments

Comments
 (0)