// Wokwi Custom SPI Chip Example for Camera
//
// This chip simulates an OV5642-like camera, providing random image data over SPI.
//
// For information and examples see:
// https://docs.wokwi.com/chips-api/getting-started
//
// SPDX-License-Identifier: MIT
// Copyright (C) 2022 Uri Shaked / wokwi.com (original template)
// Adapted for OV5642 SPI camera simulation
#include "wokwi-api.h" // <--- This line MUST be here for custom chips
#include <stdio.h>
#include <stdlib.h> // For rand(), srand()
// Define a reasonable image resolution for simulation
#define IMAGE_WIDTH 120
#define IMAGE_HEIGHT 160
#define BUFFER_LEN (IMAGE_WIDTH * IMAGE_HEIGHT) // Total bytes for a grayscale image (one byte per pixel)
typedef struct {
pin_t cs_pin;
spi_dev_t spi_dev; // Use spi_dev_t for the SPI device ID
} chip_state_t;
// Global buffer for image data
uint8_t image_data[BUFFER_LEN];
// We don't need spi_buffer_read_index as spi_start handles the buffer directly.
// Function prototype
static void chip_pin_change(void *user_data, pin_t pin, uint32_t value);
// Fills the image_data buffer with dummy data
void generate_image_data() {
// Use a fixed seed for reproducible random data in simulation
srand(100);
for (int i = 0; i < BUFFER_LEN; i++) {
image_data[i] = rand() % 256; // Generate random byte (0-255)
}
printf("Generated %u bytes of dummy image data.\n", BUFFER_LEN);
}
void chip_init(void) {
chip_state_t *chip = malloc(sizeof(chip_state_t));
if (chip == NULL) {
printf("Failed to allocate chip state\n");
return;
}
// Initialize random image data once
generate_image_data();
chip->cs_pin = pin_init("CS", INPUT_PULLUP); // Chip Select pin
const pin_watch_config_t watch_config = {
.edge = BOTH, // Watch for both rising and falling edges
.pin_change = chip_pin_change,
.user_data = chip,
};
pin_watch(chip->cs_pin, &watch_config);
const spi_config_t spi_config = {
.sck = pin_init("SCK", INPUT),
.miso = pin_init("MISO", OUTPUT), // MISO is an output from the chip's perspective
.mosi = pin_init("MOSI", INPUT),
.user_data = chip,
};
chip->spi_dev = spi_init(&spi_config); // Store the SPI device handle
printf("OV5642 SPI Camera Chip initialized!\n");
}
// This function is called when the CS pin changes state
void chip_pin_change(void *user_data, pin_t pin, uint32_t value) {
chip_state_t *chip = (chip_state_t*)user_data;
if (pin == chip->cs_pin) {
if (value == LOW) { // Chip Select is active (LOW)
printf("OV5642 SPI Camera selected. Starting image data transfer.\n");
// Start SPI transaction. The slave will send 'BUFFER_LEN' bytes from 'image_data'.
// The MOSI buffer is NULL here as the camera is primarily sending, not receiving.
spi_start(chip->spi_dev, image_data, BUFFER_LEN);
} else { // Chip Select is inactive (HIGH)
printf("OV5642 SPI Camera deselected.\n");
spi_stop(chip->spi_dev); // Stop the SPI communication
}
}
}