mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
ports/rp2: Add support for multiple CSIs.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
parent
e4ee291028
commit
be6b3fa80d
@ -73,7 +73,7 @@ PIXEL_LOOP:
|
|||||||
.wrap
|
.wrap
|
||||||
|
|
||||||
% c-sdk {
|
% c-sdk {
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
int omv_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
||||||
uint offset;
|
uint offset;
|
||||||
pio_sm_config config;
|
pio_sm_config config;
|
||||||
@ -86,7 +86,7 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
}
|
}
|
||||||
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 7, false);
|
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 7, false);
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
||||||
config = dcmi_odd_byte_program_get_default_config(offset);
|
config = dcmi_odd_byte_program_get_default_config(offset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -57,7 +57,7 @@ PIXEL_LOOP:
|
|||||||
.wrap
|
.wrap
|
||||||
|
|
||||||
% c-sdk {
|
% c-sdk {
|
||||||
int omv_csi_config(omv_csi_config_t config) {
|
int omv_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
if (config == OMV_CSI_CONFIG_PIXFORMAT) {
|
||||||
uint offset;
|
uint offset;
|
||||||
pio_sm_config config;
|
pio_sm_config config;
|
||||||
@ -70,7 +70,7 @@ int omv_csi_config(omv_csi_config_t config) {
|
|||||||
}
|
}
|
||||||
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 8, false);
|
pio_sm_set_consecutive_pindirs(OMV_CSI_PIO, OMV_CSI_SM, OMV_CSI_D0_PIN, 8, false);
|
||||||
|
|
||||||
if (csi.pixformat == PIXFORMAT_GRAYSCALE) {
|
if (csi->pixformat == PIXFORMAT_GRAYSCALE) {
|
||||||
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
offset = pio_add_program(OMV_CSI_PIO, &dcmi_odd_byte_program);
|
||||||
config = dcmi_odd_byte_program_get_default_config(offset);
|
config = dcmi_odd_byte_program_get_default_config(offset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,31 +41,56 @@
|
|||||||
#include "unaligned_memcpy.h"
|
#include "unaligned_memcpy.h"
|
||||||
#include "dcmi.pio.h"
|
#include "dcmi.pio.h"
|
||||||
|
|
||||||
static void dma_irq_handler();
|
|
||||||
extern void __fatal_error(const char *msg);
|
extern void __fatal_error(const char *msg);
|
||||||
|
|
||||||
static void omv_csi_dma_config(int w, int h, int bpp, uint32_t *capture_buf, bool rev_bytes) {
|
static void dma_irq_handler() {
|
||||||
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
omv_csi_t *csi = omv_csi_get(-1);
|
||||||
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
dma_channel_config c = dma_channel_get_default_config(OMV_CSI_DMA_CHANNEL);
|
if (dma_irqn_get_channel_status(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL)) {
|
||||||
channel_config_set_read_increment(&c, false);
|
// Clear the interrupt request.
|
||||||
channel_config_set_write_increment(&c, true);
|
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
||||||
channel_config_set_dreq(&c, pio_get_dreq(OMV_CSI_PIO, OMV_CSI_SM, false));
|
|
||||||
channel_config_set_bswap(&c, rev_bytes);
|
|
||||||
|
|
||||||
dma_channel_configure(OMV_CSI_DMA_CHANNEL, &c,
|
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
||||||
capture_buf, // Destinatinon pointer.
|
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
||||||
&OMV_CSI_PIO->rxf[OMV_CSI_SM], // Source pointer.
|
if (buffer != NULL) {
|
||||||
(w * h * bpp) >> 2, // Number of transfers in words.
|
// Set next buffer and retrigger the DMA channel.
|
||||||
true // Start immediately, will block on SM.
|
dma_channel_set_write_addr(OMV_CSI_DMA_CHANNEL, buffer->data, true);
|
||||||
);
|
|
||||||
|
|
||||||
// Re-enable DMA IRQs.
|
// Unblock the state machine
|
||||||
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, true);
|
pio_sm_restart(OMV_CSI_PIO, OMV_CSI_SM);
|
||||||
|
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
||||||
|
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->v - 1));
|
||||||
|
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->u * fb->bpp) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
static int rp2_csi_config(omv_csi_t *csi, omv_csi_config_t config) {
|
||||||
|
if (config == OMV_CSI_CONFIG_INIT) {
|
||||||
|
// Install new DMA IRQ handler.
|
||||||
|
irq_set_enabled(OMV_CSI_DMA_IRQ, false);
|
||||||
|
|
||||||
|
// Clear DMA interrupts.
|
||||||
|
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
||||||
|
|
||||||
|
// Remove current handler if any
|
||||||
|
irq_handler_t irq_handler = irq_get_exclusive_handler(OMV_CSI_DMA_IRQ);
|
||||||
|
if (irq_handler != NULL) {
|
||||||
|
irq_remove_handler(OMV_CSI_DMA_IRQ, irq_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new exclusive IRQ handler.
|
||||||
|
irq_set_exclusive_handler(OMV_CSI_DMA_IRQ, dma_irq_handler);
|
||||||
|
// Or set shared IRQ handler, but this needs to be called once.
|
||||||
|
// irq_add_shared_handler(OMV_CSI_DMA_IRQ, dma_irq_handler, PICO_DEFAULT_IRQ_PRIORITY);
|
||||||
|
|
||||||
|
irq_set_enabled(OMV_CSI_DMA_IRQ, true);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rp2_csi_abort(omv_csi_t *csi, bool fifo_flush, bool in_irq) {
|
||||||
// Disable DMA channel
|
// Disable DMA channel
|
||||||
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
||||||
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
||||||
@ -107,39 +132,17 @@ int omv_csi_set_clk_frequency(uint32_t frequency) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int omv_csi_set_windowing(int x, int y, int w, int h) {
|
int omv_csi_set_windowing(omv_csi_t *csi, int x, int y, int w, int h) {
|
||||||
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
return OMV_CSI_ERROR_CTL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_irq_handler() {
|
static int rp2_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||||
framebuffer_t *fb = csi.fb;
|
|
||||||
|
|
||||||
if (dma_irqn_get_channel_status(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL)) {
|
|
||||||
// Clear the interrupt request.
|
|
||||||
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
|
||||||
|
|
||||||
framebuffer_get_tail(fb, FB_NO_FLAGS);
|
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK);
|
|
||||||
if (buffer != NULL) {
|
|
||||||
// Set next buffer and retrigger the DMA channel.
|
|
||||||
dma_channel_set_write_addr(OMV_CSI_DMA_CHANNEL, buffer->data, true);
|
|
||||||
|
|
||||||
// Unblock the state machine
|
|
||||||
pio_sm_restart(OMV_CSI_PIO, OMV_CSI_SM);
|
|
||||||
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
|
||||||
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->v - 1));
|
|
||||||
pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->u * fb->bpp) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|
||||||
framebuffer_t *fb = csi->fb;
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
// Compress the framebuffer for the IDE preview.
|
// Compress the framebuffer for the IDE preview.
|
||||||
framebuffer_update_jpeg_buffer(fb);
|
framebuffer_update_jpeg_buffer(fb);
|
||||||
|
|
||||||
if (omv_csi_check_framebuffer_size() != 0) {
|
if (omv_csi_check_framebuffer_size(csi) != 0) {
|
||||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,10 +167,25 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the DMA on the first frame, for later frames only the write is changed.
|
// Configure the DMA on the first frame.
|
||||||
omv_csi_dma_config(fb->u, fb->v, fb->bpp,
|
dma_channel_abort(OMV_CSI_DMA_CHANNEL);
|
||||||
(void *) buffer->data,
|
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, false);
|
||||||
(csi->rgb_swap && fb->bpp == 2));
|
|
||||||
|
dma_channel_config c = dma_channel_get_default_config(OMV_CSI_DMA_CHANNEL);
|
||||||
|
channel_config_set_read_increment(&c, false);
|
||||||
|
channel_config_set_write_increment(&c, true);
|
||||||
|
channel_config_set_dreq(&c, pio_get_dreq(OMV_CSI_PIO, OMV_CSI_SM, false));
|
||||||
|
channel_config_set_bswap(&c, csi->rgb_swap && (fb->bpp == 2));
|
||||||
|
|
||||||
|
dma_channel_configure(OMV_CSI_DMA_CHANNEL, &c,
|
||||||
|
(uint32_t *) buffer->data, // Destinatinon pointer.
|
||||||
|
&OMV_CSI_PIO->rxf[OMV_CSI_SM], // Source pointer.
|
||||||
|
(fb->u * fb->v * fb->bpp) >> 2, // Number of transfers in words.
|
||||||
|
true // Start immediately, will block on SM.
|
||||||
|
);
|
||||||
|
|
||||||
|
// Re-enable DMA IRQs.
|
||||||
|
dma_irqn_set_channel_enabled(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL, true);
|
||||||
|
|
||||||
// Re-enable the state machine.
|
// Re-enable the state machine.
|
||||||
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
pio_sm_clear_fifos(OMV_CSI_PIO, OMV_CSI_SM);
|
||||||
@ -194,10 +212,10 @@ int omv_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
framebuffer_init_image(fb, image);
|
framebuffer_init_image(fb, image);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int omv_csi_init() {
|
int omv_csi_init() {
|
||||||
int init_ret = 0;
|
int init_ret = 0;
|
||||||
|
static omv_i2c_t i2c;
|
||||||
|
|
||||||
// PIXCLK
|
// PIXCLK
|
||||||
gpio_init(OMV_CSI_PXCLK_PIN);
|
gpio_init(OMV_CSI_PXCLK_PIN);
|
||||||
@ -225,17 +243,19 @@ int omv_csi_init() {
|
|||||||
gpio_put(OMV_CSI_RESET_PIN, 1);
|
gpio_put(OMV_CSI_RESET_PIN, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset the csi state
|
// Initialize the CSIs using this driver's ops as defaults,
|
||||||
memset(&csi, 0, sizeof(omv_csi_t));
|
// which can be overridden by sensor drivers during probe.
|
||||||
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set default framebuffer
|
memset(csi, 0, sizeof(omv_csi_t));
|
||||||
csi.fb = framebuffer_get(0);
|
csi->i2c = &i2c;
|
||||||
|
csi->fb = framebuffer_get(-1);
|
||||||
// Set I2C bus
|
csi->abort = rp2_csi_abort;
|
||||||
csi.i2c = &csi_i2c;
|
csi->config = rp2_csi_config;
|
||||||
|
csi->snapshot = rp2_csi_snapshot;
|
||||||
// Set default snapshot function.
|
csi->color_palette = rainbow_table;
|
||||||
csi.snapshot = omv_csi_snapshot;
|
}
|
||||||
|
|
||||||
// Configure the csi external clock (XCLK).
|
// Configure the csi external clock (XCLK).
|
||||||
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
if (omv_csi_set_clk_frequency(OMV_CSI_CLK_FREQUENCY) != 0) {
|
||||||
@ -243,43 +263,28 @@ int omv_csi_init() {
|
|||||||
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
return OMV_CSI_ERROR_TIM_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the camera bus.
|
||||||
|
omv_i2c_init(&i2c, OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED);
|
||||||
|
|
||||||
// Detect and initialize the image sensor.
|
// Detect and initialize the image sensor.
|
||||||
if ((init_ret = omv_csi_probe_init(OMV_CSI_I2C_ID, OMV_CSI_I2C_SPEED)) != 0) {
|
if ((init_ret = omv_csi_probe(&i2c)) != 0) {
|
||||||
// Sensor probe/init failed.
|
// Sensor probe/init failed.
|
||||||
return init_ret;
|
return init_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default color palette.
|
// Configure the DCMI interface.
|
||||||
csi.color_palette = rainbow_table;
|
for (size_t i=0; i<OMV_CSI_MAX_DEVICES; i++) {
|
||||||
|
omv_csi_t *csi = &csi_all[i];
|
||||||
|
|
||||||
// Set new DMA IRQ handler.
|
if (omv_csi_config(csi, OMV_CSI_CONFIG_INIT) != 0) {
|
||||||
// Disable IRQs.
|
return OMV_CSI_ERROR_CSI_INIT_FAILED;
|
||||||
irq_set_enabled(OMV_CSI_DMA_IRQ, false);
|
}
|
||||||
|
|
||||||
// Clear DMA interrupts.
|
csi->detected = true;
|
||||||
dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL);
|
|
||||||
|
|
||||||
// Remove current handler if any
|
|
||||||
irq_handler_t irq_handler = irq_get_exclusive_handler(OMV_CSI_DMA_IRQ);
|
|
||||||
if (irq_handler != NULL) {
|
|
||||||
irq_remove_handler(OMV_CSI_DMA_IRQ, irq_handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set new exclusive IRQ handler.
|
// Clear fb_enabled flag.
|
||||||
irq_set_exclusive_handler(OMV_CSI_DMA_IRQ, dma_irq_handler);
|
JPEG_FB()->enabled = 0;
|
||||||
// Or set shared IRQ handler, but this needs to be called once.
|
|
||||||
// irq_add_shared_handler(OMV_CSI_DMA_IRQ, dma_irq_handler, PICO_DEFAULT_IRQ_PRIORITY);
|
|
||||||
|
|
||||||
irq_set_enabled(OMV_CSI_DMA_IRQ, true);
|
|
||||||
|
|
||||||
// Disable VSYNC IRQ and callback
|
|
||||||
omv_csi_set_vsync_callback(NULL);
|
|
||||||
|
|
||||||
// Disable Frame callback.
|
|
||||||
omv_csi_set_frame_callback(NULL);
|
|
||||||
|
|
||||||
/* All good! */
|
|
||||||
csi.detected = true;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif // MICROPY_PY_CSI
|
||||||
|
Loading…
Reference in New Issue
Block a user