Some DMA thoughts
This commit is contained in:
parent
5049ef6e9d
commit
76bf0c144e
@ -8,6 +8,7 @@
|
|||||||
#include "hardware/timer.h"
|
#include "hardware/timer.h"
|
||||||
#include "hardware/clocks.h"
|
#include "hardware/clocks.h"
|
||||||
#include "hardware/uart.h"
|
#include "hardware/uart.h"
|
||||||
|
#include "../../hardware_dma/include/hardware/dma.h"
|
||||||
|
|
||||||
#include <ov2640/SCCB.hpp>
|
#include <ov2640/SCCB.hpp>
|
||||||
#include <ov2640/camera.hpp>
|
#include <ov2640/camera.hpp>
|
||||||
@ -32,6 +33,9 @@ int main()
|
|||||||
{
|
{
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
|
OV2640 left_cam = OV2640(left_eye_config);
|
||||||
|
left_cam.begin(DMA_IRQ_0);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
printf("Hello, world!\n");
|
printf("Hello, world!\n");
|
||||||
sleep_ms(1000);
|
sleep_ms(1000);
|
||||||
|
|||||||
@ -22,7 +22,6 @@ static uint16_t capture_pio_opcodes[] = {
|
|||||||
0b0010000000000000, // WAIT 0 GPIO 0 (mask in PCLK pin before use)
|
0b0010000000000000, // WAIT 0 GPIO 0 (mask in PCLK pin before use)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct pio_program cap_pio_program = {
|
static struct pio_program cap_pio_program = {
|
||||||
.instructions = capture_pio_opcodes,
|
.instructions = capture_pio_opcodes,
|
||||||
.length = sizeof capture_pio_opcodes / sizeof capture_pio_opcodes[0],
|
.length = sizeof capture_pio_opcodes / sizeof capture_pio_opcodes[0],
|
||||||
@ -280,8 +279,7 @@ register_val_t OV2640_init[] = {
|
|||||||
{OV2640_REG0_ZMOH, 0x78}, // OUTH low bits
|
{OV2640_REG0_ZMOH, 0x78}, // OUTH low bits
|
||||||
{OV2640_REG0_ZMHH, 0x00}, // OUTW/H high bits
|
{OV2640_REG0_ZMHH, 0x00}, // OUTW/H high bits
|
||||||
{OV2640_REG0_R_DVP_SP, 0x02}, // Manual DVP PCLK setting
|
{OV2640_REG0_R_DVP_SP, 0x02}, // Manual DVP PCLK setting
|
||||||
{OV2640_REG0_RESET, 0x00}
|
{OV2640_REG0_RESET, 0x00}}; // Go
|
||||||
}; // Go
|
|
||||||
// TODO: figure out how to set to JPEG and 260x260
|
// TODO: figure out how to set to JPEG and 260x260
|
||||||
/*OV2640_qqvga[] =
|
/*OV2640_qqvga[] =
|
||||||
{// Configure OV2640 for QQVGA output
|
{// Configure OV2640 for QQVGA output
|
||||||
@ -321,11 +319,17 @@ OV2640_yuv[] = {
|
|||||||
{OV2640_REG0_RESET, 0x00}
|
{OV2640_REG0_RESET, 0x00}
|
||||||
}; // Go*/
|
}; // Go*/
|
||||||
|
|
||||||
OV2640::OV2640(camera_config_t config) {
|
uint8_t image_buf[3][13 * 1024];
|
||||||
|
sm_dma_config_t gpios[48];
|
||||||
|
|
||||||
|
OV2640::OV2640(camera_config_t config)
|
||||||
|
{
|
||||||
this->config = config;
|
this->config = config;
|
||||||
|
this->fb = &image_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OV2640::begin() {
|
int OV2640::begin(int dma_irq)
|
||||||
|
{
|
||||||
// Initialize peripherals for parallel+I2C camera:
|
// Initialize peripherals for parallel+I2C camera:
|
||||||
|
|
||||||
// XCLK generation (~20.83 MHz)
|
// XCLK generation (~20.83 MHz)
|
||||||
@ -359,7 +363,8 @@ int OV2640::begin() {
|
|||||||
gpio_set_dir(this->config.pin_vsync, GPIO_IN);
|
gpio_set_dir(this->config.pin_vsync, GPIO_IN);
|
||||||
gpio_init(this->config.pin_href);
|
gpio_init(this->config.pin_href);
|
||||||
gpio_set_dir(this->config.pin_href, GPIO_IN);
|
gpio_set_dir(this->config.pin_href, GPIO_IN);
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
gpio_init(this->config.pin_data_base + i);
|
gpio_init(this->config.pin_data_base + i);
|
||||||
gpio_set_dir(this->config.pin_data_base + i, GPIO_IN);
|
gpio_set_dir(this->config.pin_data_base + i, GPIO_IN);
|
||||||
}
|
}
|
||||||
@ -376,8 +381,6 @@ int OV2640::begin() {
|
|||||||
uint offset = pio_add_program(pio2, &cap_pio_program);
|
uint offset = pio_add_program(pio2, &cap_pio_program);
|
||||||
this->sm = pio_claim_unused_sm(pio2, true); // 0-3
|
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_set_consecutive_pindirs(pio2, this->sm, this->config.pin_data_base, 8, false);
|
||||||
|
|
||||||
pio_sm_config c = pio_get_default_sm_config();
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
@ -399,7 +402,7 @@ int OV2640::begin() {
|
|||||||
channel_config_set_transfer_data_size(&this->dma_config, DMA_SIZE_16);
|
channel_config_set_transfer_data_size(&this->dma_config, DMA_SIZE_16);
|
||||||
channel_config_set_read_increment(&this->dma_config, false);
|
channel_config_set_read_increment(&this->dma_config, false);
|
||||||
channel_config_set_write_increment(&this->dma_config, true);
|
channel_config_set_write_increment(&this->dma_config, true);
|
||||||
channel_config_set_bswap(&this->dma_config, true); // TODO: bswap should be true or false?
|
channel_config_set_bswap(&this->dma_config, true);
|
||||||
|
|
||||||
// Set PIO RX as DMA trigger. Input shift register saturates at 16 bits
|
// 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.
|
// (1 pixel), configured in data size above and in PIO setup elsewhere.
|
||||||
@ -413,35 +416,47 @@ int OV2640::begin() {
|
|||||||
|
|
||||||
// Set up end-of-DMA interrupt
|
// Set up end-of-DMA interrupt
|
||||||
dma_channel_set_irq0_enabled(this->dma_channel, true);
|
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);
|
//? setup diffrent handlers for each cam???
|
||||||
irq_set_enabled(DMA_IRQ_0, true);
|
//? check with a button or smth if this fires all events or only one
|
||||||
|
//? cuz then I would be able to do dma_finish_irq_cam1, dma_finish_irq_cam2, dma_finish_irq_cam3
|
||||||
|
//? That would have hardcoded values for the buffers
|
||||||
|
irq_set_exclusive_handler(dma_irq, dma_finish_irq);
|
||||||
|
irq_set_enabled(dma_irq, true);
|
||||||
|
|
||||||
// SET UP VSYNC INTERRUPT ------------------------------------------------
|
// SET UP VSYNC INTERRUPT ------------------------------------------------
|
||||||
|
//? This also could be redone with hardcoded values
|
||||||
gpio_set_irq_enabled_with_callback(this->config.pin_vsync, GPIO_IRQ_EDGE_RISE, true,
|
gpio_set_irq_enabled_with_callback(this->config.pin_vsync, GPIO_IRQ_EDGE_RISE, true,
|
||||||
&iCap_vsync_irq);
|
&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).
|
// Pin interrupt on VSYNC calls this to start DMA transfer (unless suspended).
|
||||||
static void iCap_vsync_irq(uint gpio, uint32_t events) {
|
static void vsync_irq(uint gpio, uint32_t events)
|
||||||
|
{
|
||||||
pio_sm_clear_fifos(pio2, archptr->sm);
|
pio_sm_clear_fifos(pio2, archptr->sm);
|
||||||
dma_channel_start(archptr->dma_channel);
|
dma_channel_start(archptr->dma_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make a static array with something like a hashmap containing GPIO -> sm+dma_channel mappings
|
static void dma_finish_irq()
|
||||||
static void iCap_dma_finish_irq() {
|
{
|
||||||
// Channel MUST be reconfigured each time (to reset the dest address).
|
// Channel MUST be reconfigured each time (to reset the dest address).
|
||||||
dma_channel_set_write_addr(archptr->dma_channel,
|
dma_channel_set_write_addr(archptr->dma_channel,
|
||||||
(uint8_t *)(capptr->getBuffer()), false);
|
(uint8_t *)(image_buf), false);
|
||||||
dma_hw->ints0 = 1u << archptr->dma_channel; // Clear IRQ
|
dma_hw->ints0 = 1u << archptr->dma_channel; // Clear IRQ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! https://forums.raspberrypi.com/viewtopic.php?t=339299
|
||||||
|
// TODO: change to switches and experiment with state machines, check if I can kinda reserve dma's so 0-3 would indicate state machines 0-3
|
||||||
|
/* Read the flags
|
||||||
|
uint32_t flags = read_register(PIO0_BASE, PIO_IRQ_OFFSET)
|
||||||
|
// Check the flags to determine which state machine made the request
|
||||||
|
if (flags & 0b0001) { handle_sm_0(); }
|
||||||
|
if (flags & 0b0010) { handle_sm_1(); }
|
||||||
|
if (flags & 0b0100) { handle_sm_2(); }
|
||||||
|
if (flags & 0b1000) { handle_sm_3(); }
|
||||||
|
*/
|
||||||
|
|
||||||
// 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
|
||||||
@ -13,15 +13,22 @@ 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 {
|
||||||
|
uint sm;
|
||||||
|
uint dma_channel;
|
||||||
|
} sm_dma_config_t;
|
||||||
|
|
||||||
|
|
||||||
class OV2640 {
|
class OV2640 {
|
||||||
public:
|
public:
|
||||||
OV2640(camera_config_t config);
|
OV2640(camera_config_t config);
|
||||||
~OV2640();
|
~OV2640();
|
||||||
|
|
||||||
int begin();
|
int begin(int dma_irq);
|
||||||
private:
|
private:
|
||||||
camera_config_t config;
|
camera_config_t config;
|
||||||
SCCB sccb;
|
SCCB sccb;
|
||||||
|
uint8_t* (*fb)[3];
|
||||||
uint sm;
|
uint sm;
|
||||||
uint dma_channel;
|
uint dma_channel;
|
||||||
dma_channel_config dma_config;
|
dma_channel_config dma_config;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user