mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #2720 from kwagyeman/kwabena/framebuffer_lepton
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions
drivers/sensors/lepton: Update lepton driver with asynchronous fb.
This commit is contained in:
commit
acc5edb0fc
@ -141,8 +141,6 @@
|
||||
#define OMV_FB_OVERLAY_SIZE (448K) // Fast fb_alloc memory size.
|
||||
#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer.
|
||||
#define OMV_JPEG_SIZE (1M) // IDE JPEG buffer (header + data).
|
||||
#define OMV_VOSPI_MEMORY DTCM // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (38K)
|
||||
#define OMV_DMA_MEMORY SRAM3 // Misc DMA buffers memory.
|
||||
#define OMV_DMA_MEMORY_D1 SRAM0 // Domain 1 DMA buffers.
|
||||
#define OMV_DMA_MEMORY_D2 SRAM3 // Domain 2 DMA buffers.
|
||||
|
||||
@ -139,6 +139,7 @@
|
||||
#define OMV_GC_BLOCK2_SIZE (276K)
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -139,8 +139,6 @@
|
||||
#define OMV_FB_OVERLAY_SIZE (480K) // Fast fb_alloc memory size.
|
||||
#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer.
|
||||
#define OMV_JPEG_SIZE (1M) // IDE JPEG buffer (header + data).
|
||||
#define OMV_VOSPI_MEMORY SRAM4 // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (38K)
|
||||
#define OMV_DMA_MEMORY SRAM3 // Misc DMA buffers memory.
|
||||
#define OMV_DMA_MEMORY_D1 SRAM0 // Domain 1 DMA buffers.
|
||||
#define OMV_DMA_MEMORY_D2 SRAM3 // Domain 2 DMA buffers.
|
||||
@ -156,6 +154,7 @@
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_SDRAM_SIZE (8 * 1024 * 1024) // This needs to be here for UVC firmware.
|
||||
#define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer round(2592 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -93,6 +93,7 @@
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_FFS_BUF_SIZE (16K) // Flash filesystem cache
|
||||
#define OMV_LINE_BUF_SIZE (2 * 1024) // Image line buffer round(320 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -92,6 +92,7 @@
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_FFS_BUF_SIZE (32K) // Flash filesystem cache
|
||||
#define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -138,15 +138,14 @@
|
||||
#define OMV_FB_ALLOC_SIZE (80K) // minimum fb alloc size
|
||||
#define OMV_JPEG_MEMORY SRAM0 // JPEG buffer memory.
|
||||
#define OMV_JPEG_SIZE (32K) // IDE JPEG buffer (header + data).
|
||||
#define OMV_VOSPI_MEMORY SRAM4 // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (38K)
|
||||
#define OMV_DMA_MEMORY SRAM2 // Misc DMA buffers memory.
|
||||
#define OMV_GC_BLOCK0_MEMORY SRAM4 // Main GC block.
|
||||
#define OMV_GC_BLOCK0_SIZE (26K)
|
||||
#define OMV_GC_BLOCK0_SIZE (64K)
|
||||
#define OMV_GC_BLOCK1_MEMORY SRAM1 // Extra GC block 0.
|
||||
#define OMV_GC_BLOCK1_SIZE (267K)
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_LINE_BUF_SIZE (3 * 1024) // Image line buffer round(640 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -126,8 +126,6 @@
|
||||
#define OMV_FB_OVERLAY_SIZE (496K) // Fast fb_alloc memory size.
|
||||
#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer.
|
||||
#define OMV_JPEG_SIZE (1M) // IDE JPEG buffer (header + data).
|
||||
#define OMV_VOSPI_MEMORY SRAM4 // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (38K)
|
||||
#define OMV_DMA_MEMORY SRAM3 // Misc DMA buffers memory.
|
||||
#define OMV_DMA_MEMORY_D1 SRAM0 // Domain 1 DMA buffers.
|
||||
#define OMV_DMA_MEMORY_D2 SRAM3 // Domain 2 DMA buffers.
|
||||
@ -139,6 +137,7 @@
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_SDRAM_SIZE (32 * 1024 * 1024) // This needs to be here for UVC firmware.
|
||||
#define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer round(2592 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -117,8 +117,6 @@
|
||||
#define OMV_FB_OVERLAY_SIZE (496K) // Fast fb_alloc memory size.
|
||||
#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer.
|
||||
#define OMV_JPEG_SIZE (1M) // IDE JPEG buffer (header + data).
|
||||
#define OMV_VOSPI_MEMORY SRAM4 // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (38K)
|
||||
#define OMV_DMA_MEMORY SRAM3 // DMA buffers memory.
|
||||
#define OMV_DMA_MEMORY_D1 SRAM0 // Domain 1 DMA buffers.
|
||||
#define OMV_DMA_MEMORY_D2 SRAM3 // Domain 2 DMA buffers.
|
||||
@ -130,6 +128,7 @@
|
||||
#define OMV_SDRAM_SIZE (64 * 1024 * 1024) // This needs to be here for UVC firmware.
|
||||
#define OMV_MSC_BUF_SIZE (2K) // USB MSC bot data
|
||||
#define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer round(2592 * 2BPP * 2 buffers).
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_FLASH_ORIGIN 0x08000000
|
||||
|
||||
@ -153,14 +153,14 @@
|
||||
#define OMV_FB_ALLOC_SIZE (11M) // minimum fb_alloc size
|
||||
#define OMV_JPEG_MEMORY DRAM // JPEG buffer memory buffer.
|
||||
#define OMV_JPEG_SIZE (1M) // IDE JPEG buffer (header + data).
|
||||
#define OMV_VOSPI_MEMORY SRAM1 // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (64K)
|
||||
#define OMV_DMA_MEMORY SRAM1 // Misc DMA buffers memory.
|
||||
#define OMV_DMA_MEMORY_D2 SRAM7 // Domain 2 DMA buffers.
|
||||
#define OMV_GC_BLOCK0_MEMORY SRAM2 // Main GC block
|
||||
#define OMV_GC_BLOCK0_SIZE (1M)
|
||||
#define OMV_GC_BLOCK1_MEMORY DRAM // Main GC block
|
||||
#define OMV_GC_BLOCK1_SIZE (24M)
|
||||
#define OMV_MSC_BUF_SIZE (4K) // USB MSC bot data
|
||||
#define OMV_VOSPI_DMA_BUFFER ".d2_dma_buffer"
|
||||
|
||||
// Memory map.
|
||||
#define OMV_DTCM_ORIGIN 0x30000000
|
||||
|
||||
@ -84,17 +84,16 @@
|
||||
#define OMV_FB_ALLOC_SIZE (10M) // minimum fb alloc size
|
||||
#define OMV_FB_OVERLAY_MEMORY OCRM1 // Fast fb_alloc memory.
|
||||
#define OMV_FB_OVERLAY_SIZE (512K)
|
||||
#define OMV_VOSPI_MEMORY OCRM2 // VoSPI buffer memory.
|
||||
#define OMV_VOSPI_SIZE (38K)
|
||||
#define OMV_DMA_MEMORY DTCM // Misc DMA buffers memory.
|
||||
#define OMV_GC_BLOCK0_MEMORY OCRM2 // Extra GC block 0.
|
||||
#define OMV_GC_BLOCK0_SIZE (26K)
|
||||
#define OMV_GC_BLOCK0_SIZE (64K)
|
||||
#define OMV_GC_BLOCK1_MEMORY DTCM // Main GC block
|
||||
#define OMV_GC_BLOCK1_SIZE (288K)
|
||||
#define OMV_GC_BLOCK2_MEMORY DRAM // Extra GC block 1.
|
||||
#define OMV_GC_BLOCK2_SIZE (8M)
|
||||
#define OMV_RAMFUNC_MEMORY ITCM2 // RAM code memory.
|
||||
#define OMV_LINE_BUF_SIZE (11 * 1024) // Image line buffer.
|
||||
#define OMV_VOSPI_DMA_BUFFER ".dma_buffer"
|
||||
|
||||
// Memory configuration.
|
||||
#define OMV_DTCM_ORIGIN 0x20000000
|
||||
|
||||
@ -133,17 +133,6 @@ PROVIDE(__stack = __StackTop);
|
||||
} >OMV_JPEG_MEMORY
|
||||
#endif
|
||||
|
||||
/* VOSPI framebuffer memory */
|
||||
#if defined(OMV_VOSPI_MEMORY)
|
||||
.vospi_memory (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_vospi_buf = .;
|
||||
. = . + OMV_VOSPI_SIZE;
|
||||
. = ALIGN(4);
|
||||
} >OMV_VOSPI_MEMORY
|
||||
#endif
|
||||
|
||||
/* GPU memory */
|
||||
#if defined(OMV_GPU_MEMORY)
|
||||
.gpu_memory (NOLOAD) :
|
||||
|
||||
@ -60,7 +60,7 @@ typedef enum {
|
||||
typedef struct _vospi_state {
|
||||
int pid;
|
||||
int sid;
|
||||
uint16_t *framebuffer;
|
||||
framebuffer_t *fb;
|
||||
bool lepton_3;
|
||||
omv_spi_t spi_bus;
|
||||
volatile uint32_t flags;
|
||||
@ -68,7 +68,7 @@ typedef struct _vospi_state {
|
||||
|
||||
static vospi_state_t vospi;
|
||||
|
||||
static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(vospi_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer");
|
||||
static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(vospi_buf[VOSPI_BUFFER_SIZE]), OMV_VOSPI_DMA_BUFFER);
|
||||
static void vospi_callback(omv_spi_t *spi, void *userdata, void *buf);
|
||||
|
||||
static void vospi_resync() {
|
||||
@ -143,33 +143,39 @@ void vospi_callback(omv_spi_t *spi, void *userdata, void *buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(vospi.framebuffer
|
||||
+ (vospi.pid * VOSPI_PID_SIZE_PIXELS)
|
||||
+ (vospi.sid * VOSPI_SID_SIZE_PIXELS),
|
||||
base + VOSPI_HEADER_WORDS, VOSPI_PID_SIZE_PIXELS * sizeof(uint16_t));
|
||||
vbuffer_t *buffer = framebuffer_get_tail(vospi.fb, FB_PEEK);
|
||||
|
||||
vospi.pid += 1;
|
||||
if (vospi.pid == VOSPI_PIDS_PER_SID) {
|
||||
vospi.pid = 0;
|
||||
if (buffer) {
|
||||
memcpy(((uint16_t *) buffer->data)
|
||||
+ (vospi.pid * VOSPI_PID_SIZE_PIXELS)
|
||||
+ (vospi.sid * VOSPI_SID_SIZE_PIXELS),
|
||||
base + VOSPI_HEADER_WORDS, VOSPI_PID_SIZE_PIXELS * sizeof(uint16_t));
|
||||
|
||||
// For the FLIR Lepton 3 we have to receive all the pids in all the segments.
|
||||
if (vospi.lepton_3) {
|
||||
vospi.sid += 1;
|
||||
if (vospi.sid == VOSPI_SIDS_PER_FRAME) {
|
||||
vospi.sid = 0;
|
||||
vospi.flags &= ~VOSPI_FLAGS_CAPTURE;
|
||||
vospi.pid += 1;
|
||||
if (vospi.pid == VOSPI_PIDS_PER_SID) {
|
||||
vospi.pid = 0;
|
||||
|
||||
// For the FLIR Lepton 3 we have to receive all the pids in all the segments.
|
||||
if (vospi.lepton_3) {
|
||||
vospi.sid += 1;
|
||||
if (vospi.sid == VOSPI_SIDS_PER_FRAME) {
|
||||
vospi.sid = 0;
|
||||
framebuffer_get_tail(vospi.fb, FB_NO_FLAGS);
|
||||
}
|
||||
// For the FLIR Lepton 1/2 we just have to receive all the pids.
|
||||
} else {
|
||||
framebuffer_get_tail(vospi.fb, FB_NO_FLAGS);
|
||||
}
|
||||
// For the FLIR Lepton 1/2 we just have to receive all the pids.
|
||||
} else {
|
||||
vospi.flags &= ~VOSPI_FLAGS_CAPTURE;
|
||||
}
|
||||
} else {
|
||||
vospi.flags &= ~VOSPI_FLAGS_CAPTURE;
|
||||
}
|
||||
}
|
||||
|
||||
int vospi_init(uint32_t n_packets, void *buffer) {
|
||||
int vospi_init(uint32_t n_packets, framebuffer_t *fb) {
|
||||
memset(&vospi, 0, sizeof(vospi_state_t));
|
||||
vospi.lepton_3 = n_packets > VOSPI_PIDS_PER_SID;
|
||||
vospi.framebuffer = buffer;
|
||||
vospi.fb = fb;
|
||||
// resync on first snapshot.
|
||||
vospi.flags = VOSPI_FLAGS_RESYNC;
|
||||
|
||||
@ -183,15 +189,26 @@ int vospi_init(uint32_t n_packets, void *buffer) {
|
||||
spi_config.clk_pha = OMV_SPI_CPHA_2EDGE;
|
||||
spi_config.dma_flags = OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE;
|
||||
|
||||
if (omv_spi_init(&vospi.spi_bus, &spi_config) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return omv_spi_init(&vospi.spi_bus, &spi_config);
|
||||
}
|
||||
|
||||
int vospi_deinit() {
|
||||
return omv_spi_deinit(&vospi.spi_bus);
|
||||
}
|
||||
|
||||
bool vospi_active(void) {
|
||||
return vospi.flags & VOSPI_FLAGS_CAPTURE;
|
||||
}
|
||||
|
||||
int vospi_snapshot(uint32_t timeout_ms) {
|
||||
// Restart counters to capture a new frame.
|
||||
vospi.flags |= VOSPI_FLAGS_CAPTURE;
|
||||
framebuffer_free_current_buffer(vospi.fb);
|
||||
|
||||
if (!(vospi.flags & VOSPI_FLAGS_CAPTURE)) {
|
||||
framebuffer_setup_buffers(vospi.fb);
|
||||
|
||||
// Restart counters to capture a new frame.
|
||||
vospi.flags |= VOSPI_FLAGS_CAPTURE;
|
||||
}
|
||||
|
||||
// Snapshot start tick
|
||||
mp_uint_t tick_start = mp_hal_ticks_ms();
|
||||
@ -202,6 +219,10 @@ int vospi_snapshot(uint32_t timeout_ms) {
|
||||
vospi_resync();
|
||||
}
|
||||
|
||||
if (timeout_ms == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((mp_hal_ticks_ms() - tick_start) > timeout_ms) {
|
||||
omv_spi_transfer_abort(&vospi.spi_bus);
|
||||
vospi.pid = 0;
|
||||
@ -211,9 +232,8 @@ int vospi_snapshot(uint32_t timeout_ms) {
|
||||
}
|
||||
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
} while (vospi.flags & VOSPI_FLAGS_CAPTURE);
|
||||
} while (!framebuffer_get_head(vospi.fb, FB_NO_FLAGS));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -25,6 +25,9 @@
|
||||
*/
|
||||
#ifndef __VOSPI_H__
|
||||
#define __VOSPI_H__
|
||||
int vospi_init(uint32_t n_packets, void *buffer);
|
||||
#include "framebuffer.h"
|
||||
int vospi_init(uint32_t n_packets, framebuffer_t *fb);
|
||||
int vospi_deinit();
|
||||
bool vospi_active(void);
|
||||
int vospi_snapshot(uint32_t timeout_ms);
|
||||
#endif // __VOSPI_H__
|
||||
|
||||
@ -69,7 +69,6 @@ typedef struct lepton_state {
|
||||
LEP_CAMERA_PORT_DESC_T port;
|
||||
} lepton_state_t;
|
||||
|
||||
extern uint16_t _vospi_buf[];
|
||||
static lepton_state_t lepton;
|
||||
|
||||
static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mode);
|
||||
@ -202,7 +201,7 @@ static int ioctl(omv_csi_t *csi, int request, va_list ap) {
|
||||
}
|
||||
case OMV_CSI_IOCTL_LEPTON_GET_RESOLUTION: {
|
||||
int *resolution = va_arg(ap, int *);
|
||||
*resolution = 14;
|
||||
*resolution = lepton.radiometry ? 16 : 14;
|
||||
break;
|
||||
}
|
||||
case OMV_CSI_IOCTL_LEPTON_RUN_COMMAND: {
|
||||
@ -359,21 +358,21 @@ static int lepton_reset(omv_csi_t *csi, bool measurement_mode, bool high_temp_mo
|
||||
}
|
||||
|
||||
static int reset(omv_csi_t *csi) {
|
||||
static bool vospi_initialized = false;
|
||||
vospi_deinit();
|
||||
|
||||
memset(&lepton, 0, sizeof(lepton_state_t));
|
||||
lepton.min_temp = LEPTON_MIN_TEMP_DEFAULT;
|
||||
lepton.max_temp = LEPTON_MAX_TEMP_DEFAULT;
|
||||
|
||||
// Extra delay after power-on
|
||||
mp_hal_delay_ms(1000);
|
||||
|
||||
if (lepton_reset(csi, false, false) != 0) {
|
||||
return OMV_CSI_ERROR_CTL_FAILED;
|
||||
}
|
||||
|
||||
if (vospi_initialized == false) {
|
||||
if (vospi_init(lepton.v_res, _vospi_buf) != 0) {
|
||||
return OMV_CSI_ERROR_CTL_FAILED;
|
||||
}
|
||||
vospi_initialized = true;
|
||||
if (csi->fb && vospi_init(lepton.v_res, csi->fb) != 0) {
|
||||
return OMV_CSI_ERROR_CTL_FAILED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -383,10 +382,6 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||
framebuffer_t *fb = csi->fb;
|
||||
framebuffer_update_jpeg_buffer(fb);
|
||||
|
||||
if (fb->n_buffers != 1) {
|
||||
framebuffer_set_buffers(fb, 1);
|
||||
}
|
||||
|
||||
if (csi->pixformat == PIXFORMAT_INVALID) {
|
||||
return OMV_CSI_ERROR_INVALID_PIXFORMAT;
|
||||
}
|
||||
@ -399,15 +394,12 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||
}
|
||||
|
||||
if (omv_csi_check_framebuffer_size(csi) == -1) {
|
||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||
if (resolution[csi->framesize][0] < lepton.h_res || resolution[csi->framesize][1] < lepton.v_res) {
|
||||
return OMV_CSI_ERROR_INVALID_FRAMESIZE;
|
||||
}
|
||||
|
||||
framebuffer_free_current_buffer(fb);
|
||||
vbuffer_t *buffer = framebuffer_get_tail(fb, FB_NO_FLAGS);
|
||||
|
||||
if (!buffer) {
|
||||
return OMV_CSI_ERROR_FRAMEBUFFER_ERROR;
|
||||
if (omv_csi_check_framebuffer_size(csi) == -1) {
|
||||
return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LEPTON_SNAPSHOT_RETRY; i++) {
|
||||
@ -423,20 +415,18 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||
}
|
||||
}
|
||||
|
||||
fb->w = fb->u;
|
||||
fb->h = fb->v;
|
||||
if (!csi->transpose) {
|
||||
fb->w = fb->u;
|
||||
fb->h = fb->v;
|
||||
} else {
|
||||
fb->w = fb->v;
|
||||
fb->h = fb->u;
|
||||
}
|
||||
|
||||
fb->pixfmt = csi->pixformat;
|
||||
|
||||
framebuffer_init_image(fb, image);
|
||||
|
||||
float x_scale = resolution[csi->framesize][0] / ((float) lepton.h_res);
|
||||
float y_scale = resolution[csi->framesize][1] / ((float) lepton.v_res);
|
||||
// MAX == KeepAspectRationByExpanding - MIN == KeepAspectRatio
|
||||
float scale = IM_MAX(x_scale, y_scale), scale_inv = 1.0f / scale;
|
||||
int x_offset = (resolution[csi->framesize][0] - (lepton.h_res * scale)) / 2;
|
||||
int y_offset = (resolution[csi->framesize][1] - (lepton.v_res * scale)) / 2;
|
||||
// The code below upscales the source image to the requested frame size
|
||||
// and then crops it to the window set by the user.
|
||||
image_t fb_image;
|
||||
framebuffer_init_image(fb, &fb_image);
|
||||
|
||||
LEP_SYS_FPA_TEMPERATURE_KELVIN_T kelvin;
|
||||
if (lepton.measurement_mode && (!lepton.radiometry)) {
|
||||
@ -444,60 +434,38 @@ static int snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
||||
return OMV_CSI_ERROR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
fb_alloc_mark();
|
||||
image_t temp = {
|
||||
.w = (!csi->transpose) ? lepton.h_res : lepton.v_res,
|
||||
.h = (!csi->transpose) ? lepton.v_res : lepton.h_res,
|
||||
.pixfmt = PIXFORMAT_GRAYSCALE,
|
||||
.data = fb_alloc(lepton.h_res * lepton.v_res, FB_ALLOC_CACHE_ALIGN),
|
||||
};
|
||||
|
||||
for (int y = y_offset, yy = fast_ceilf(lepton.v_res * scale) + y_offset; y < yy; y++) {
|
||||
if ((fb->y <= y) && (y < (fb->y + fb->v))) {
|
||||
// user window cropping
|
||||
// When not in measurment mode set the min and max temperatures such that 0-255 values from the
|
||||
// sensor, which are grayscale pixels 0-255, are not clipped when interpreted as Kelvin values.
|
||||
float min = -273.15f; // in Celsius -> 0.0f in Kelvin
|
||||
float max = -270.6f; // in Celsius -> 2.55f in Kelvin
|
||||
|
||||
uint16_t *row_ptr = _vospi_buf + (fast_floorf(y * scale_inv) * lepton.h_res);
|
||||
|
||||
for (int x = x_offset, xx = fast_ceilf(lepton.h_res * scale) + x_offset; x < xx; x++) {
|
||||
if ((fb->x <= x) && (x < (fb->x + fb->u))) {
|
||||
// user window cropping
|
||||
|
||||
// Value is the 14/16-bit value from the FLIR IR camera.
|
||||
// However, with AGC enabled only the bottom 8-bits are non-zero.
|
||||
int value = row_ptr[fast_floorf(x * scale_inv)];
|
||||
|
||||
if (lepton.measurement_mode) {
|
||||
// Need to convert 14/16-bits to 8-bits ourselves...
|
||||
if (!lepton.radiometry) {
|
||||
value = (value - 8192) + kelvin;
|
||||
}
|
||||
float celsius = (value * 0.01f) - 273.15f;
|
||||
celsius = IM_CLAMP(celsius, lepton.min_temp, lepton.max_temp);
|
||||
value = __USAT(IM_DIV(((celsius - lepton.min_temp) * 255),
|
||||
(lepton.max_temp - lepton.min_temp)), 8);
|
||||
}
|
||||
|
||||
int t_x = x - fb->x;
|
||||
int t_y = y - fb->y;
|
||||
|
||||
if (lepton.hmirror) {
|
||||
t_x = fb->u - t_x - 1;
|
||||
}
|
||||
if (lepton.vflip) {
|
||||
t_y = fb->v - t_y - 1;
|
||||
}
|
||||
|
||||
switch (csi->pixformat) {
|
||||
case PIXFORMAT_GRAYSCALE: {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL(image, t_x, t_y, value & 0xFF);
|
||||
break;
|
||||
}
|
||||
case PIXFORMAT_RGB565: {
|
||||
IMAGE_PUT_RGB565_PIXEL(image, t_x, t_y, csi->color_palette[value & 0xFF]);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// When in measurment mode the lepton provides 14-bit or 16-bit values that must be clamped
|
||||
// between the min and max temperatures in celsius and scaled to 0-255 values.
|
||||
if (lepton.measurement_mode) {
|
||||
min = lepton.min_temp;
|
||||
max = lepton.max_temp;
|
||||
}
|
||||
|
||||
imlib_fill_image_from_lepton(&temp, lepton.h_res, lepton.v_res, (uint16_t *) fb_image.data, min, max,
|
||||
false, (!lepton.measurement_mode) || lepton.radiometry, kelvin,
|
||||
lepton.hmirror, lepton.vflip, csi->transpose);
|
||||
|
||||
imlib_draw_image(&fb_image, &temp, 0, 0, 1.0f, 1.0f, NULL, -1, 255,
|
||||
(csi->pixformat == PIXFORMAT_RGB565) ? csi->color_palette : NULL, NULL,
|
||||
IMAGE_HINT_BILINEAR | IMAGE_HINT_CENTER | IMAGE_HINT_SCALE_ASPECT_EXPAND,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
fb_alloc_free_till_mark();
|
||||
framebuffer_init_image(fb, image);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -456,6 +456,76 @@ void imlib_fill_image_from_float(image_t *img, int w, int h, float *data, float
|
||||
}
|
||||
}
|
||||
|
||||
// This function fills a grayscale image from an array of lepton 8/14/16-bit values that are scaled
|
||||
// between min and max. The image w*h must equal the floating point array w*h.
|
||||
void imlib_fill_image_from_lepton(image_t *img, int w, int h, uint16_t *data, float min, float max,
|
||||
bool auto_range, bool radiometric, int kelvin_offset,
|
||||
bool mirror, bool flip, bool transpose) {
|
||||
int new_min;
|
||||
int new_max;
|
||||
|
||||
if (auto_range) {
|
||||
new_min = INT_MAX;
|
||||
new_max = INT_MIN;
|
||||
|
||||
for (int i = 0; i < w * h; i++) {
|
||||
int temp = data[i];
|
||||
|
||||
if (!radiometric) {
|
||||
temp = (temp - 8192) + kelvin_offset;
|
||||
}
|
||||
|
||||
if (temp < new_min) {
|
||||
new_min = temp;
|
||||
}
|
||||
|
||||
if (temp > new_max) {
|
||||
new_max = temp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float tmp = min;
|
||||
min = (min < max) ? min : max;
|
||||
max = (max > tmp) ? max : tmp;
|
||||
new_min = fast_roundf((min + 273.15f) * 100.f); // to kelvin
|
||||
new_max = fast_roundf((max + 273.15f) * 100.f); // to kelvin
|
||||
}
|
||||
|
||||
float diff = 255.f / (new_max - new_min);
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
int y_dst = flip ? (h - 1 - y) : y;
|
||||
const uint16_t *raw_row = data + (y * w);
|
||||
uint8_t *row_pointer = ((uint8_t *) img->data) + (y_dst * w);
|
||||
uint8_t *t_row_pointer = ((uint8_t *) img->data) + y_dst;
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
int x_dst = mirror ? (w - 1 - x) : x;
|
||||
int raw = raw_row[x];
|
||||
|
||||
if (!radiometric) {
|
||||
raw = (raw - 8192) + kelvin_offset;
|
||||
}
|
||||
|
||||
if (raw < new_min) {
|
||||
raw = new_min;
|
||||
}
|
||||
|
||||
if (raw > new_max) {
|
||||
raw = new_max;
|
||||
}
|
||||
|
||||
int pixel = __USAT(fast_roundf((raw - new_min) * diff), 8);
|
||||
|
||||
if (!transpose) {
|
||||
row_pointer[x_dst] = pixel;
|
||||
} else {
|
||||
t_row_pointer[x_dst * h] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t imlib_rgb565_to_l(uint16_t pixel) {
|
||||
float r_lin = xyz_table[COLOR_RGB565_TO_R8(pixel)];
|
||||
float g_lin = xyz_table[COLOR_RGB565_TO_G8(pixel)];
|
||||
|
||||
@ -1187,6 +1187,9 @@ void imlib_deinit_all();
|
||||
// Generic Helper Functions
|
||||
void imlib_fill_image_from_float(image_t *img, int w, int h, float *data, float min, float max,
|
||||
bool mirror, bool flip, bool dst_transpose, bool src_transpose);
|
||||
void imlib_fill_image_from_lepton(image_t *img, int w, int h, uint16_t *data, float min, float max,
|
||||
bool auto_range, bool radiometric, int kelvin_offset,
|
||||
bool mirror, bool flip, bool transpose);
|
||||
|
||||
// Bayer Image Processing
|
||||
pixformat_t imlib_bayer_shift(pixformat_t pixfmt, int x, int y, bool transpose);
|
||||
|
||||
@ -1089,9 +1089,10 @@ mp_obj_t py_fir_snapshot(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
|
||||
#if (OMV_FIR_LEPTON_ENABLE == 1)
|
||||
case FIR_LEPTON: {
|
||||
bool auto_range = args[ARG_scale].u_obj == mp_const_none;
|
||||
fir_lepton_fill_image(&src_img, fir_width, fir_height, auto_range, min, max,
|
||||
args[ARG_hmirror].u_bool, args[ARG_vflip].u_bool,
|
||||
args[ARG_transpose].u_bool, args[ARG_timeout].u_int);
|
||||
imlib_fill_image_from_lepton(&src_img, fir_width, fir_height,
|
||||
fir_lepton_get_frame(args[ARG_timeout].u_int), min, max, auto_range,
|
||||
fir_lepton_get_radiometry_enabled(), fir_lepton_get_temperature(),
|
||||
args[ARG_hmirror].u_bool, args[ARG_vflip].u_bool, args[ARG_transpose].u_bool);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -81,7 +81,7 @@ static soft_timer_entry_t flir_lepton_spi_rx_timer = {};
|
||||
static int fir_lepton_spi_rx_cb_tail = 0;
|
||||
static int fir_lepton_spi_rx_cb_expected_pid = 0;
|
||||
static int fir_lepton_spi_rx_cb_expected_sid = 0;
|
||||
static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(fir_lepton_buf[VOSPI_BUFFER_SIZE]), ".dma_buffer");
|
||||
static uint16_t OMV_ATTR_SECTION(OMV_ATTR_ALIGNED_DMA(fir_lepton_buf[VOSPI_BUFFER_SIZE]), OMV_VOSPI_DMA_BUFFER);
|
||||
static void fir_lepton_spi_callback(omv_spi_t *spi, void *userdata, void *buf);
|
||||
|
||||
static mp_obj_t fir_lepton_spi_resync_callback(mp_obj_t unused) {
|
||||
@ -390,7 +390,7 @@ int fir_lepton_init(omv_i2c_t *bus, int *w, int *h, int *refresh, int *resolutio
|
||||
fir_lepton_rad_en = rad == LEP_RAD_ENABLE;
|
||||
*w = flir_w;
|
||||
*h = flir_h;
|
||||
*refresh = fir_lepton_3 ? 27 : 9;
|
||||
*refresh = fir_lepton_3 ? 9 : 27;
|
||||
*resolution = fir_lepton_rad_en ? 16 : 14;
|
||||
|
||||
#if defined(OMV_FIR_LEPTON_VSYNC_PIN)
|
||||
@ -441,7 +441,7 @@ mp_obj_t fir_lepton_get_frame_available() {
|
||||
return mp_obj_new_bool(framebuffer_tail != framebuffer_head);
|
||||
}
|
||||
|
||||
static const uint16_t *fir_lepton_get_frame(int timeout) {
|
||||
uint16_t *fir_lepton_get_frame(int timeout) {
|
||||
int sampled_framebuffer_tail = framebuffer_tail;
|
||||
|
||||
if (timeout >= 0) {
|
||||
@ -464,7 +464,11 @@ static const uint16_t *fir_lepton_get_frame(int timeout) {
|
||||
return framebuffers[sampled_framebuffer_tail];
|
||||
}
|
||||
|
||||
static int fir_lepton_get_temperature() {
|
||||
bool fir_lepton_get_radiometry_enabled() {
|
||||
return fir_lepton_rad_en;
|
||||
}
|
||||
|
||||
int fir_lepton_get_temperature() {
|
||||
LEP_SYS_FPA_TEMPERATURE_KELVIN_T kelvin;
|
||||
|
||||
if (LEP_GetSysFpaTemperatureKelvin(&fir_lepton_handle, &kelvin) != LEP_OK) {
|
||||
@ -529,78 +533,6 @@ mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose
|
||||
return mp_obj_new_tuple(4, tuple);
|
||||
}
|
||||
|
||||
void fir_lepton_fill_image(image_t *img, int w, int h, bool auto_range, float min, float max,
|
||||
bool mirror, bool flip, bool transpose, int timeout) {
|
||||
int kelvin = fir_lepton_get_temperature();
|
||||
const uint16_t *data = fir_lepton_get_frame(timeout);
|
||||
int new_min;
|
||||
int new_max;
|
||||
|
||||
if (auto_range) {
|
||||
new_min = INT_MAX;
|
||||
new_max = INT_MIN;
|
||||
|
||||
for (int i = 0, ii = w * h; i < ii; i++) {
|
||||
int temp = data[i];
|
||||
|
||||
if (!fir_lepton_rad_en) {
|
||||
temp = (temp - 8192) + kelvin;
|
||||
}
|
||||
|
||||
if (temp < new_min) {
|
||||
new_min = temp;
|
||||
}
|
||||
|
||||
if (temp > new_max) {
|
||||
new_max = temp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float tmp = min;
|
||||
min = (min < max) ? min : max;
|
||||
max = (max > tmp) ? max : tmp;
|
||||
new_min = fast_roundf((min + 273.15f) * 100.f); // to kelvin
|
||||
new_max = fast_roundf((max + 273.15f) * 100.f); // to kelvin
|
||||
}
|
||||
|
||||
float diff = 255.f / (new_max - new_min);
|
||||
int w_1 = w - 1;
|
||||
int h_1 = h - 1;
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
int y_dst = flip ? (h_1 - y) : y;
|
||||
const uint16_t *raw_row = data + (y * w);
|
||||
uint8_t *row_pointer = ((uint8_t *) img->data) + (y_dst * w);
|
||||
uint8_t *t_row_pointer = ((uint8_t *) img->data) + y_dst;
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
int x_dst = mirror ? (w_1 - x) : x;
|
||||
int raw = raw_row[x];
|
||||
|
||||
if (!fir_lepton_rad_en) {
|
||||
raw = (raw - 8192) + kelvin;
|
||||
}
|
||||
|
||||
if (raw < new_min) {
|
||||
raw = new_min;
|
||||
}
|
||||
|
||||
if (raw > new_max) {
|
||||
raw = new_max;
|
||||
}
|
||||
|
||||
int pixel = fast_roundf((raw - new_min) * diff);
|
||||
pixel = __USAT(pixel, 8);
|
||||
|
||||
if (!transpose) {
|
||||
row_pointer[x_dst] = pixel;
|
||||
} else {
|
||||
t_row_pointer[x_dst * h] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fir_lepton_trigger_ffc(int timeout) {
|
||||
if (LEP_RunSysFFCNormalization(&fir_lepton_handle) != LEP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("FFC Error!"));
|
||||
|
||||
@ -31,9 +31,10 @@ void fir_lepton_register_vsync_cb(mp_obj_t cb);
|
||||
mp_obj_t fir_lepton_get_radiometry();
|
||||
void fir_lepton_register_frame_cb(mp_obj_t cb);
|
||||
mp_obj_t fir_lepton_get_frame_available();
|
||||
uint16_t *fir_lepton_get_frame(int timeout);
|
||||
bool fir_lepton_get_radiometry_enabled();
|
||||
int fir_lepton_get_temperature();
|
||||
mp_obj_t fir_lepton_read_ta();
|
||||
mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose, int timeout);
|
||||
void fir_lepton_fill_image(image_t *img, int w, int h, bool auto_range, float min, float max,
|
||||
bool mirror, bool flip, bool transpose, int timeout);
|
||||
void fir_lepton_trigger_ffc(int timeout);
|
||||
#endif // __PY_FIR_LEPTON_H__
|
||||
|
||||
@ -75,6 +75,7 @@
|
||||
#include "file_utils.h"
|
||||
#include "mp_utils.h"
|
||||
#include "mimxrt_hal.h"
|
||||
#include "vospi.h"
|
||||
|
||||
int main(void) {
|
||||
bool first_soft_reset = true;
|
||||
@ -222,6 +223,9 @@ soft_reset:
|
||||
|
||||
soft_reset_exit:
|
||||
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
|
||||
#if OMV_ENABLE_VOSPI || OMV_LEPTON_ENABLE
|
||||
vospi_deinit();
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_CAN
|
||||
machine_can_irq_deinit();
|
||||
#endif
|
||||
|
||||
@ -88,6 +88,7 @@
|
||||
#include "fb_alloc.h"
|
||||
#include "dma_alloc.h"
|
||||
#include "file_utils.h"
|
||||
#include "vospi.h"
|
||||
|
||||
#include "py_image.h"
|
||||
#include "py_fir.h"
|
||||
@ -373,6 +374,9 @@ soft_reset_exit:
|
||||
// soft reset
|
||||
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
|
||||
|
||||
#if OMV_ENABLE_VOSPI || OMV_LEPTON_ENABLE
|
||||
vospi_deinit();
|
||||
#endif
|
||||
#if MICROPY_PY_LWIP
|
||||
systick_disable_dispatch(SYSTICK_DISPATCH_LWIP);
|
||||
#endif
|
||||
|
||||
@ -95,7 +95,7 @@ DEFINE_SPI_INSTANCE(6)
|
||||
|
||||
static omv_spi_t *omv_spi_descr_all[6] = { NULL };
|
||||
#if defined(STM32N6)
|
||||
static DMA_NodeTypeDef OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(omv_dma_nodes_all[6 * 2], 32), ".dma_buffer");
|
||||
static DMA_NodeTypeDef OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(omv_dma_nodes_all[6 * 2], 32), OMV_VOSPI_DMA_BUFFER);
|
||||
#endif
|
||||
|
||||
static uint32_t omv_spi_clocksource(SPI_TypeDef *spi) {
|
||||
@ -330,8 +330,8 @@ static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t
|
||||
dma_init->Direction = direction;
|
||||
dma_init->SrcInc = (direction == DMA_PERIPH_TO_MEMORY) ? DMA_SINC_FIXED : DMA_SINC_INCREMENTED;
|
||||
dma_init->DestInc = (direction == DMA_MEMORY_TO_PERIPH) ? DMA_DINC_FIXED : DMA_DINC_INCREMENTED;
|
||||
dma_init->SrcDataWidth = (config->datasize == 8) ? DMA_SRC_DATAWIDTH_BYTE : DMA_SRC_DATAWIDTH_WORD;
|
||||
dma_init->DestDataWidth = (config->datasize == 8) ? DMA_DEST_DATAWIDTH_BYTE : DMA_DEST_DATAWIDTH_WORD;
|
||||
dma_init->SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
|
||||
dma_init->DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
|
||||
dma_init->SrcBurstLength = 1;
|
||||
dma_init->DestBurstLength = 1;
|
||||
dma_init->TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
|
||||
@ -368,7 +368,7 @@ static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t
|
||||
return -1;
|
||||
}
|
||||
|
||||
dma_descr->InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
|
||||
dma_descr->InitLinkedList.Priority = DMA_HIGH_PRIORITY;
|
||||
dma_descr->InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
|
||||
dma_descr->InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
|
||||
dma_descr->InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user