Comments (39)
How HREF is used by i2s? My assumption was that HREF triggers interrupt to collect a single line by function i2s_fill_buf(cur_buffer).
I2S peripheral will sample on each PCLK clock, if all three signals are high: HREF (called H_ENABLE in code), HSYNC, VSYNC.
Here's the relevant diagram about these signals from OV7725 datasheet:
As you can see, high VSYNC signal marks spaces between frames. So we need to invert it before feeding it into the I2S peripheral (so that VSYNC == 1 while frame is being sent). This can be done in two ways: a) by setting a register in OV7725 (bit 1 in COM10 register, "VSYNC negative"), or b) by inverting the signal using ESP32 GPIO matrix (change third argument of gpio_matrix_in
function to true
). In the current code, option a) is used.
So once the I2S peripheral is configured and I2S_RX_START_S
bit is set in I2S_CONF_REG(0)
, it will start receiving data and writing to DMA (via FIFO). Sampling happens on each PCLK clock when HREF & VSYNC & HSYNC = 1. So to remove the skew, we need to start I2S after !VSYNC goes high, before the first HSYNC goes high. Also, the I2S_RX_EOF_NUM
field has to be set exactly to the number of PCLK cycles found in one line.
from esp32-cam-demo.
I have just verified that this issue is not caused by VSYNC detection. Seems like i'm not configuring DMA correctly. We are trying to troubleshoot this in simulation, then will test on the real chip.
Edit: works great in simulation... next hypothesis is that we are loosing some samples. Still messing around with this.
from esp32-cam-demo.
- To capture a single frame we are waiting for VSYNC by directly polling GPIO:
ESP_LOGD(TAG, "Waiting for VSYNC");
while(gpio_get_level(s_config.pin_vsync) != 0);
while(gpio_get_level(s_config.pin_vsync) == 0);
ESP_LOGD(TAG, "Got VSYNC");
What is then the purpose of VSYNC in i2s routines? I see it configured in function i2s_init()
:
gpio_matrix_in(s_config.pin_vsync, I2S0I_V_SYNC_IDX, false);
- Function
i2s_init()
contains:
gpio_matrix_in(s_config.pin_href, I2S0I_H_ENABLE_IDX, false);
How HREF is used by i2s? My assumption was that HREF triggers interrupt to collect a single line by function i2s_fill_buf(cur_buffer)
.
If so, why first 8 - 9 pixels (16 - 18 bytes) in a line look like invalid data and are not aligned?
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
from esp32-cam-demo.
Could you verify if figure below correctly reflects operation of camera demo?
EDIT: updated basing on #11 (comment) by @Oitzu.
from esp32-cam-demo.
Does someone actually has a picture how the fb looks like before its converted to ascii?
from esp32-cam-demo.
Using this snippet:
for (int ih = 0; ih < 40; ih++){
for (int iw = 0; iw < 40; iw++){
uint8_t px = (s_fb[iw + (ih * s_fb_w)]);
printf("%02x", px);
}
printf("\n");
}
I have prepared 40x40 bytes output of left upper corner of test pattern:
D (11629) camera: Waiting for VSYNC
D (11629) camera: Got VSYNC
D (11629) camera: Waiting for frame
D (11639) camera: Frame done
D (11639) camera_demo: Done
13131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
80ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
13131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
13131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Does it justify asking for a logic analyser for Christmas?
from esp32-cam-demo.
This issue is due to a clumsy way of waiting for VSYNC (polling GPIOs). Instead this should be changed to use GPIO interrupts and/or timers.
from esp32-cam-demo.
Does it justify asking for a logic analyser for Christmas?
Totally! Also an osci! You will totally need this.
Unfortunately i already asked for a new bluetooth enabled multimeter.
from esp32-cam-demo.
@igrr - yes, you said about using interrupts before.
@Oitzu - thanks! I had doubts after reply by @igrr 😉
from esp32-cam-demo.
@krzychb my guess was that the first buffer is directly filled after the vsync is polled and the delay(2).
But that doesn't make much sense either, after looking again at the code.
Is line 0 actually discarded?
from esp32-cam-demo.
@igrr great explanation. :)
On which condition is the i2s interrupt called? I conclude as soon as a counter reached I2S_RX_EOF_NUM?
If yes: Is there a maximum of dma buffer i can set and can i abort the i2s before the buffer is completly full?
I'm asking because i'm still looking envy at the onboard jpeg mode of the ov2640, which would allow a full size, color picture to load into ram.
As far as i understand a jpeg frame behaves like one line of pixels without a certain length (due to compression), and i would need to abort the i2s at the end, before the dma buffer is completly full, based on pin signal behaviour.
from esp32-cam-demo.
There is a bunch of interrupt sources within I2S, they can be selected by setting bits in I2S_INT_ENA_REG(0)
. Right now it uses I2S_IN_DONE_INT_ENA_S
, so the interrupt will be generated when the correct number of samples is received. I know that the I2S can time out (there is an I2S_RX_HUNG
interrupt for that case), but i don't know how to set the timeout yet. I'll find out and post back. I also need to see the waveforms for JPEG case and check with hardware folks if this is something that I2S can support (although this is not something directly related to this specific issue).
from esp32-cam-demo.
@krzychb kind of leaves out the waiting on the falling VSYNC edge between camera run and the actual i2s start.
from esp32-cam-demo.
@Oitzu, thank you for review and finding this one!
I will correct it. I am really grateful that @igrr shed extra light on I2S internals. This figure is my starting point to review how to fix the skew as I still not get how it happens.
I was wondering why we engage in controlling whole I2S process for each snapshot instead of leaving it running continuously and filling in DNA buffer 0 and 1?
Then to take a snapshot I would wait for failing edge of VSYNC and control only the line_filter_task
using the semaphore data_ready
.
Also what about using failing edge of HREF to trigger interrupt instead of I2S_IN_DONE_INT_ENA_S
?
from esp32-cam-demo.
I am really grateful that @igrr shed extra light on I2S internals.
i second that. 👍
This figure is my starting point to review how to fix the skew as I still not get how it happens.
@igrr mentioned that it may be due to the sloppy vsync catching so the offending code would be:
ESP_LOGD(TAG, "Waiting for VSYNC");
while(gpio_get_level(s_config.pin_vsync) != 0);
while(gpio_get_level(s_config.pin_vsync) == 0);
ESP_LOGD(TAG, "Got VSYNC");
But that also confuses me further, because @igrr said VSYNC is inverted by cam registers so looking at the timing diagram, it would make more sense to me to catch the rising edge. But maybe he decided on the falling edge to catch the VSYNC after the previous frame is done.
This would indeed be better if we would attach a gpio interrupt to it. But i don't know if this would in any way offend the already set gpio matrix.
I was wondering why we engage in controlling whole I2S process for each snapshot instead of leaving it running continuously and filling in DNA buffer 0 and 1?
Then to take a snapshot I would wait for failing edge of VSYNC and control only the line_filter_task using the semaphore data_ready.
I think there is no special reaon for that, just demo-code stuff and of course you would capture frames in the background that you never could use.
Also what about using failing edge of HREF to trigger interrupt instead of I2S_IN_DONE_INT_ENA_S?
A good reason for that, that i can think of, is that you don't run accidentaly in a dma buffer overflow. This is actually pretty near to the method dcmi does it.
from esp32-cam-demo.
Demo code does a separate transfer for each line just because it was easier to debug and figure out things that didn't work. I think we could use two buffers pointing at each other, so that DMA would automatically advance to the next buffer once one is filled. But in that case we probably need to set different RX_EOF_NUM value (full frame size?), and use different interrupt status bit to check that one buffer has been filled. I'll take a look at this if i get some time between other things next week.
from esp32-cam-demo.
@igrr Could we simply config the size of DMA to receive one full frame (nlines x npixels_per_line)
data ? I see the timing diagram on mt9v034
, it has exactly npixels_per_line
PCLK
cycles when HREF
is high.
from esp32-cam-demo.
That would require 4x current framebuffer size, as line_filter_task currently extracts one byte out of every 4 bytes.
from esp32-cam-demo.
OK, I see that.
I used xilinx zynq before and remember that xilinx has one special type of DMA called VDMA, it spawns nlines
copies of DMA and the size of each DMA is npixels
, pointing at different locations of framebuffer.
I am new to ARM coding and esp-idf
might support this type of DMA for image capturing.
from esp32-cam-demo.
Couldn't we just replace the sloppy pull with:
gpio_set_intr_type(s_config.pin_vsync, GPIO_INTR_POSEDGE);
gpio_intr_enable(s_config.pin_vsync);
gpio_isr_register(23, gpioCallback, (void *)TAG);
and do:
void gpioCallback(void* arg)
{
if(!i2s_running)
{
cur_buffer = 0;
line_count = 0;
isr_count = 0;
i2s_running = true;
i2s_fill_buf(cur_buffer);
}
else
{
gpio_intr_disable(s_config.pin_vsync)
i2s_running = false;
i2s_stop();
}
}
?
from esp32-cam-demo.
To clarify after thinking about it: I mean just the concept point of view.
The first intr maybe should just detect just rising edge and reconfigured to falling edge in the interrupt to avoid false detection.
from esp32-cam-demo.
I will get to changing the sloppy pull of GPIO to interrupt. What I do not get is why sloppy VSYNC catching (I assume not at the right time) would cause wavy vertical edge shown in #11 (comment)
I would expect the same horizontal offset for each line without creeping for first lines and then stabilising.
BTW I got the the above pattern for XCLK @40HMz.
Now, following information about bit 1 in COM10 register, "VSYNC negative" by @igrr, I have updated camera setting in COM10 from:
{COM10, (1 << 1) | (1 << 5)},
to
{COM10, (COM10_VSYNC_NEG | COM10_PCLK_REV)},
This is to maintain negation of VSYNC and to change PCLK setting - see ov7725_regs.h for clarification.
I have also reduced XCLK to 10Mhz.
EDIT: After such changes the horizontal offset on 40x40 pixels cropped from the upper left corner of frame buffer looks as follows:
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
The offset is still creeping for first couple of lines but at least is sharp / without jumping by two pixels every second line.
from esp32-cam-demo.
I would expect the same horizontal offset for each line without creeping for first lines and then stabilising.
I was also expecting that. My guess was that it syncs up with href after a few lines.
Why do you want to reverse PCLK?
from esp32-cam-demo.
Why do you want to reverse PCLK?
I do not want to reverse 😄
There is no documentation for I2S, I am just guessing what may be the issue and poking settings.
from esp32-cam-demo.
Ah i see desperate times poking bits. I do not even understand what reversing PCLK do, inverting the PCLK signal? This could help or, it could happen that it trys to read the bus in a undefined state between 2 bytes, as far as the timing diagram says.
My bet was on COM10_PCLK_MASK maybe helping.
from esp32-cam-demo.
...it trys to read the bus in a undefined state between 2 pixels, as far as the timing diagram says.
This is my guess. I do not have documentation to say on what edge of PCLK I2S reads the bus / how it is configured now.
My bet was on COM10_PCLK_MASK maybe helping.
Setting COM10_PCLK_MASK makes PCLK as a logical AND of HREF & XCLK.
As I2C that does not sample data when HREF is low, such masking should not change anything.
To double check I have applied:
{COM10, (COM10_VSYNC_NEG | COM10_PCLK_REV | COM10_PCLK_MASK)},
I can not see any difference.
from esp32-cam-demo.
This is my guess. I do not have documentation to say on what edge of PCLK I2S reads the bus / how it is configured now.
Well, at I2S it would sample on the rising edge of CLK while wordselect (configured to be PCLK) is high. But i can't quite figure out how CLK is configured. The new code suggests that somehow "HSYNC/VSYNC/HREF" with a clock divider is used to get the sampling rate.
Cryptic register settings are cryptic. :D
such masking should not change anything.
Also we shouldn't have skew ¯ \ (ツ)/¯
from esp32-cam-demo.
The new code suggests that somehow "HSYNC/VSYNC/HREF" with a clock divider is used to get the sampling rate.
I guess you mean lines 358-361?
- Basing on line 333, HSYNC is set permanently HIGH - ref. #6 (comment)
- VSYNC is LOW only for the period of four lines (4 x 576 x XCLK) and then is HIGH during rest of the time
- Sampling should start 24 lines (24 x 576 x XCLK) after VSYNC goes HIGH
This looks like plenty of time, also for a lousy VSYNC detection.
I have noticed that the first two lines of the very first grabbed frame look OK. Second frame is skew from the beginning.
D (1366) camera: Allocating DMA buffer #0, size=1280
D (1366) camera: Allocating DMA buffer #1, size=1280
D (1376) camera: Init done
D (1376) camera: Waiting for VSYNC
D (1406) camera: Got VSYNC
D (1406) camera: Waiting for frame
D (1436) camera: Frame done
D (1436) camera_demo: Done
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
D (2716) camera: Waiting for VSYNC
D (2716) camera: Got VSYNC
D (2716) camera: Waiting for frame
D (2746) camera: Frame done
D (2746) camera_demo: Done
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
from esp32-cam-demo.
I have also checked espressif/esp-idf#152
Changing DR_REG_I2S_BASE
(and DR_REG_I2S1_BASE
just in case) according to errata made the skew two times bigger:
D (1355) camera: Allocating DMA buffer #0, size=1280
D (1355) camera: Allocating DMA buffer #1, size=1280
D (1365) camera: Init done
D (1365) camera: Waiting for VSYNC
D (1395) camera: Got VSYNC
D (1395) camera: Waiting for frame
D (1425) camera: Frame done
D (1425) camera_demo: Done
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
14141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
from esp32-cam-demo.
I guess you mean lines 358-361?
Also the lines inbefore configure a parallel mode (on a serial interface?) and a camera mode which isn't excatly clear what it cause.
Sampling should start 24 lines
Isn't it 22 lines? But yeah, should be plenty of time.
Hm... changing the base-adress maybe has some not wanted side effects?
Could you print out the first 3-4 complete lines?
from esp32-cam-demo.
Also maybe even a raw output would give maybe new insights what is going wrong.
from esp32-cam-demo.
Thank you for being with me!
Here is the code for first four lines.
for (int ih = 0; ih < 4; ih++){
for (int iw = 0; iw < s_fb_w; iw++){
uint8_t px = (s_fb[iw + (ih * s_fb_w)]);
printf("%02x", px);
}
printf("\n");
}
Below are first two captured frames / first four lines each.
D (1092) camera: Allocating DMA buffer #0, size=1280
D (1092) camera: Allocating DMA buffer #1, size=1280
D (1092) camera: Init done
D (1102) camera: Waiting for VSYNC
D (1132) camera: Got VSYNC
D (1132) camera: Waiting for frame
D (1162) camera: Frame done
D (1162) camera_demo: Done
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d14141414141414141414141414141414141414141414141414141414141414141414141414141414
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d1414141414141414141414141414141414141414141414141414141414141414141414149fc54119
14141414fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d141414141414141414141414141414141414141414141414141414141414141414141414
14141414fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d14141414141414141414141414141414141414141414141414141414141414149fc54119
D (2382) camera: Waiting for VSYNC
D (2382) camera: Got VSYNC
D (2382) camera: Waiting for frame
D (2412) camera: Frame done
D (2412) camera_demo: Done
14141414fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d141414141414141414141414141414141414141414141414141414141414141414141414
14141414fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d141414141414141414141414141414141414141414141414141414141414141414141414
14141414fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d141414141414141414141414141414141414141414141414141414141414141414141414
14141414fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d141414141414141414141414141414141414141414141414141414141414141414141414
from esp32-cam-demo.
@krzychb i also want this to work, despite having my camera not yet (but looking every 8 hours into my postbox) :D
The data suggests that the previous line leaks into the next line. That could be a memory corruption, or maybe a speed problem?
Changing DR_REG_I2S_BASE (and DR_REG_I2S1_BASE just in case) according to errata made the skew two times bigger
I actually read in the forum that the "changed addresses" are slower as the "original addresses" so that the "rapidly write" problem don't occur. Maybe this could be an indicator to an speed problem?
For a memory problem speaks: The first 2 lines on your output in the first frame seem to be okay. At this point none of the dma buffers were filled in before. At the third line, both had been used.
On the second frame both had been used before obviously.
from esp32-cam-demo.
Maybe this could be an indicator to an speed problem?
This is a good point! I believe the speed problem shows up by shaky offset and is visible in two cases:
- When XCLK is increased to 40MHz - case #11 (comment)
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
131313131313131313ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
1313131313131380ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
- After changing
DR_REG_I2S_BASE
because the "changed addresses" are slower as the "original addresses" - case #11 (comment)
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
1414141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffff
141414141414141414141414141414ffffffffffffffffffffffffffffffffffffffffffffffffff
none of the dma buffers were filled in before. At the third line, both had been used.
Another great observation with two dma buffers!
The tail of line somehow winds up to the beginning of next line. I was thinking that maybe I2S FIFO is not fully purged to the dma buffer. The leftover adds up to the next line. But then the offset would creep to the right every two lines.
Good luck with quickly getting your camera. I have ordered mine from the UK. Estimated delivery was 10 days and it arrived exactly after 10 days.
from esp32-cam-demo.
The hard question is: How to debug this?
A good starting point may be to check the dma buffers. Possible printing out the the first byte of the currently used dma buffer after it filled the fb?
Just to see if it still looks okay at this point if its still okay.
from esp32-cam-demo.
save .bmp
file remotely at the PC, and analyze its contents using python.
from esp32-cam-demo.
@krzychb the operation diagram is really cool and should definitely be added to the readme.
from esp32-cam-demo.
@igrr it is fantastic you resolved the issue with configuration. Currently I am travelling and I will do my testing this Thursday. Later I will also update the readme.
from esp32-cam-demo.
Test pattern from OV7725 is now shown nice and square:
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%********** +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%********** +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%********** +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%********** +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%********** +++++++++==========-:::::::::
@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%********** +++++++++==========-:::::::::
If anybody is curious where the horizontal space in the middle comes from, here is the whole first line of the test pattern:
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2d9c6bdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdbdff9a12979797979797979797979797979797979797979797979797979797979797979797979797978d7b72727272727272727272727272727272727272727272727272727272727272727272727272727b7550393939393939393939393939393939393939393939393939393939393939393939393939392f1d14141414141414141414141414141414141414141414141414141414141414141414141414141414
from esp32-cam-demo.
Related Issues (20)
- camera probe failed (0x20001) with OV7670 HOT 7
- OV7725 in esp32 HOT 1
- *** No rule to make target 'C:/........./sccb.c', needed by 'sccb.o' Stop. HOT 1
- OV2640 jpeg image with pixelated edges HOT 2
- Camera Issue
- The make is failing HOT 3
- IO Expander HOT 1
- 0v7725 rgb565 HOT 1
- Unable to build from source - esp_http_server.h problem HOT 1
- How to save captured images to computer through wifi?? HOT 1
- Red Board OV2640 - solved HOT 5
- Download to computer
- Newbie of Ai Thinker with OV2640 : Camera probe failed with error 0x20001
- dear all, just clone esp-who, that one works plus it uses the latest driver for cameras
- Sometimes a black screen HOT 1
- How to read individual pixel values in a frame or image. HOT 1
- OV7725 has different pins than those mentioned in README.md
- Need pin mapping for ov7725 esp-cam module
- Do you have an image of the ov2640 Color Bar?
- [-Werror=unused-const-variable=]
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from esp32-cam-demo.