XCLK is now generated (in theory)
GPIO gets inited PIO gets setup (no DMA currently)
This commit is contained in:
parent
4286ab04ee
commit
fde6d7d999
@ -9,8 +9,11 @@
|
|||||||
#include "hardware/clocks.h"
|
#include "hardware/clocks.h"
|
||||||
#include "hardware/uart.h"
|
#include "hardware/uart.h"
|
||||||
|
|
||||||
|
#include <ov2640/SCCB.hpp>
|
||||||
#include <ov2640/camera.hpp>
|
#include <ov2640/camera.hpp>
|
||||||
|
|
||||||
|
// PIO2 is reserved for the cam data retreive functions
|
||||||
|
|
||||||
camera_config_t left_eye_config = {
|
camera_config_t left_eye_config = {
|
||||||
.pin_pwdn = -1, /*!< GPIO pin for camera power down line */ //? Also called PWDN, or set to -1 and tie to GND
|
.pin_pwdn = -1, /*!< GPIO pin for camera power down line */ //? Also called PWDN, or set to -1 and tie to GND
|
||||||
.pin_reset = -1, /*!< GPIO pin for camera reset line */ //? Cam reset, or set to -1 and tie to 3.3V
|
.pin_reset = -1, /*!< GPIO pin for camera reset line */ //? Cam reset, or set to -1 and tie to 3.3V
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#include <sccb.hpp>
|
#include <SCCB.hpp>
|
||||||
|
#include <camera.hpp>
|
||||||
#include "hardware/i2c.h"
|
#include "hardware/i2c.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "src/pio/i2c/pio_i2c.h"
|
#include "src/pio/i2c/pio_i2c.h"
|
||||||
|
|
||||||
SCCB::SCCB(uint8_t sda_pin, uint8_t scl_pin) {
|
SCCB::SCCB(uint8_t sda_pin, uint8_t scl_pin) {
|
||||||
this->sda = sda_pin;
|
this->sda = sda_pin;
|
||||||
this->scl = scl_pin;
|
this->scl = scl_pin;
|
||||||
@ -1,4 +1,7 @@
|
|||||||
#include <camera.hpp>
|
typedef struct {
|
||||||
|
uint8_t reg; ///< Register address
|
||||||
|
uint8_t value; ///< Value to store
|
||||||
|
} register_val_t;
|
||||||
|
|
||||||
class SCCB {
|
class SCCB {
|
||||||
public:
|
public:
|
||||||
@ -1,7 +1,34 @@
|
|||||||
#include <camera.hpp>
|
#include <camera.hpp>
|
||||||
#include <sccb.hpp>
|
#include <SCCB.hpp>
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "../../hardware_dma/include/hardware/dma.h"
|
||||||
|
#include "hardware/pwm.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
#include "hardware/irq.h"
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
|
||||||
|
// TODO: Stolen from Adafruit repo (Check if correct)
|
||||||
|
|
||||||
|
// PIO code in this table is modified at runtime so that PCLK is
|
||||||
|
// configurable (rather than fixed GP## or PIN offset). Data pins
|
||||||
|
// must be contiguous but are otherwise configurable.
|
||||||
|
static uint16_t capture_pio_opcodes[] = {
|
||||||
|
// Only monitor PCLK when HSYNC is high. This is more noise-immune
|
||||||
|
// than letting it fly.
|
||||||
|
0b0010000010000000, // WAIT 1 GPIO 0 (mask in HSYNC pin before use)
|
||||||
|
0b0010000010000000, // WAIT 1 GPIO 0 (mask in PCLK pin before use)
|
||||||
|
0b0100000000001000, // IN PINS 8 -- 8 bits into RX FIFO
|
||||||
|
0b0010000000000000, // WAIT 0 GPIO 0 (mask in PCLK pin before use)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct pio_program cap_pio_program = {
|
||||||
|
.instructions = capture_pio_opcodes,
|
||||||
|
.length = sizeof capture_pio_opcodes / sizeof capture_pio_opcodes[0],
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
register_val_t OV2640_init[] = {
|
register_val_t OV2640_init[] = {
|
||||||
// Ideas from rp2040_ov2640-main repo
|
// Ideas from rp2040_ov2640-main repo
|
||||||
// OV2640 camera initialization after reset
|
// OV2640 camera initialization after reset
|
||||||
@ -300,7 +327,16 @@ OV2640::OV2640(camera_config_t config) {
|
|||||||
|
|
||||||
int OV2640::begin() {
|
int OV2640::begin() {
|
||||||
// Initialize peripherals for parallel+I2C camera:
|
// Initialize peripherals for parallel+I2C camera:
|
||||||
//! TODO: start XCLK before SCCB init
|
|
||||||
|
// XCLK generation (~20.83 MHz)
|
||||||
|
gpio_set_function(this->config.pin_xclk, GPIO_FUNC_PWM);
|
||||||
|
uint slice_num = pwm_gpio_to_slice_num(this->config.pin_xclk);
|
||||||
|
// 6 cycles (0 to 5), 125 MHz / 6 = ~20.83 MHz wrap rate
|
||||||
|
pwm_set_wrap(slice_num, 5);
|
||||||
|
pwm_set_gpio_level(this->config.pin_xclk, 3);
|
||||||
|
pwm_set_enabled(slice_num, true);
|
||||||
|
|
||||||
|
// Init SCCB
|
||||||
this->sccb = SCCB(this->config.pin_sccb_sda,this->config.pin_sccb_scl);
|
this->sccb = SCCB(this->config.pin_sccb_sda,this->config.pin_sccb_scl);
|
||||||
this->sccb.begin(this->config.sccb_ctrl);
|
this->sccb.begin(this->config.sccb_ctrl);
|
||||||
|
|
||||||
@ -316,8 +352,96 @@ int OV2640::begin() {
|
|||||||
|
|
||||||
// Init main camera settings
|
// Init main camera settings
|
||||||
this->sccb.writeList(OV2640_init, sizeof OV2640_init / sizeof OV2640_init[0]);
|
this->sccb.writeList(OV2640_init, sizeof OV2640_init / sizeof OV2640_init[0]);
|
||||||
|
|
||||||
|
gpio_init(this->config.pin_pclk);
|
||||||
|
gpio_set_dir(this->config.pin_pclk, GPIO_IN);
|
||||||
|
gpio_init(this->config.pin_vsync);
|
||||||
|
gpio_set_dir(this->config.pin_vsync, GPIO_IN);
|
||||||
|
gpio_init(this->config.pin_href);
|
||||||
|
gpio_set_dir(this->config.pin_href, GPIO_IN);
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
gpio_init(this->config.pin_data_base + i);
|
||||||
|
gpio_set_dir(this->config.pin_data_base + i, GPIO_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PIO periph to use is currently specified by the user in the arch struct,
|
||||||
|
// but I suppose this could be written to use whatever PIO has resources.
|
||||||
|
|
||||||
|
// Mask the GPIO pin used PCLK into the PIO opcodes -- see notes at top
|
||||||
|
// TODO: check if this is correct (code made for rp2040 not rp2350 so it might differ)
|
||||||
|
capture_pio_opcodes[0] |= (this->config.pin_href & 31);
|
||||||
|
capture_pio_opcodes[1] |= (this->config.pin_pclk & 31);
|
||||||
|
capture_pio_opcodes[3] |= (this->config.pin_pclk & 31);
|
||||||
|
|
||||||
|
uint offset = pio_add_program(pio2, &cap_pio_program);
|
||||||
|
this->sm = pio_claim_unused_sm(pio2, true); // 0-3
|
||||||
|
|
||||||
|
// host->pins->data[0] is data bit 0. PIO code requires all 8 data be
|
||||||
|
// contiguous.
|
||||||
|
pio_sm_set_consecutive_pindirs(pio2, this->sm, this->config.pin_data_base, 8, false);
|
||||||
|
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
c.pinctrl = 0; // SDK fails to set this
|
||||||
|
sm_config_set_wrap(&c, offset, offset + cap_pio_program.length - 1);
|
||||||
|
|
||||||
|
sm_config_set_in_pins(&c, this->config.pin_data_base);
|
||||||
|
sm_config_set_in_shift(&c, false, true, 16); // 1 pixel (16b) ISR to FIFO
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||||
|
|
||||||
|
pio_sm_init(pio2, this->sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio2, this->sm, true);
|
||||||
|
|
||||||
|
// SET UP DMA ------------------------------------------------------------
|
||||||
|
|
||||||
|
this->dma_channel = dma_claim_unused_channel(false); // don't panic
|
||||||
|
|
||||||
|
this->dma_config = dma_channel_get_default_config(this->dma_channel);
|
||||||
|
channel_config_set_transfer_data_size(&this->dma_config, DMA_SIZE_16);
|
||||||
|
channel_config_set_read_increment(&this->dma_config, false);
|
||||||
|
channel_config_set_write_increment(&this->dma_config, true);
|
||||||
|
channel_config_set_bswap(&this->dma_config, true); // TODO: bswap should be true or false?
|
||||||
|
|
||||||
|
// Set PIO RX as DMA trigger. Input shift register saturates at 16 bits
|
||||||
|
// (1 pixel), configured in data size above and in PIO setup elsewhere.
|
||||||
|
channel_config_set_dreq(&this->dma_config,
|
||||||
|
pio_get_dreq(pio2, this->sm, false));
|
||||||
|
// Set up baseline DMA configuration...it's initially lacking destination
|
||||||
|
// and count, set later (dma_change()) after resolution is known. DMA
|
||||||
|
// isn't started until later, and is triggered in the vsync interrupt.
|
||||||
|
dma_channel_configure(this->dma_channel, &this->dma_config, NULL,
|
||||||
|
&pio2->rxf[this->sm], 0, false);
|
||||||
|
|
||||||
|
// Set up end-of-DMA interrupt
|
||||||
|
dma_channel_set_irq0_enabled(this->dma_channel, true);
|
||||||
|
// TODO: setup diffrent handlers for each cam???
|
||||||
|
irq_set_exclusive_handler(DMA_IRQ_0, iCap_dma_finish_irq);
|
||||||
|
irq_set_enabled(DMA_IRQ_0, true);
|
||||||
|
|
||||||
|
// SET UP VSYNC INTERRUPT ------------------------------------------------
|
||||||
|
|
||||||
|
gpio_set_irq_enabled_with_callback(this->config.pin_vsync, GPIO_IRQ_EDGE_RISE, true,
|
||||||
|
&iCap_vsync_irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: figure out how to get from where does IRQs originate from
|
||||||
|
// TODO: how to transfer data?
|
||||||
|
// TODO: what?
|
||||||
|
// TODO: eep time
|
||||||
|
// TODO: make a static array with something like a hashmap containing GPIO -> sm+dma_channel mappings
|
||||||
|
// Pin interrupt on VSYNC calls this to start DMA transfer (unless suspended).
|
||||||
|
static void iCap_vsync_irq(uint gpio, uint32_t events) {
|
||||||
|
pio_sm_clear_fifos(pio2, archptr->sm);
|
||||||
|
dma_channel_start(archptr->dma_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make a static array with something like a hashmap containing GPIO -> sm+dma_channel mappings
|
||||||
|
static void iCap_dma_finish_irq() {
|
||||||
|
// Channel MUST be reconfigured each time (to reset the dest address).
|
||||||
|
dma_channel_set_write_addr(archptr->dma_channel,
|
||||||
|
(uint8_t *)(capptr->getBuffer()), false);
|
||||||
|
dma_hw->ints0 = 1u << archptr->dma_channel; // Clear IRQ
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: add all of the specific controls like brightness and all of that scheiße
|
// TODO: add all of the specific controls like brightness and all of that scheiße
|
||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// TODO: Add XCLK settings
|
// TODO: Add XCLK settings
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int pin_pwdn; /*!< GPIO pin for camera power down line */ //? Also called PWDN, or set to -1 and tie to GND
|
int pin_pwdn; /*!< GPIO pin for camera power down line */ //? Also called PWDN, or set to -1 and tie to GND
|
||||||
@ -14,11 +13,6 @@ typedef struct {
|
|||||||
uint8_t sccb_ctrl; /* Select i2c controller ctrl: 0 - i2c0, 1 - i2c1, 2 - pio0, 3 - pio1, 4 - pio2 */
|
uint8_t sccb_ctrl; /* Select i2c controller ctrl: 0 - i2c0, 1 - i2c1, 2 - pio0, 3 - pio1, 4 - pio2 */
|
||||||
} camera_config_t;
|
} camera_config_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t reg; ///< Register address
|
|
||||||
uint8_t value; ///< Value to store
|
|
||||||
} register_val_t;
|
|
||||||
|
|
||||||
class OV2640 {
|
class OV2640 {
|
||||||
public:
|
public:
|
||||||
OV2640(camera_config_t config);
|
OV2640(camera_config_t config);
|
||||||
@ -28,6 +22,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
camera_config_t config;
|
camera_config_t config;
|
||||||
SCCB sccb;
|
SCCB sccb;
|
||||||
|
uint sm;
|
||||||
|
uint dma_channel;
|
||||||
|
dma_channel_config dma_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
//? Refer to https://github.com/adafruit/Adafruit_ImageCapture/blob/main/src/Adafruit_iCap_OV2640.h to check whatever this shit below even is??
|
//? Refer to https://github.com/adafruit/Adafruit_ImageCapture/blob/main/src/Adafruit_iCap_OV2640.h to check whatever this shit below even is??
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user