Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 339 additions & 0 deletions LICENSE.txt

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
# arduino-library
# Harvard_TinyMLx Arduino Library

Source code and examples for using and testing your Tiny Machine Learning Kit and Shield.

This library also includes a modified verison of the 0.0.2 version of the OV767X Library for Arduino (Copyright (c) 2020 Arduino SA) which is based on https://www.kernel.org[Linux Kernel's] V4L2 driver for OmniVision OV7670 cameras - which was created by Jonathan Corbet.

== License ==

Copyright (c) 2021 TinyMLx. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
54 changes: 10 additions & 44 deletions examples/test_camera/test_camera.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,14 @@
Harvard University
tinyMLx - OV7675 Camera Test

Requires the the Arduino_OV767X library
*/

#include <Arduino_OV767X.h>

#define BUTTON_PIN 13
#include <TinyMLShield.h>

bool commandRecv = false; // flag used for indicating receipt of commands from serial port
bool liveFlag = false; // flag as true to live stream raw camera bytes, set as false to take single images on command
bool captureFlag = false;

// Variables for button debouncing
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
bool lastButtonState = HIGH;
bool buttonState;

// Image buffer;
byte image[176 * 144 * 2]; // QCIF: 176x144 x 2 bytes per pixel (RGB565)
int bytesPerFrame;
Expand All @@ -28,12 +19,10 @@ void setup() {
Serial.begin(9600);
while (!Serial);

pinMode(BUTTON_PIN, OUTPUT);
digitalWrite(BUTTON_PIN, HIGH);
nrf_gpio_cfg_out_with_input(digitalPinToPinName(BUTTON_PIN));
initializeShield();

// Initialize camera
if (!Camera.begin(QCIF, RGB565, 1)) {
// Initialize the OV7675 camera
if (!Camera.begin(QCIF, RGB565, 1, OV7675)) {
Serial.println("Failed to initialize camera");
while (1);
}
Expand All @@ -50,28 +39,15 @@ void loop() {
int i = 0;
String command;

bool buttonRead = nrf_gpio_pin_read(digitalPinToPinName(BUTTON_PIN));

if (buttonRead != lastButtonState) {
lastDebounceTime = millis();
}

if (millis() - lastDebounceTime >= debounceDelay) {
if (buttonRead != buttonState) {
buttonState = buttonRead;

if (!buttonState) {
if (!liveFlag) {
if (!captureFlag) {
captureFlag = true;
}
}
bool clicked = readShieldButton();
if (clicked) {
if (!liveFlag) {
if (!captureFlag) {
captureFlag = true;
}
}
}

lastButtonState = buttonRead;

// Read incoming commands from serial monitor
while (Serial.available()) {
char c = Serial.read();
Expand Down Expand Up @@ -132,14 +108,4 @@ void loop() {
Serial.println();
}
}
}

void nrf_gpio_cfg_out_with_input(uint32_t pin_number) {
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_PULLUP,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
}
65 changes: 27 additions & 38 deletions examples/test_microphone/test_microphone.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,21 @@
*/

#include <PDM.h>

#define BUTTON_PIN 13
#include <TinyMLShield.h>

// PDM buffer
short sampleBuffer[256];
volatile int samplesRead;

// Variables for button debouncing
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;
bool lastButtonState = HIGH;
bool buttonState;

bool record = false;
bool commandRecv = false;

void setup() {
Serial.begin(9600);
while (!Serial);

pinMode(BUTTON_PIN, OUTPUT);
digitalWrite(BUTTON_PIN, HIGH);
nrf_gpio_cfg_out_with_input(digitalPinToPinName(BUTTON_PIN));
// Initialize the TinyML Shield
initializeShield();

PDM.onReceive(onPDMdata);
// Initialize PDM microphone in mono mode with 16 kHz sample rate
Expand All @@ -36,38 +29,44 @@ void setup() {
}

Serial.println("Welcome to the microphone test for the built-in microphone on the Nano 33 BLE Sense\n");
Serial.println("Use the on-shield button to start and stop an audio recording");
Serial.println("Use the on-shield button or send the command 'click' to start and stop an audio recording");
Serial.println("Open the Serial Plotter to view the corresponding waveform");
}

void loop() {
bool buttonRead = nrf_gpio_pin_read(digitalPinToPinName(BUTTON_PIN));

if (buttonRead != lastButtonState) {
lastDebounceTime = millis();
// see if the button is pressed and turn off or on recording accordingly
bool clicked = readShieldButton();
if (clicked){
record = !record;
}

if (millis() - lastDebounceTime >= debounceDelay) {
if (buttonRead != buttonState) {
buttonState = buttonRead;

if (!buttonState) {
record = !record;
}

// see if a command was sent over the serial monitor and record it if so
String command;
while (Serial.available()) {
char c = Serial.read();
if ((c != '\n') && (c != '\r')) {
command.concat(c);
}
else if (c == '\r') {
commandRecv = true;
command.toLowerCase();
}
}

lastButtonState = buttonRead;

if (samplesRead) {
// parse the command if applicable
if (commandRecv && command == "click") {
commandRecv = false;
record = !record;
}

// display the audio if applicable
if (samplesRead) {
// print samples to serial plotter
if (record) {
for (int i = 0; i < samplesRead; i++) {
Serial.println(sampleBuffer[i]);
}
}

// clear read count
samplesRead = 0;
}
Expand All @@ -82,13 +81,3 @@ void onPDMdata() {

samplesRead = bytesAvailable / 2;
}

void nrf_gpio_cfg_out_with_input(uint32_t pin_number) {
nrf_gpio_cfg(
pin_number,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_CONNECT,
NRF_GPIO_PIN_PULLUP,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
}
92 changes: 92 additions & 0 deletions extras/CameraCapture/CameraCapture.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
OV767X - Camera Test Pattern

This sketch waits for the letter 'c' on the Serial Monitor,
it then reads a frame from the OmniVision OV7670 camera and
prints the data to the Serial Monitor as a hex string.

The website https://rawpixels.net - can be used the visualize the data:
width: 176
height: 144
RGB565
Little Endian

Circuit:
- Arduino Nano 33 BLE board
- OV7670 camera module:
- 3.3 connected to 3.3
- GND connected GND
- SIOC connected to A5
- SIOD connected to A4
- VSYNC connected to 8
- HREF connected to A1
- PCLK connected to A0
- XCLK connected to 9
- D7 connected to 4
- D6 connected to 6
- D5 connected to 5
- D4 connected to 3
- D3 connected to 2
- D2 connected to 0 / RX
- D1 connected to 1 / TX
- D0 connected to 10

This example code is in the public domain.
*/

#include <Arduino_OV767X.h>

unsigned short pixels[176 * 144]; // QCIF: 176x144 X 2 bytes per pixel (RGB565)

void setup() {
Serial.begin(9600);
while (!Serial);

Serial.println("OV767X Camera Capture");
Serial.println();

if (!Camera.begin(QCIF, RGB565, 1, OV7675)) {
Serial.println("Failed to initialize camera!");
while (1);
}

Serial.println("Camera settings:");
Serial.print("\twidth = ");
Serial.println(Camera.width());
Serial.print("\theight = ");
Serial.println(Camera.height());
Serial.print("\tbits per pixel = ");
Serial.println(Camera.bitsPerPixel());
Serial.println();

Serial.println("Send the 'c' character to read a frame ...");
Serial.println();
}

void loop() {
if (Serial.read() == 'c') {
Serial.println("Reading frame");
Serial.println();
Camera.readFrame(pixels);

int numPixels = Camera.width() * Camera.height();

for (int i = 0; i < numPixels; i++) {
unsigned short p = pixels[i];

if (p < 0x1000) {
Serial.print('0');
}

if (p < 0x0100) {
Serial.print('0');
}

if (p < 0x0010) {
Serial.print('0');
}

Serial.print(p, HEX);
}
}
}
36 changes: 36 additions & 0 deletions extras/CameraCaptureRawBytes/CameraCaptureRawBytes.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
OV767X - Camera Capture Raw Bytes

This sketch reads a frame from the OmniVision OV7675 camera
and writes the bytes to the Serial port. Use the Procesing
sketch in the extras folder to visualize the camera output.

This example code is in the public domain.
*/

#include <Arduino_OV767X.h>

int bytesPerFrame;

byte data[176 * 144 * 2]; // QVGA: 320x240 X 2 bytes per pixel (RGB565)

void setup() {
Serial.begin(9600);
while (!Serial);

if (!Camera.begin(QVGA, RGB565, 1, OV7675)) {
Serial.println("Failed to initialize camera!");
while (1);
}

bytesPerFrame = Camera.width() * Camera.height() * Camera.bytesPerPixel();

// Optionally, enable the test pattern for testing
// Camera.testPattern();
}

void loop() {
Camera.readFrame(data);

Serial.write(data, bytesPerFrame);
}
Loading