Skip to content

Commit 428005e

Browse files
committed
add webserial
1 parent dbe5fbf commit 428005e

File tree

3 files changed

+120
-165
lines changed

3 files changed

+120
-165
lines changed
Lines changed: 120 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: GIGA R1 Camera Guide
33
description: Learn about the GIGA R1 WiFi's camera connector, and how to use existing examples.
4-
tags: [ArduCAM, Camera, Processing]
4+
tags: [ArduCAM, Camera, WebSerial]
55
author: Karl Söderby
66
hardware:
77
- hardware/10.mega/boards/giga-r1-wifi
@@ -16,21 +16,30 @@ The GIGA R1 has a dedicated camera connector that allows certain camera modules
1616
In this guide, we will explore the following:
1717

1818
- Where the camera connector is located.
19-
- What cameras are compatible.
20-
- What library to use.
21-
- How to setup a camera stream to a processing application.
19+
- What cameras are compatible?
20+
- What library to use?
21+
- How to set up a camera stream to a browser using webserial.
2222

2323
## Hardware & Software Needed
2424

2525
To follow and use the examples provided in this guide, you will need an [Arduino GIGA R1 WiFi](/hardware/giga-r1-wifi)
2626

2727
You will also need the following software:
28+
2829
- [Arduino IDE](https://www.arduino.cc/en/software) (any version).
29-
- [Processing](https://processing.org/download) (for displaying camera feed).
30+
- [Webserial](https://github.com/arduino/ArduinoCore-mbed/tree/main/libraries/Camera/extras/WebSerialCamera) (for displaying camera feed).
31+
32+
To run the Webserial locally go to:
33+
34+
```
35+
C:\Users\<UserName>\AppData\Local\Arduino15\packages\arduino\hardware\mbed_giga\4.1.3\libraries\Camera\extras\WebSerialCamera
36+
```
37+
38+
and open the `.index`. We suggest using the Chrome™ browser.
3039

3140
## Supported Cameras
3241

33-
The GIGA R1 currently supports the following cameras, via the [Camera](https://github.com/arduino/ArduinoCore-mbed/tree/master/libraries/Camera) library that is bundled with the [Arduino Mbed PS GIGA Board Package](https://github.com/arduino/ArduinoCore-mbed):
42+
The GIGA R1 currently supports the following cameras, via the [Camera](https://github.com/arduino/ArduinoCore-mbed/tree/master/libraries/Camera) library that is bundled with the [Arduino Mbed Core](https://github.com/arduino/ArduinoCore-mbed):
3443

3544
- **OV7670** and **OV7675**
3645
- **GC2145**
@@ -41,13 +50,13 @@ The GIGA R1 currently supports the following cameras, via the [Camera](https://g
4150

4251
![Camera Connector on GIGA R1](assets/camera-connector-pins.png)
4352

44-
The 20 pin camera connector onboard the GIGA R1 is designed to be directly compatible with some breakout boards from ArduCam.
53+
The 20 pin camera connector onboard the GIGA R1 is designed to be directly compatible with some breakout boards from ArduCam.
4554

4655
This allows you to simply connect the camera module directly to the board, without making any additional circuit.
4756

4857
![Camera Module Connected](assets/camera-connector-photo.png)
4958

50-
Some of the 20 pin connector breakout boards from ArduCam can be found [here](https://www.arducam.com/product-category/stm32-camera-modules-dcmi-and-spi/).
59+
Some of the 20 pin connector breakout boards from ArduCam can be found [here](https://www.arducam.com/product-category/embedded-camera-module/camera-breakout-board/).
5160

5261
The complete pin map can be found below:
5362

@@ -70,13 +79,9 @@ You can also view the schematic for this connector in more detail just below. Th
7079

7180
![Schematic for Camera Connector (J6).](assets/camera-schematic.png)
7281

73-
## Raw Bytes Over Serial (Processing)
74-
75-
![Live view of the camera.](assets/processing-example.png)
82+
## Raw Bytes Over Serial
7683

77-
This example allows you to stream the sensor data from your camera to a Processing application, using serial over USB. This will allow you to see the image directly in your computer.
78-
79-
***This example requires a version of [Processing](https://processing.org/download) on your machine.***
84+
This example allows you to stream the sensor data from your camera to a web interface, using serial over USB. This will allow you to see the image directly in your browser.
8085

8186
### Step 1: Arduino
8287

@@ -93,14 +98,19 @@ This sketch is also available in the Arduino IDE via **Examples > Camera > Camer
9398
Camera cam(galaxyCore);
9499
#define IMAGE_MODE CAMERA_RGB565
95100
#elif defined(ARDUINO_PORTENTA_H7_M7)
101+
// uncomment the correct camera in use
96102
#include "hm0360.h"
97103
HM0360 himax;
104+
// #include "himax.h";
105+
// HM01B0 himax;
98106
Camera cam(himax);
99107
#define IMAGE_MODE CAMERA_GRAYSCALE
100108
#elif defined(ARDUINO_GIGA)
101-
#include "ov7670.h"
102-
OV7670 ov7670;
103-
Camera cam(ov7670);
109+
#include "ov767x.h"
110+
// uncomment the correct camera in use
111+
OV7670 ov767x;
112+
// OV7675 ov767x;
113+
Camera cam(ov767x);
104114
#define IMAGE_MODE CAMERA_RGB565
105115
#else
106116
#error "This board is unsupported."
@@ -110,188 +120,133 @@ This sketch is also available in the Arduino IDE via **Examples > Camera > Camer
110120
Other buffer instantiation options:
111121
FrameBuffer fb(0x30000000);
112122
FrameBuffer fb(320,240,2);
113-
*/
114-
FrameBuffer fb;
115123
116-
unsigned long lastUpdate = 0;
124+
If resolution higher than 320x240 is required, please use external RAM via
125+
#include "SDRAM.h"
126+
FrameBuffer fb(SDRAM_START_ADDRESS);
127+
...
128+
// and adding in setup()
129+
SDRAM.begin();
130+
*/
131+
constexpr uint16_t CHUNK_SIZE = 512; // Size of chunks in bytes
132+
constexpr uint8_t RESOLUTION = CAMERA_R320x240; // CAMERA_R160x120
133+
constexpr uint8_t CONFIG_SEND_REQUEST = 2;
134+
constexpr uint8_t IMAGE_SEND_REQUEST = 1;
117135
136+
uint8_t START_SEQUENCE[4] = { 0xfa, 0xce, 0xfe, 0xed };
137+
uint8_t STOP_SEQUENCE[4] = { 0xda, 0xbb, 0xad, 0x00 };
138+
FrameBuffer fb;
118139
119-
void blinkLED(uint32_t count = 0xFFFFFFFF)
120-
{
121-
pinMode(LED_BUILTIN, OUTPUT);
140+
/**
141+
* Blinks the LED a specified number of times.
142+
* @param ledPin The pin number of the LED.
143+
* @param count The number of times to blink the LED. Default is 0xFFFFFFFF.
144+
*/
145+
void blinkLED(int ledPin, uint32_t count = 0xFFFFFFFF) {
122146
while (count--) {
123-
digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level)
147+
digitalWrite(ledPin, LOW); // turn the LED on (HIGH is the voltage level)
124148
delay(50); // wait for a second
125-
digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW
149+
digitalWrite(ledPin, HIGH); // turn the LED off by making the voltage LOW
126150
delay(50); // wait for a second
127151
}
128152
}
129153
130154
void setup() {
155+
pinMode(LED_BUILTIN, OUTPUT);
156+
pinMode(LEDR, OUTPUT);
157+
digitalWrite(LED_BUILTIN, HIGH);
158+
digitalWrite(LEDR, HIGH);
159+
131160
// Init the cam QVGA, 30FPS
132-
if (!cam.begin(CAMERA_R320x240, IMAGE_MODE, 30)) {
133-
blinkLED();
161+
if (!cam.begin(RESOLUTION, IMAGE_MODE, 30)) {
162+
blinkLED(LEDR);
134163
}
135164
136-
blinkLED(5);
165+
blinkLED(LED_BUILTIN, 5);
137166
}
138167
139-
void loop() {
140-
if(!Serial) {
141-
Serial.begin(921600);
142-
while(!Serial);
143-
}
144-
145-
// Time out after 2 seconds and send new data
146-
bool timeoutDetected = millis() - lastUpdate > 2000;
147-
148-
// Wait for sync byte.
149-
if(!timeoutDetected && Serial.read() != 1) return;
168+
/**
169+
* Sends a chunk of data over a serial connection.
170+
*
171+
* @param buffer The buffer containing the data to be sent.
172+
* @param bufferSize The size of the buffer.
173+
*/
174+
void sendChunk(uint8_t* buffer, size_t bufferSize){
175+
Serial.write(buffer, bufferSize);
176+
Serial.flush();
177+
delay(1); // Optional: Add a small delay to allow the receiver to process the chunk
178+
}
150179
151-
lastUpdate = millis();
152-
180+
/**
181+
* Sends a frame of camera image data over a serial connection.
182+
*/
183+
void sendFrame(){
153184
// Grab frame and write to serial
154185
if (cam.grabFrame(fb, 3000) == 0) {
155-
Serial.write(fb.getBuffer(), cam.frameSize());
156-
} else {
157-
blinkLED(20);
158-
}
159-
}
160-
161-
```
162-
163-
### Step 2: Processing
186+
byte* buffer = fb.getBuffer();
187+
size_t bufferSize = cam.frameSize();
188+
digitalWrite(LED_BUILTIN, LOW);
164189
165-
The following Processing sketch will launch a Java app that allows you to view the camera feed. As data is streamed via serial, make sure you close the Serial Monitor during this process, else it will not work.
190+
sendChunk(START_SEQUENCE, sizeof(START_SEQUENCE));
166191
167-
***Important! Make sure to replace the following line in the code below: `/dev/cu.usbmodem14301`, with the name of your port.***
192+
// Split buffer into chunks
193+
for(size_t i = 0; i < bufferSize; i += CHUNK_SIZE) {
194+
size_t chunkSize = min(bufferSize - i, CHUNK_SIZE);
195+
sendChunk(buffer + i, chunkSize);
196+
}
168197
169-
Click on the **"PLAY"** button to initialize the app.
198+
sendChunk(STOP_SEQUENCE, sizeof(STOP_SEQUENCE));
170199
171-
```cpp
172-
/*
173-
Use with the Examples -> CameraCaptureRawBytes Arduino sketch.
174-
This example code is in the public domain.
175-
*/
176-
177-
import processing.serial.*;
178-
import java.nio.ByteBuffer;
179-
import java.nio.ByteOrder;
180-
181-
Serial myPort;
182-
183-
// must match resolution used in the Arduino sketch
184-
final int cameraWidth = 320;
185-
final int cameraHeight = 240;
186-
187-
// Must match the image mode in the Arduino sketch
188-
final boolean useGrayScale = true;
200+
digitalWrite(LED_BUILTIN, HIGH);
201+
} else {
202+
blinkLED(20);
203+
}
204+
}
189205
190-
// Must match the baud rate in the Arduino sketch
191-
final int baudRate = 921600;
206+
/**
207+
* Sends the camera configuration over a serial connection.
208+
* This is used to configure the web app to display the image correctly.
209+
*/
210+
void sendCameraConfig(){
211+
Serial.write(IMAGE_MODE);
212+
Serial.write(RESOLUTION);
213+
Serial.flush();
214+
delay(1);
215+
}
192216
193-
final int cameraBytesPerPixel = useGrayScale ? 1 : 2;
194-
final int cameraPixelCount = cameraWidth * cameraHeight;
195-
final int bytesPerFrame = cameraPixelCount * cameraBytesPerPixel;
196-
final int timeout = int((bytesPerFrame / float(baudRate / 10)) * 1000 * 2); // Twice the transfer rate
217+
void loop() {
218+
if(!Serial) {
219+
Serial.begin(115200);
220+
while(!Serial);
221+
}
197222
198-
PImage myImage;
199-
byte[] frameBuffer = new byte[bytesPerFrame];
200-
int lastUpdate = 0;
201-
boolean shouldRedraw = false;
223+
if(!Serial.available()) return;
202224
203-
void setup() {
204-
size(640, 480);
225+
byte request = Serial.read();
205226
206-
// If you have only ONE serial port active you may use this:
207-
//myPort = new Serial(this, Serial.list()[0], baudRate); // if you have only ONE serial port active
227+
switch(request){
228+
case IMAGE_SEND_REQUEST:
229+
sendFrame();
230+
break;
231+
case CONFIG_SEND_REQUEST:
232+
sendCameraConfig();
233+
break;
234+
}
208235
209-
// If you know the serial port name
210-
//myPort = new Serial(this, "COM5", baudRate); // Windows
211-
//myPort = new Serial(this, "/dev/ttyACM0", baudRate); // Linux
212-
myPort = new Serial(this, "/dev/cu.usbmodem14301", baudRate); // Mac
236+
}
213237
214-
// wait for a full frame of bytes
215-
myPort.buffer(bytesPerFrame);
238+
```
216239

217-
myImage = createImage(cameraWidth, cameraHeight, ALPHA);
218-
219-
// Let the Arduino sketch know we're ready to receive data
220-
myPort.write(1);
221-
}
240+
### Step 2: Web Serial
222241

223-
void draw() {
224-
// Time out after a few seconds and ask for new data
225-
if(millis() - lastUpdate > timeout) {
226-
println("Connection timed out.");
227-
myPort.clear();
228-
myPort.write(1);
229-
}
230-
231-
if(shouldRedraw){
232-
PImage img = myImage.copy();
233-
img.resize(640, 480);
234-
image(img, 0, 0);
235-
shouldRedraw = false;
236-
}
237-
}
242+
Open the Webserial Interface which allows you to view the camera feed. As data is streamed via serial, make sure you close the Serial Monitor during this process, else it will not work.
238243

239-
int[] convertRGB565ToRGB888(short pixelValue){
240-
//RGB565
241-
int r = (pixelValue >> (6+5)) & 0x01F;
242-
int g = (pixelValue >> 5) & 0x03F;
243-
int b = (pixelValue) & 0x01F;
244-
//RGB888 - amplify
245-
r <<= 3;
246-
g <<= 2;
247-
b <<= 3;
248-
return new int[]{r,g,b};
249-
}
244+
Press on **Connect** and select the correct port.
250245

251-
void serialEvent(Serial myPort) {
252-
lastUpdate = millis();
253-
254-
// read the received bytes
255-
myPort.readBytes(frameBuffer);
256-
257-
// Access raw bytes via byte buffer
258-
ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
259-
260-
// Ensure proper endianness of the data for > 8 bit values.
261-
// The 1 byte bb.get() function will always return the bytes in the correct order.
262-
bb.order(ByteOrder.BIG_ENDIAN);
263-
264-
int i = 0;
265-
266-
while (bb.hasRemaining()) {
267-
if(useGrayScale){
268-
// read 8-bit pixel data
269-
byte pixelValue = bb.get();
270-
271-
// set pixel color
272-
myImage.pixels[i++] = color(Byte.toUnsignedInt(pixelValue));
273-
} else {
274-
// read 16-bit pixel data
275-
int[] rgbValues = convertRGB565ToRGB888(bb.getShort());
276-
277-
// set pixel RGB color
278-
myImage.pixels[i++] = color(rgbValues[0], rgbValues[1], rgbValues[2]);
279-
}
280-
}
281-
282-
myImage.updatePixels();
283-
284-
// Ensures that the new image data is drawn in the next draw loop
285-
shouldRedraw = true;
286-
287-
// Let the Arduino sketch know we received all pixels
288-
// and are ready for the next frame
289-
myPort.write(1);
290-
}
291-
```
246+
![Select Port](./assets/webSerial_example_connect.png)
292247

293-
If all goes well, you should now be able to see the camera feed.
248+
You should now be able to see the camera feed.
294249

295250
## Summary
296251

297-
In this article, we learned a bit more about the camera connector on board the GIGA R1 board, how it is connected to the STM32H747XI microcontroller, and a simple example on how to connect an inexpensive OV7675 camera module to a Processing application.
252+
In this article, we learned a bit more about the camera connector on board the GIGA R1 board, how it is connected to the STM32H747XI microcontroller, and a simple example on how to connect an inexpensive OV7675 camera module through web serial.

0 commit comments

Comments
 (0)