#include <tensorflow/lite/micro/micro_interpreter.h>
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <esp_camera.h>
#include "model.h" // TensorFlow Lite model dosyasını buraya ekleyin
#include <driver/i2s.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
// BLE UUID'leri
#define SERVICE_UUID "00001101-0000-1000-8000-00805F9B34FB"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
// I2S Pin Yapılandırması (MAX98357A için)
#define I2S_BCK_IO 18
#define I2S_WS_IO 17
#define I2S_DO_IO 16
// OV7670 Kamera Pin Yapılandırması
#define CAM_SCL_PIN 9 // I2C Clock
#define CAM_SDA_PIN 46 // I2C Data
#define CAM_XCLK_PIN 3 // Kamera Saat Sinyali
#define CAM_PCLK_PIN 8 // Piksel Saat
#define CAM_HREF_PIN 18 // Yatay Senkronizasyon
#define CAM_VSYNC_PIN 17 // Dikey Senkronizasyon
// OV7670 Kamera Veri Pinleri (8-bit paralel veri yolu)
#define CAM_D0_PIN 16
#define CAM_D1_PIN 15
#define CAM_D2_PIN 7
#define CAM_D3_PIN 5
#define CAM_D4_PIN 4
#define CAM_D5_PIN 41
#define CAM_D6_PIN 40
#define CAM_D7_PIN 39
#define CAM_PWDN_PIN -1 // PWDWN GND'ye bağlı olduğu için kullanılmıyor
#define CAM_RESET_PIN 21 // RESET GPIO21'e bağlı
#define TENSOR_ARENA_SIZE 120 * 1024 // Tensor Arena Boyutu
// TensorFlow Lite nesneleri
uint8_t *tensor_arena;
tflite::MicroMutableOpResolver<4> resolver;
tflite::MicroInterpreter *interpreter = nullptr;
TfLiteTensor *input_tensor = nullptr;
void *AllocatePersistentBuffer(size_t bytes) {
void *ptr = heap_caps_malloc(bytes, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (!ptr) {
Serial.printf("PSRAM'de bellek tahsis edilemedi! Boyut: %u bytes\n", bytes);
}
return ptr;
}
// BLE Server nesneleri
BLEServer *pServer = nullptr;
BLECharacteristic *pCharacteristic = nullptr;
void setupCamera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = CAM_D0_PIN;
config.pin_d1 = CAM_D1_PIN;
config.pin_d2 = CAM_D2_PIN;
config.pin_d3 = CAM_D3_PIN;
config.pin_d4 = CAM_D4_PIN;
config.pin_d5 = CAM_D5_PIN;
config.pin_d6 = CAM_D6_PIN;
config.pin_d7 = CAM_D7_PIN;
config.pin_xclk = CAM_XCLK_PIN;
config.pin_pclk = CAM_PCLK_PIN;
config.pin_vsync = CAM_VSYNC_PIN;
config.pin_href = CAM_HREF_PIN;
config.pin_sscb_sda = CAM_SDA_PIN;
config.pin_sscb_scl = CAM_SCL_PIN;
config.pin_pwdn = CAM_PWDN_PIN;
config.pin_reset = CAM_RESET_PIN;
config.xclk_freq_hz = 20000000; // 20 MHz
config.pixel_format = PIXFORMAT_RGB888; // RGB888 formatı
config.frame_size = FRAMESIZE_QVGA; // Çözünürlük: 320x240
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_PSRAM;
if (esp_camera_init(&config) != ESP_OK) {
Serial.println("Kamera başlatılamadı!");
while (1) delay(1000);
} else {
Serial.println("Kamera başarıyla başlatıldı!");
}
}
// Yeniden boyutlandırma fonksiyonu
void resizeImage(uint8_t *src, uint8_t *dst, int src_width, int src_height, int dst_width, int dst_height) {
for (int y = 0; y < dst_height; y++) {
for (int x = 0; x < dst_width; x++) {
int src_x = x * src_width / dst_width;
int src_y = y * src_height / dst_height;
int src_index = (src_y * src_width + src_x) * 3; // RGB888 için
int dst_index = (y * dst_width + x) * 3; // RGB888 için
dst[dst_index] = src[src_index]; // R
dst[dst_index + 1] = src[src_index + 1]; // G
dst[dst_index + 2] = src[src_index + 2]; // B
}
}
}
// I2S Başlatma
void initI2S() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 16000, // Telefonla eşleşmeli
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_BCK_IO,
.ws_io_num = I2S_WS_IO,
.data_out_num = I2S_DO_IO,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &pin_config);
}
void playAudio(const char *audioData, size_t length) {
size_t bytes_written;
i2s_write(I2S_NUM_0, audioData, length, &bytes_written, portMAX_DELAY);
Serial.println("Ses çalındı.");
}
// BLE Server Callbacks
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("BLE cihazına bağlanıldı.");
}
void onDisconnect(BLEServer* pServer) {
Serial.println("BLE cihazından bağlantı kesildi.");
}
};
// BLE Kurulumu
void setupBLE() {
BLEDevice::init("ESP32-TTS");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
pServer->getAdvertising()->start();
Serial.println("BLE hizmeti başlatıldı.");
}
void printMemoryUsage() {
Serial.printf("Heap Toplam: %u bytes\n", ESP.getHeapSize());
Serial.printf("Heap Kullanılabilir: %u bytes\n", ESP.getFreeHeap());
Serial.printf("PSRAM Toplam: %u bytes\n", ESP.getPsramSize());
Serial.printf("PSRAM Kullanılabilir: %u bytes\n", ESP.getFreePsram());
}
void setup() {
Serial.begin(115200);
// BLE Başlatma
setupBLE();
// I2S Başlatma
initI2S();
// Kamera Başlatma
setupCamera();
tensor_arena = (uint8_t *)heap_caps_malloc(TENSOR_ARENA_SIZE, MALLOC_CAP_SPIRAM);
if (!tensor_arena) {
Serial.println("Tensor Arena tahsisi başarısız!");
printMemoryUsage();
while (1) delay(1000);
} else {
Serial.println("Tensor Arena başarıyla tahsis edildi.");
}
static tflite::MicroInterpreter static_interpreter(
tflite::GetModel(model), resolver, tensor_arena, TENSOR_ARENA_SIZE);
interpreter = &static_interpreter;
if (interpreter->AllocateTensors() != kTfLiteOk) {
Serial.println("Tensor Bellek Ayırma Başarısız!");
printMemoryUsage();
while (1) delay(1000);
} else {
Serial.println("TensorFlow Bellek Başarıyla Ayırıldı.");
}
input_tensor = interpreter->input(0);
Serial.println("TensorFlow Lite Başarıyla Başlatıldı!");
// PSRAM kontrolü
if (psramFound()) {
Serial.println("PSRAM bulundu!");
Serial.printf("PSRAM Toplam: %u bytes\n", ESP.getPsramSize());
Serial.printf("PSRAM Kullanılabilir: %u bytes\n", ESP.getFreePsram());
} else {
Serial.println("PSRAM bulunamadı!");
while (1) delay(1000);
}
printMemoryUsage();
// TensorFlow Lite kurulum
resolver.AddConv2D();
resolver.AddFullyConnected();
resolver.AddSoftmax();
resolver.AddReshape();
}
void loop() {
// TensorFlow Lite işlemleri
camera_fb_t *frame = esp_camera_fb_get();
if (!frame) {
Serial.println("Görüntü alınamadı!");
return;
}
int input_width = input_tensor->dims->data[1];
int input_height = input_tensor->dims->data[2];
int input_channels = input_tensor->dims->data[3];
uint8_t *resized_image = (uint8_t *)malloc(input_width * input_height * input_channels);
if (!resized_image) {
Serial.println("Yeniden boyutlandırma için bellek tahsisi başarısız!");
esp_camera_fb_return(frame);
return;
}
// Görüntüyü yeniden boyutlandır
resizeImage(frame->buf, resized_image, frame->width, frame->height, input_width, input_height);
// Yeniden boyutlandırılmış görüntüyü giriş tensörüne kopyala
memcpy(input_tensor->data.uint8, resized_image, input_width * input_height * input_channels);
free(resized_image);
esp_camera_fb_return(frame);
if (interpreter->Invoke() != kTfLiteOk) {
Serial.println("Model çalıştırılamadı!");
return;
}
memcpy(input_tensor->data.uint8, frame->buf, input_tensor->bytes);
if (interpreter->Invoke() != kTfLiteOk) {
Serial.println("Model çalıştırılamadı!");
esp_camera_fb_return(frame);
return;
}
TfLiteTensor *output_tensor = interpreter->output(0);
int num_classes = output_tensor->dims->data[1];
for (int i = 0; i < num_classes; i++) {
float confidence = output_tensor->data.f[i];
if (confidence > 0.5) { // Güven eşiği
String object_name = "Object " + String(i);
Serial.printf("Sınıf %d: %.2f\n", i, confidence);
pCharacteristic->setValue(object_name.c_str());
pCharacteristic->notify();
Serial.println("Nesne bilgisi gönderildi.");
}
}
esp_camera_fb_return(frame);
delay(1000); // 1 saniye bekle
}
I bought a ESP32-S3 WROOM-1 N16R8 from Temu.
I wrote code but Tensorflow can't allocate memory. Area is generating but i getting this problem.
Arduino IDE choosed Fri3d Badge 2024 (PSRAM working just this board setup, when i choose i can't run PSRAM With ESP32S3 DEV BOARD)
I tried many partition scheme.
Arduino IDE Serial Monitor:
BLE service started.
Tensor Arena has been successfully deployed.
Tensor Memory Allocation Failed! (Code 155.)
Total Heap: 352484 bytes
Heap Available: 248148 bytes
PSRAM Total: 8388608 bytes
PSRAM Available: 8180668 bytes
