From efaeb1c89a7b29708c744060c6fa18e4e95208cc Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 15 Jan 2021 23:24:54 +0200 Subject: [PATCH 1/6] Update Himax driver. * Fix default registers. * Set default registers on reset/boot. --- libraries/Himax_HM01B0/himax.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/Himax_HM01B0/himax.cpp b/libraries/Himax_HM01B0/himax.cpp index fcf588407..95e9e4312 100644 --- a/libraries/Himax_HM01B0/himax.cpp +++ b/libraries/Himax_HM01B0/himax.cpp @@ -157,7 +157,7 @@ static regval_list_t himax_default_regs[] = { {0x3010, 0x01}, // 324 x 244 pixel {0x0383, 0x01}, {0x0387, 0x01}, - {0x0390, 0x03}, + {0x0390, 0x00}, {0x3011, 0x70}, {0x3059, 0x02}, {0x3060, 0x00}, @@ -207,8 +207,11 @@ uint8_t HIMAX_Open(void) //printf("Model: %x:%x\n", HIMAX_RegRead(MODEL_ID_H), HIMAX_RegRead(MODEL_ID_L)); - if (HIMAX_Reset()!=0) return -1; - //HIMAX_Boot(); + if (HIMAX_Reset()!=0) { + return -1; + } + + HIMAX_Boot(); //For debugging camera Configuration //HIMAX_PrintReg(); HAL_Delay(200); @@ -284,13 +287,12 @@ static uint8_t HIMAX_Boot() uint32_t i; for(i = 0; i < (sizeof(himax_default_regs) / sizeof(regval_list_t)); i++) { - //printf("%d\n", i); HIMAX_RegWrite(himax_default_regs[i].reg_num, himax_default_regs[i].value); - //delay(1); } HIMAX_RegWrite(PCLK_POLARITY, (0x20 | PCLK_FALLING_EDGE)); + HIMAX_RegWrite(MODE_SELECT, HIMAX_Standby); return 0; } @@ -354,4 +356,4 @@ static uint8_t HIMAX_PrintReg() /** * @} - */ \ No newline at end of file + */ From 029b8f6e45b94732ca544121a3730ebcca92291a Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 15 Jan 2021 23:25:22 +0200 Subject: [PATCH 2/6] Update camera driver. * Fix broken DMA transfer. * Fix timer frequency (was running at 3MHz). * Fix cache issues. * Update API as requested. * Add skip_frames function. --- libraries/Portenta_Camera/camera.cpp | 105 ++++++++++++++------------- libraries/Portenta_Camera/camera.h | 7 +- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/libraries/Portenta_Camera/camera.cpp b/libraries/Portenta_Camera/camera.cpp index 28b80e00f..a391be6b7 100644 --- a/libraries/Portenta_Camera/camera.cpp +++ b/libraries/Portenta_Camera/camera.cpp @@ -7,8 +7,8 @@ #define LCD_FRAME_BUFFER 0xC0000000 /* LCD Frame buffer of size 800x480 in ARGB8888 */ #define CAMERA_FRAME_BUFFER 0xC0200000 -#define QVGA_RES_X 324 -#define QVGA_RES_Y 244 +#define QVGA_RES_X 320 +#define QVGA_RES_Y 240 #define ARGB8888_BYTE_PER_PIXEL 4 @@ -16,6 +16,7 @@ static uint32_t CameraResX = QVGA_RES_X; static uint32_t CameraResY = QVGA_RES_Y; static uint32_t LcdResX = 0; static uint32_t LcdResY = 0; +static uint32_t *user_buffer = 0; __IO uint32_t camera_frame_ready = 0; __IO uint32_t lcd_frame_ready = 0; @@ -92,11 +93,11 @@ void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params) hdma_handler.Init.MemInc = DMA_MINC_ENABLE; hdma_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_handler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; - hdma_handler.Init.Mode = DMA_CIRCULAR; + hdma_handler.Init.Mode = DMA_NORMAL; hdma_handler.Init.Priority = DMA_PRIORITY_HIGH; hdma_handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE; hdma_handler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_handler.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_handler.Init.MemBurst = DMA_MBURST_INC4; hdma_handler.Init.PeriphBurst = DMA_PBURST_SINGLE; hdma_handler.Instance = CAMERA_DCMI_DMAx_STREAM; @@ -193,6 +194,10 @@ uint8_t BSP_CAMERA_Init(uint32_t Resolution) phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_LOW; phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING; + phdcmi->Init.ByteSelectMode = DCMI_BSM_ALL; // Capture all received bytes + phdcmi->Init.ByteSelectStart = DCMI_OEBS_ODD; // Ignored + phdcmi->Init.LineSelectMode = DCMI_LSM_ALL; // Capture all received lines + phdcmi->Init.LineSelectStart = DCMI_OELS_ODD; // Ignored phdcmi->Instance = DCMI; /* Power up camera */ @@ -204,18 +209,16 @@ uint8_t BSP_CAMERA_Init(uint32_t Resolution) HAL_DCMI_Init(phdcmi); /* - * @param YSize DCMI Line number - * @param XSize DCMI Pixel per line * @param X0 DCMI window X offset * @param Y0 DCMI window Y offset + * @param XSize DCMI Pixel per line + * @param YSize DCMI Line number * @retval HAL status */ -//HAL_StatusTypeDef HAL_DCMI_ConfigCrop(DCMI_HandleTypeDef *hdcmi, uint32_t X0, uint32_t Y0, uint32_t XSize, uint32_t YSize) - - HAL_DCMI_ConfigCROP(phdcmi, (QVGA_RES_X - CameraResX) / 2, (QVGA_RES_Y - CameraResY / 2), CameraResX-1, CameraResY-1); HAL_DCMI_EnableCROP(phdcmi); + HAL_DCMI_ConfigCROP(phdcmi, (QVGA_RES_X - CameraResX) / 2, (QVGA_RES_Y - CameraResY) / 2, CameraResX-1, CameraResY-1); - //HAL_DCMI_DisableCROP(phdcmi); + __HAL_DCMI_DISABLE_IT(&hdcmi_discovery, DCMI_IT_LINE); CameraCurrentResolution = Resolution; @@ -239,17 +242,6 @@ uint8_t BSP_CAMERA_DeInit(void) return 1; } -/** - * @brief Starts the camera capture in continuous mode. - * @param buff: pointer to the camera output buffer - * @retval None - */ -void BSP_CAMERA_ContinuousStart(uint8_t *buff) -{ - /* Start the camera capture */ - HAL_DCMI_Start_DMA(&hdcmi_discovery, DCMI_MODE_CONTINUOUS, (uint32_t)buff, GetSize(CameraCurrentResolution)); -} - /** * @brief Starts the camera capture in snapshot mode. * @param buff: pointer to the camera output buffer @@ -257,8 +249,12 @@ void BSP_CAMERA_ContinuousStart(uint8_t *buff) */ void BSP_CAMERA_SnapshotStart(uint8_t *buff) { + user_buffer = (uint32_t*) buff; + + __HAL_DCMI_ENABLE_IT(&hdcmi_discovery, DCMI_IT_FRAME); + /* Start the camera capture */ - HAL_DCMI_Start_DMA(&hdcmi_discovery, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)); + HAL_DCMI_Start_DMA(&hdcmi_discovery, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)/4); } /** @@ -333,8 +329,8 @@ void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) static int extclk_config(int frequency) { - /* TCLK (PCLK * 2) */ - int tclk = DCMI_TIM_PCLK_FREQ() * 2; + /* TCLK (PCLK) */ + int tclk = DCMI_TIM_PCLK_FREQ(); /* Period should be even */ int period = (tclk / frequency) - 1; @@ -418,7 +414,7 @@ static uint32_t GetSize(uint32_t Resolution) break; case CAMERA_R320x240: { - size = 324 * 244; + size = 320 * 240; } break; case CAMERA_R480x272: @@ -450,7 +446,8 @@ void BSP_CAMERA_ErrorCallback(void) void BSP_CAMERA_FrameEventCallback(void) { - camera_frame_ready++; + camera_frame_ready++; + SCB_InvalidateDCache_by_Addr((uint32_t*)user_buffer, GetSize(CameraCurrentResolution)); } @@ -536,50 +533,57 @@ int CameraClass::begin(int horizontalResolution, int verticalResolution) { return -1; } + return 0; } -int CameraClass::start(uint32_t timeout) +int CameraClass::grab(uint8_t *buffer, uint32_t timeout) { HIMAX_Mode(HIMAX_Streaming); + BSP_CAMERA_Resume(); + /* Start the Camera Snapshot Capture */ - BSP_CAMERA_ContinuousStart((uint8_t *)LCD_FRAME_BUFFER); - uint32_t time =millis(); + BSP_CAMERA_SnapshotStart(buffer); + camera_frame_ready = 0; /* Wait until camera frame is ready : DCMI Frame event */ - while((camera_frame_ready == 0) && ((timeout+time)>millis())) - { + for (uint32_t start = millis(); camera_frame_ready == 0;) { + __WFI(); + if ((millis() - start) > timeout) { + HAL_DMA_Abort(hdcmi_discovery.DMA_Handle); + return -1; + } } - return camera_frame_ready ? 0: -1; -} -uint8_t* CameraClass::grab(void) -{ - //HIMAX_Mode(HIMAX_Streaming); + HIMAX_Mode(HIMAX_Standby); - /* Start the Camera Snapshot Capture */ - //BSP_CAMERA_ContinuousStart((uint8_t *)LCD_FRAME_BUFFER); + /* Stop the camera to avoid having the DMA2D work in parallel of Display */ + /* which cause perturbation of LTDC */ + BSP_CAMERA_Suspend(); - /* Wait until camera frame is ready : DCMI Frame event */ - while(camera_frame_ready == 0) - { - } - return (uint8_t *)LCD_FRAME_BUFFER; + return 0; } -uint8_t* CameraClass::snapshot(void) +int CameraClass::skip_frames(uint8_t *buffer, uint32_t n_frames, uint32_t timeout) { HIMAX_Mode(HIMAX_Streaming); BSP_CAMERA_Resume(); /* Start the Camera Snapshot Capture */ - BSP_CAMERA_SnapshotStart((uint8_t *)LCD_FRAME_BUFFER); - - /* Wait until camera frame is ready : DCMI Frame event */ - while(camera_frame_ready == 0) - { + BSP_CAMERA_SnapshotStart(buffer); + + while (n_frames--) { + camera_frame_ready = 0; + /* Wait until camera frame is ready : DCMI Frame event */ + for (uint32_t start = millis(); camera_frame_ready == 0;) { + __WFI(); + if ((millis() - start) > timeout) { + HAL_DMA_Abort(hdcmi_discovery.DMA_Handle); + return -1; + } + } } HIMAX_Mode(HIMAX_Standby); @@ -587,8 +591,7 @@ uint8_t* CameraClass::snapshot(void) /* Stop the camera to avoid having the DMA2D work in parallel of Display */ /* which cause perturbation of LTDC */ BSP_CAMERA_Suspend(); - - return (uint8_t *)LCD_FRAME_BUFFER; + return 0; } void CameraClass::testPattern(bool walking) diff --git a/libraries/Portenta_Camera/camera.h b/libraries/Portenta_Camera/camera.h index fd61ef0d9..817f3a968 100644 --- a/libraries/Portenta_Camera/camera.h +++ b/libraries/Portenta_Camera/camera.h @@ -1,8 +1,7 @@ class CameraClass { public: int begin(int horizontalResolution, int verticalResolution); - uint8_t* snapshot(); - int start(uint32_t timeout); - uint8_t* grab(void); + int grab(uint8_t *buffer, uint32_t timeout=5000); void testPattern(bool walking); -}; \ No newline at end of file + int skip_frames(uint8_t *buffer, uint32_t n_frames, uint32_t timeout=5000); +}; From 0bc3fa2a395237003f7c7295b314c81262af5a2c Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 15 Jan 2021 23:25:50 +0200 Subject: [PATCH 3/6] Update Arduino example sketch. --- .../examples/Envie_camera/Envie_camera.ino | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino b/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino index a9ad129d9..bc221f5ca 100644 --- a/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino +++ b/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino @@ -1,21 +1,26 @@ + #include "camera.h" CameraClass cam; +uint8_t fb[320*240] __attribute__((aligned(32))); void setup() { - Serial.begin(115200); - //while (!Serial); + Serial.begin(921600); + + // Init the cam + cam.begin(320, 240); - // put your setup code here, to run once: - cam.begin(324, 244); - cam.start(); - //cam.testPattern(true); + // Skip 60 frames + cam.skip_frames(fb, 60); } void loop() { // put your main code here, to run repeatedly: if (Serial) { - Serial.write(cam.grab(), 324 * 244); + // Grab frame and write to serial + if (cam.grab(fb) == 0) { + Serial.write(fb, 320*240); + } } } From 13b13728fc58d0310774553e87944a04d7ec7139 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 15 Jan 2021 23:26:21 +0200 Subject: [PATCH 4/6] Update Processing example. * Use faster baudrate. * Upscale image to VGA for better viewing. --- .../CameraRawBytesVisualizer.pde | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/Portenta_Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde b/libraries/Portenta_Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde index e951a4364..7c8393fdc 100644 --- a/libraries/Portenta_Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde +++ b/libraries/Portenta_Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde @@ -13,8 +13,8 @@ import java.nio.ByteOrder; Serial myPort; // must match resolution used in the sketch -final int cameraWidth = 324; -final int cameraHeight = 244; +final int cameraWidth = 320; +final int cameraHeight = 240; final int cameraBytesPerPixel = 1; final int bytesPerFrame = cameraWidth * cameraHeight * cameraBytesPerPixel; @@ -23,14 +23,14 @@ byte[] frameBuffer = new byte[bytesPerFrame]; void setup() { - size(324, 244); + size(640, 480); // if you have only ONE serial port active //myPort = new Serial(this, Serial.list()[0], 9600); // if you have only ONE serial port active // if you know the serial port name //myPort = new Serial(this, "COM5", 9600); // Windows - myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux + myPort = new Serial(this, "/dev/ttyACM0", 921600); // Linux //myPort = new Serial(this, "/dev/cu.usbmodem14401", 9600); // Mac // wait for full frame of bytes @@ -41,7 +41,9 @@ void setup() void draw() { - image(myImage, 0, 0); + PImage img = myImage.copy(); + img.resize(640, 480); + image(img, 0, 0); } void serialEvent(Serial myPort) { From 780323e52dfa105df1b591d245f240decf7a9c4d Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 18 Jan 2021 22:39:46 +0200 Subject: [PATCH 5/6] Update the camera drivers. * Fix pixclk polarity. * Update himax registers. * Support QVGA and QQVGA. * add set_framerate() * add standby() for low-power mode. --- libraries/Himax_HM01B0/himax.cpp | 260 ++++++++++++------ libraries/Himax_HM01B0/himax.h | 6 +- libraries/Portenta_Camera/camera.cpp | 176 ++++-------- libraries/Portenta_Camera/camera.h | 21 +- .../examples/Envie_camera/Envie_camera.ino | 12 +- 5 files changed, 257 insertions(+), 218 deletions(-) diff --git a/libraries/Himax_HM01B0/himax.cpp b/libraries/Himax_HM01B0/himax.cpp index 95e9e4312..7001a8f9b 100644 --- a/libraries/Himax_HM01B0/himax.cpp +++ b/libraries/Himax_HM01B0/himax.cpp @@ -50,6 +50,7 @@ memory mounted on GAPUINO board. /* Includes ------------------------------------------------------------------*/ #include "himax.h" +#include "camera.h" /** @addtogroup BSP * @{ @@ -77,93 +78,122 @@ memory mounted on GAPUINO board. /** @defgroup GAPUINO_HIMAX_Private_Variables I2C Private Variables * @{ */ +#define HIMAX_LINE_LEN_PCK_QVGA 0x178 +#define HIMAX_FRAME_LENGTH_QVGA 0x104 + +#define HIMAX_LINE_LEN_PCK_QQVGA 0x178 +#define HIMAX_FRAME_LENGTH_QQVGA 0x084 + static regval_list_t himax_default_regs[] = { - {BLC_TGT, 0x08}, // BLC target :8 at 8 bit mode - {BLC2_TGT, 0x08}, // BLI target :8 at 8 bit mode - {0x3044, 0x0A}, // Increase CDS time for settling - {0x3045, 0x00}, // Make symetric for cds_tg and rst_tg - {0x3047, 0x0A}, // Increase CDS time for settling - {0x3050, 0xC0}, // Make negative offset up to 4x - {0x3051, 0x42}, - {0x3052, 0x50}, - {0x3053, 0x00}, - {0x3054, 0x03}, // tuning sf sig clamping as lowest - {0x3055, 0xF7}, // tuning dsun - {0x3056, 0xF8}, // increase adc nonoverlap clk - {0x3057, 0x29}, // increase adc pwr for missing code - {0x3058, 0x1F}, // turn on dsun - {0x3059, 0x1E}, - {0x3064, 0x00}, - {0x3065, 0x04}, // pad pull 0 - - {BLC_CFG, 0x43}, // BLC_on, IIR - - {0x1001, 0x43}, // BLC dithering en - {0x1002, 0x43}, // blc_darkpixel_thd - {0x0350, 0x00}, // Dgain Control - {BLI_EN, 0x01}, // BLI enable - {0x1003, 0x00}, // BLI Target [Def: 0x20] - - {DPC_CTRL, 0x01}, // DPC option 0: DPC off 1 : mono 3 : bayer1 5 : bayer2 - {0x1009, 0xA0}, // cluster hot pixel th - {0x100A, 0x60}, // cluster cold pixel th - {SINGLE_THR_HOT, 0x90}, // single hot pixel th - {SINGLE_THR_COLD, 0x40}, // single cold pixel th - {0x1012, 0x00}, // Sync. shift disable - {0x2000, 0x07}, - {0x2003, 0x00}, - {0x2004, 0x1C}, - {0x2007, 0x00}, - {0x2008, 0x58}, - {0x200B, 0x00}, - {0x200C, 0x7A}, - {0x200F, 0x00}, - {0x2010, 0xB8}, - {0x2013, 0x00}, - {0x2014, 0x58}, - {0x2017, 0x00}, - {0x2018, 0x9B}, - - {AE_CTRL, 0x01}, //Automatic Exposure - {AE_TARGET_MEAN, 0x3C}, //AE target mean [Def: 0x3C] - {AE_MIN_MEAN, 0x0A}, //AE min target mean [Def: 0x0A] - - {INTEGRATION_H, 0x01}, //Integration H [Def: 0x01] - {INTEGRATION_L, 0x08}, //Integration L [Def: 0x08] - {ANALOG_GAIN, 0x00}, //Analog Global Gain [Def: 0x00] - {DAMPING_FACTOR, 0x20}, //Damping Factor [Def: 0x20] - {DIGITAL_GAIN_H, 0x01}, //Digital Gain High [Def: 0x01] - {DIGITAL_GAIN_L, 0x00}, //Digital Gain Low [Def: 0x00] - - {CONVERGE_IN_TH, 0x03}, //Converge in threshold [Def: 0x03] - {CONVERGE_OUT_TH, 0x05}, //Converge out threshold [Def: 0x05] - {MAX_INTG_H, 0x01}, //Maximum INTG High Byte [Def: 0x01] - {MAX_INTG_L, 0x54}, //Maximum INTG Low Byte [Def: 0x54] - {MAX_AGAIN_FULL, 0x03}, //Maximum Analog gain in full frame mode [Def: 0x03] - {MAX_AGAIN_BIN2, 0x04}, //Maximum Analog gain in bin2 mode [Def: 0x04] - - {0x210B, 0xC0}, - {0x210E, 0x00}, //Flicker Control - {0x210F, 0x00}, - {0x2110, 0x3C}, - {0x2111, 0x00}, - {0x2112, 0x32}, - - {0x2150, 0x30}, - {0x0340, 0x02}, - {0x0341, 0x16}, - {0x0342, 0x01}, - {0x0343, 0x78}, - {0x3010, 0x01}, // 324 x 244 pixel - {0x0383, 0x01}, - {0x0387, 0x01}, - {0x0390, 0x00}, - {0x3011, 0x70}, - {0x3059, 0x02}, - {0x3060, 0x00}, - //{0x0601, 0x01}, - {IMG_ORIENTATION, 0x00}, - {0x0104, 0x01} + {BLC_TGT, 0x08}, // BLC target :8 at 8 bit mode + {BLC2_TGT, 0x08}, // BLI target :8 at 8 bit mode + {0x3044, 0x0A}, // Increase CDS time for settling + {0x3045, 0x00}, // Make symetric for cds_tg and rst_tg + {0x3047, 0x0A}, // Increase CDS time for settling + {0x3050, 0xC0}, // Make negative offset up to 4x + {0x3051, 0x42}, + {0x3052, 0x50}, + {0x3053, 0x00}, + {0x3054, 0x03}, // tuning sf sig clamping as lowest + {0x3055, 0xF7}, // tuning dsun + {0x3056, 0xF8}, // increase adc nonoverlap clk + {0x3057, 0x29}, // increase adc pwr for missing code + {0x3058, 0x1F}, // turn on dsun + {0x3059, 0x1E}, + {0x3064, 0x00}, + {0x3065, 0x04}, // pad pull 0 + + {BLC_CFG, 0x43}, // BLC_on, IIR + + {0x1001, 0x43}, // BLC dithering en + {0x1002, 0x43}, // blc_darkpixel_thd + {0x0350, 0x7F}, // Dgain Control + {BLI_EN, 0x01}, // BLI enable + {0x1003, 0x00}, // BLI Target [Def: 0x20] + + {DPC_CTRL, 0x01}, // DPC option 0: DPC off 1 : mono 3 : bayer1 5 : bayer2 + {0x1009, 0xA0}, // cluster hot pixel th + {0x100A, 0x60}, // cluster cold pixel th + {SINGLE_THR_HOT, 0x90}, // single hot pixel th + {SINGLE_THR_COLD, 0x40}, // single cold pixel th + {0x1012, 0x00}, // Sync. shift disable + {0x2000, 0x07}, + {0x2003, 0x00}, + {0x2004, 0x1C}, + {0x2007, 0x00}, + {0x2008, 0x58}, + {0x200B, 0x00}, + {0x200C, 0x7A}, + {0x200F, 0x00}, + {0x2010, 0xB8}, + {0x2013, 0x00}, + {0x2014, 0x58}, + {0x2017, 0x00}, + {0x2018, 0x9B}, + + {AE_CTRL, 0x01}, //Automatic Exposure + {AE_TARGET_MEAN, 0x3C}, //AE target mean [Def: 0x3C] + {AE_MIN_MEAN, 0x0A}, //AE min target mean [Def: 0x0A] + {CONVERGE_IN_TH, 0x03}, //Converge in threshold [Def: 0x03] + {CONVERGE_OUT_TH, 0x05}, //Converge out threshold [Def: 0x05] + {MAX_INTG_H, (HIMAX_FRAME_LENGTH_QVGA-2)>>8}, //Maximum INTG High Byte [Def: 0x01] + {MAX_INTG_L, (HIMAX_FRAME_LENGTH_QVGA-2)&0xFF}, //Maximum INTG Low Byte [Def: 0x54] + {MAX_AGAIN_FULL, 0x03}, //Maximum Analog gain in full frame mode [Def: 0x03] + {MAX_AGAIN_BIN2, 0x04}, //Maximum Analog gain in bin2 mode [Def: 0x04] + {MAX_DGAIN, 0xC0}, + + {INTEGRATION_H, 0x01}, //Integration H [Def: 0x01] + {INTEGRATION_L, 0x08}, //Integration L [Def: 0x08] + {ANALOG_GAIN, 0x00}, //Analog Global Gain [Def: 0x00] + {DAMPING_FACTOR, 0x20}, //Damping Factor [Def: 0x20] + {DIGITAL_GAIN_H, 0x01}, //Digital Gain High [Def: 0x01] + {DIGITAL_GAIN_L, 0x00}, //Digital Gain Low [Def: 0x00] + + {FS_CTRL, 0x00}, //Flicker Control + + {FS_60HZ_H, 0x00}, + {FS_60HZ_L, 0x3C}, + {FS_50HZ_H, 0x00}, + {FS_50HZ_L, 0x32}, + + {MD_CTRL, 0x30}, + {FRAME_LEN_LINES_H, HIMAX_FRAME_LENGTH_QVGA>>8}, + {FRAME_LEN_LINES_L, HIMAX_FRAME_LENGTH_QVGA&0xFF}, + {LINE_LEN_PCK_H, HIMAX_LINE_LEN_PCK_QVGA>>8}, + {LINE_LEN_PCK_L, HIMAX_LINE_LEN_PCK_QVGA&0xFF}, + {QVGA_WIN_EN, 0x01}, // Enable QVGA window readout + {0x0383, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {0x3011, 0x70}, + {0x3059, 0x02}, + {OSC_CLK_DIV, 0x0B}, + {IMG_ORIENTATION, 0x00}, // change the orientation + {0x0104, 0x01}, +}; + +static regval_list_t himax_qvga_regs[] = { + {0x0383, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {MAX_INTG_H, (HIMAX_FRAME_LENGTH_QVGA-2)>>8}, + {MAX_INTG_L, (HIMAX_FRAME_LENGTH_QVGA-2)&0xFF}, + {FRAME_LEN_LINES_H, (HIMAX_FRAME_LENGTH_QVGA>>8)}, + {FRAME_LEN_LINES_L, (HIMAX_FRAME_LENGTH_QVGA&0xFF)}, + {LINE_LEN_PCK_H, (HIMAX_LINE_LEN_PCK_QVGA>>8)}, + {LINE_LEN_PCK_L, (HIMAX_LINE_LEN_PCK_QVGA&0xFF)}, +}; + +static regval_list_t himax_qqvga_regs[] = { + {0x0383, 0x03}, + {0x0387, 0x03}, + {0x0390, 0x03}, + {MAX_INTG_H, (HIMAX_FRAME_LENGTH_QQVGA-2)>>8}, + {MAX_INTG_L, (HIMAX_FRAME_LENGTH_QQVGA-2)&0xFF}, + {FRAME_LEN_LINES_H, (HIMAX_FRAME_LENGTH_QQVGA>>8)}, + {FRAME_LEN_LINES_L, (HIMAX_FRAME_LENGTH_QQVGA&0xFF)}, + {LINE_LEN_PCK_H, (HIMAX_LINE_LEN_PCK_QQVGA>>8)}, + {LINE_LEN_PCK_L, (HIMAX_LINE_LEN_PCK_QQVGA&0xFF)}, }; /* SPI transfer command sequence array */ @@ -212,6 +242,7 @@ uint8_t HIMAX_Open(void) } HIMAX_Boot(); + //For debugging camera Configuration //HIMAX_PrintReg(); HAL_Delay(200); @@ -223,9 +254,62 @@ uint8_t HIMAX_Open(void) * @brief This function selects HIMAX camera mode. * @retval None */ -void HIMAX_Mode(uint8_t mode) +int HIMAX_Mode(uint8_t mode) +{ + return HIMAX_RegWrite(MODE_SELECT, mode); +} + +int HIMAX_SetResolution(uint32_t resolution) +{ + int ret = 0; + uint32_t regs_count = 0; + regval_list_t *regs = NULL; + + switch (resolution) { + case CAMERA_R160x120: + regs = himax_qqvga_regs; + regs_count = sizeof(himax_qqvga_regs) / sizeof(regval_list_t); + break; + case CAMERA_R320x240: + regs = himax_qvga_regs; + regs_count = sizeof(himax_qvga_regs) / sizeof(regval_list_t); + break; + default: + return -1; + } + + for(uint32_t i = 0; i < regs_count; i++) { + ret |= HIMAX_RegWrite(regs[i].reg_num, regs[i].value); + } + + return ret; +} + +int HIMAX_SetFramerate(uint32_t framerate) { - HIMAX_RegWrite(MODE_SELECT, mode); + uint8_t osc_div = 0; + // binning is enabled for QQVGA + uint8_t binning = HIMAX_RegRead(BINNING_MODE) & 0x03; + + switch (framerate) { + case 15: + osc_div = (binning) ? 0x00 : 0x01; + break; + case 30: + osc_div = (binning) ? 0x01 : 0x02; + break; + case 60: + osc_div = (binning) ? 0x02 : 0x03; + break; + case 120: + // Set to max FPS for QVGA and QQVGA. + osc_div = 0x03; + break; + default: + return -1; + } + + return HIMAX_RegWrite(OSC_CLK_DIV, 0x08 | osc_div); } /** diff --git a/libraries/Himax_HM01B0/himax.h b/libraries/Himax_HM01B0/himax.h index e982d0943..4d141144d 100644 --- a/libraries/Himax_HM01B0/himax.h +++ b/libraries/Himax_HM01B0/himax.h @@ -144,7 +144,9 @@ typedef struct regval_list_ { } regval_list_t; uint8_t HIMAX_Open(void); -void HIMAX_Mode(uint8_t mode); +int HIMAX_Mode(uint8_t mode); +int HIMAX_SetResolution(uint32_t resolution); +int HIMAX_SetFramerate(uint32_t framerate); void HIMAX_TestPattern(bool enable = true, bool walking = true); @@ -152,4 +154,4 @@ void HIMAX_TestPattern(bool enable = true, bool walking = true); } #endif -#endif /* __HIMAX_H */ \ No newline at end of file +#endif /* __HIMAX_H */ diff --git a/libraries/Portenta_Camera/camera.cpp b/libraries/Portenta_Camera/camera.cpp index a391be6b7..f68557d05 100644 --- a/libraries/Portenta_Camera/camera.cpp +++ b/libraries/Portenta_Camera/camera.cpp @@ -2,41 +2,26 @@ #include "himax.h" #include "camera.h" #include "stm32h7xx_hal_dcmi.h" -#include "SDRAM.h" -#define LCD_FRAME_BUFFER 0xC0000000 /* LCD Frame buffer of size 800x480 in ARGB8888 */ #define CAMERA_FRAME_BUFFER 0xC0200000 -#define QVGA_RES_X 320 -#define QVGA_RES_Y 240 - #define ARGB8888_BYTE_PER_PIXEL 4 -static uint32_t CameraResX = QVGA_RES_X; -static uint32_t CameraResY = QVGA_RES_Y; -static uint32_t LcdResX = 0; -static uint32_t LcdResY = 0; -static uint32_t *user_buffer = 0; +static const int CamRes[][2] = { + {160, 120}, + {320, 240}, +}; +static __IO uint32_t camera_frame_ready = 0; -__IO uint32_t camera_frame_ready = 0; -__IO uint32_t lcd_frame_ready = 0; - /* DCMI DMA Stream definitions */ #define CAMERA_DCMI_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE #define CAMERA_DCMI_DMAx_STREAM DMA2_Stream3 #define CAMERA_DCMI_DMAx_IRQ DMA2_Stream3_IRQn -#define CAMERA_R160x120 0x00 /* QQVGA Resolution */ -#define CAMERA_R320x240 0x01 /* QVGA Resolution */ -#define CAMERA_R480x272 0x02 /* 480x272 Resolution */ -#define CAMERA_R640x480 0x03 /* VGA Resolution */ - extern "C" { DCMI_HandleTypeDef hdcmi_discovery; -static uint32_t CameraCurrentResolution; - void BSP_CAMERA_PwrUp(void); /** @@ -142,10 +127,6 @@ void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params) by surcharging this __weak function */ } -/** @defgroup STM32H747I_DISCOVERY_CAMERA_Private_FunctionPrototypes Private FunctionPrototypes - * @{ - */ -static uint32_t GetSize(uint32_t Resolution); /** * @} */ @@ -193,7 +174,7 @@ uint8_t BSP_CAMERA_Init(uint32_t Resolution) phdcmi->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_LOW; phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; - phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING; + phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_FALLING; phdcmi->Init.ByteSelectMode = DCMI_BSM_ALL; // Capture all received bytes phdcmi->Init.ByteSelectStart = DCMI_OEBS_ODD; // Ignored phdcmi->Init.LineSelectMode = DCMI_LSM_ALL; // Capture all received lines @@ -216,19 +197,16 @@ uint8_t BSP_CAMERA_Init(uint32_t Resolution) * @retval HAL status */ HAL_DCMI_EnableCROP(phdcmi); - HAL_DCMI_ConfigCROP(phdcmi, (QVGA_RES_X - CameraResX) / 2, (QVGA_RES_Y - CameraResY) / 2, CameraResX-1, CameraResY-1); + HAL_DCMI_ConfigCROP(phdcmi, 0, 0, CamRes[Resolution][0] - 1, CamRes[Resolution][1] - 1); __HAL_DCMI_DISABLE_IT(&hdcmi_discovery, DCMI_IT_LINE); - CameraCurrentResolution = Resolution; - /* Return CAMERA_OK status */ status = 0; return status; } - /** * @brief DeInitializes the camera. * @retval Camera status @@ -247,14 +225,12 @@ uint8_t BSP_CAMERA_DeInit(void) * @param buff: pointer to the camera output buffer * @retval None */ -void BSP_CAMERA_SnapshotStart(uint8_t *buff) +void BSP_CAMERA_SnapshotStart(uint8_t *buff, uint32_t framesize) { - user_buffer = (uint32_t*) buff; - __HAL_DCMI_ENABLE_IT(&hdcmi_discovery, DCMI_IT_FRAME); /* Start the camera capture */ - HAL_DCMI_Start_DMA(&hdcmi_discovery, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)/4); + HAL_DCMI_Start_DMA(&hdcmi_discovery, DCMI_MODE_SNAPSHOT, (uint32_t)buff, framesize / 4); } /** @@ -395,47 +371,6 @@ void BSP_CAMERA_PwrDown(void) digitalWrite(PC_13, LOW); } -/** - * @brief Get the capture size in pixels unit. - * @param Resolution: the current resolution. - * @retval capture size in pixels unit. - */ -static uint32_t GetSize(uint32_t Resolution) -{ - uint32_t size = 0; - - /* Get capture size */ - switch (Resolution) - { - case CAMERA_R160x120: - { - size = 160 * 120; - } - break; - case CAMERA_R320x240: - { - size = 320 * 240; - } - break; - case CAMERA_R480x272: - { - size = 480 * 272; - } - break; - case CAMERA_R640x480: - { - size = 640 * 480; - } - break; - default: - { - break; - } - } - - return size; -} - /** * @brief Error callback. * @retval None @@ -446,11 +381,9 @@ void BSP_CAMERA_ErrorCallback(void) void BSP_CAMERA_FrameEventCallback(void) { - camera_frame_ready++; - SCB_InvalidateDCache_by_Addr((uint32_t*)user_buffer, GetSize(CameraCurrentResolution)); + camera_frame_ready++; } - void DMA2_Stream3_IRQHandler(void) { HAL_DMA_IRQHandler(hdcmi_discovery.DMA_Handle); @@ -519,34 +452,60 @@ void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) } - -int CameraClass::begin(int horizontalResolution, int verticalResolution) +int CameraClass::begin(uint32_t resolution, uint32_t framerate) { - CameraResX = horizontalResolution; - CameraResY = verticalResolution; - - SDRAM.begin(LCD_FRAME_BUFFER); + if (resolution >= CAMERA_RMAX) { + return -1; + } /*## Camera Initialization and capture start ############################*/ /* Initialize the Camera in QVGA mode */ - if(BSP_CAMERA_Init(CAMERA_R320x240) != 0) + if(BSP_CAMERA_Init(resolution) != 0) { return -1; } + if (HIMAX_SetResolution(resolution) != 0) { + return -1; + } + + if (HIMAX_SetFramerate(framerate) != 0) { + return -1; + } + + if (HIMAX_Mode(HIMAX_Streaming) != 0) { + return -1; + } + + this->initialized = true; + this->resolution = resolution; return 0; } +int CameraClass::framerate(uint32_t framerate) +{ + if (this->initialized == false) { + return -1; + } + return HIMAX_SetFramerate(framerate); +} + int CameraClass::grab(uint8_t *buffer, uint32_t timeout) { - HIMAX_Mode(HIMAX_Streaming); + if (this->initialized == false) { + return -1; + } BSP_CAMERA_Resume(); - /* Start the Camera Snapshot Capture */ - BSP_CAMERA_SnapshotStart(buffer); + /* Frame size from resolution. */ + uint32_t framesize = CamRes[this->resolution][0] * CamRes[this->resolution][1]; camera_frame_ready = 0; + + /* Start the Camera Snapshot Capture */ + BSP_CAMERA_SnapshotStart(buffer, framesize); + /* Wait until camera frame is ready : DCMI Frame event */ for (uint32_t start = millis(); camera_frame_ready == 0;) { __WFI(); @@ -556,46 +515,33 @@ int CameraClass::grab(uint8_t *buffer, uint32_t timeout) } } - HIMAX_Mode(HIMAX_Standby); - /* Stop the camera to avoid having the DMA2D work in parallel of Display */ /* which cause perturbation of LTDC */ BSP_CAMERA_Suspend(); + /* Invalidate buffer after DMA transfer */ + SCB_InvalidateDCache_by_Addr((uint32_t*)buffer, framesize); + return 0; } -int CameraClass::skip_frames(uint8_t *buffer, uint32_t n_frames, uint32_t timeout) +int CameraClass::standby(bool enable) { - HIMAX_Mode(HIMAX_Streaming); - - BSP_CAMERA_Resume(); - - /* Start the Camera Snapshot Capture */ - BSP_CAMERA_SnapshotStart(buffer); - - while (n_frames--) { - camera_frame_ready = 0; - /* Wait until camera frame is ready : DCMI Frame event */ - for (uint32_t start = millis(); camera_frame_ready == 0;) { - __WFI(); - if ((millis() - start) > timeout) { - HAL_DMA_Abort(hdcmi_discovery.DMA_Handle); - return -1; - } - } + if (this->initialized == false) { + return -1; + } else if (enable) { + return HIMAX_Mode(HIMAX_Standby); + } else { + return HIMAX_Mode(HIMAX_Streaming); } - - HIMAX_Mode(HIMAX_Standby); - - /* Stop the camera to avoid having the DMA2D work in parallel of Display */ - /* which cause perturbation of LTDC */ - BSP_CAMERA_Suspend(); - return 0; } -void CameraClass::testPattern(bool walking) +int CameraClass::testPattern(bool walking) { + if (this->initialized == false) { + return -1; + } HIMAX_TestPattern(true, walking); + return 0; } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/Portenta_Camera/camera.h b/libraries/Portenta_Camera/camera.h index 817f3a968..e25c29063 100644 --- a/libraries/Portenta_Camera/camera.h +++ b/libraries/Portenta_Camera/camera.h @@ -1,7 +1,18 @@ +enum { + CAMERA_R160x120 = 0x00, /* QQVGA Resolution */ + CAMERA_R320x240 = 0x01, /* QVGA Resolution */ + CAMERA_RMAX +}; + class CameraClass { -public: - int begin(int horizontalResolution, int verticalResolution); - int grab(uint8_t *buffer, uint32_t timeout=5000); - void testPattern(bool walking); - int skip_frames(uint8_t *buffer, uint32_t n_frames, uint32_t timeout=5000); + private: + uint32_t resolution; + bool initialized; + public: + CameraClass(): initialized(false) {} + int begin(uint32_t resolution = CAMERA_R320x240, uint32_t framerate = 30); + int framerate(uint32_t framerate); + int grab(uint8_t *buffer, uint32_t timeout=5000); + int standby(bool enable); + int testPattern(bool walking); }; diff --git a/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino b/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino index bc221f5ca..f69cbc5fb 100644 --- a/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino +++ b/libraries/Portenta_Camera/examples/Envie_camera/Envie_camera.ino @@ -1,18 +1,14 @@ - #include "camera.h" CameraClass cam; -uint8_t fb[320*240] __attribute__((aligned(32))); +uint8_t fb[320*240]; void setup() { Serial.begin(921600); - // Init the cam - cam.begin(320, 240); - - // Skip 60 frames - cam.skip_frames(fb, 60); + // Init the cam QVGA, 30FPS + cam.begin(CAMERA_R320x240, 30); } void loop() { @@ -20,7 +16,7 @@ void loop() { if (Serial) { // Grab frame and write to serial if (cam.grab(fb) == 0) { - Serial.write(fb, 320*240); + Serial.write(fb, 320*240); } } } From 43baef4363c8082b11c74849e3babd8446a7e341 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 23 Jan 2021 22:46:21 +0200 Subject: [PATCH 6/6] Enable motion detection. --- libraries/Himax_HM01B0/himax.cpp | 43 ++++++++++ libraries/Himax_HM01B0/himax.h | 15 ++++ libraries/Portenta_Camera/camera.cpp | 79 ++++++++++++++++++- libraries/Portenta_Camera/camera.h | 11 ++- .../Envie_cameraMD/Envie_cameraMD.ino | 37 +++++++++ 5 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 libraries/Portenta_Camera/examples/Envie_cameraMD/Envie_cameraMD.ino diff --git a/libraries/Himax_HM01B0/himax.cpp b/libraries/Himax_HM01B0/himax.cpp index 7001a8f9b..781c6190f 100644 --- a/libraries/Himax_HM01B0/himax.cpp +++ b/libraries/Himax_HM01B0/himax.cpp @@ -312,6 +312,49 @@ int HIMAX_SetFramerate(uint32_t framerate) return HIMAX_RegWrite(OSC_CLK_DIV, 0x08 | osc_div); } +int HIMAX_EnableMD(bool enable) +{ + int ret = HIMAX_ClearMD(); + if (enable) { + ret |= HIMAX_RegWrite(MD_CTRL, 0x03); + } else { + ret |= HIMAX_RegWrite(MD_CTRL, 0x30); + } + return ret; +} + +int HIMAX_SetMDThreshold(uint32_t low, uint32_t high) +{ + int ret = 0; + ret |= HIMAX_RegWrite(MD_THL, low & 0xff); + ret |= HIMAX_RegWrite(MD_THH, high & 0xff); + return ret; +} + +int HIMAX_SetLROI(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2) +{ + int ret = 0; + ret |= HIMAX_RegWrite(MD_LROI_X_START_H, (x1>>8)); + ret |= HIMAX_RegWrite(MD_LROI_X_START_L, (x1&0xff)); + ret |= HIMAX_RegWrite(MD_LROI_Y_START_H, (y1>>8)); + ret |= HIMAX_RegWrite(MD_LROI_Y_START_L, (y1&0xff)); + ret |= HIMAX_RegWrite(MD_LROI_X_END_H, (x2>>8)); + ret |= HIMAX_RegWrite(MD_LROI_X_END_L, (x2&0xff)); + ret |= HIMAX_RegWrite(MD_LROI_Y_END_H, (y2>>8)); + ret |= HIMAX_RegWrite(MD_LROI_Y_END_L, (y2&0xff)); + return ret; +} + +int HIMAX_PollMD() +{ + return HIMAX_RegRead(MD_INTERRUPT); +} + +int HIMAX_ClearMD() +{ + return HIMAX_RegWrite(I2C_CLEAR, 0x01); +} + /** * @brief This function writes HIMAX camera registers. * @retval None diff --git a/libraries/Himax_HM01B0/himax.h b/libraries/Himax_HM01B0/himax.h index 4d141144d..e58bb3a42 100644 --- a/libraries/Himax_HM01B0/himax.h +++ b/libraries/Himax_HM01B0/himax.h @@ -104,6 +104,16 @@ #define MD_THM1 0x2159 #define MD_THM2 0x215A #define MD_THL 0x215B +#define STATISTIC_CTRL 0x2000 +#define MD_LROI_X_START_H 0x2011 +#define MD_LROI_X_START_L 0x2012 +#define MD_LROI_Y_START_H 0x2013 +#define MD_LROI_Y_START_L 0x2014 +#define MD_LROI_X_END_H 0x2015 +#define MD_LROI_X_END_L 0x2016 +#define MD_LROI_Y_END_H 0x2017 +#define MD_LROI_Y_END_L 0x2018 +#define MD_INTERRUPT 0x2160 // Sensor timing control #define QVGA_WIN_EN 0x3010 #define SIX_BIT_MODE_EN 0x3011 @@ -147,6 +157,11 @@ uint8_t HIMAX_Open(void); int HIMAX_Mode(uint8_t mode); int HIMAX_SetResolution(uint32_t resolution); int HIMAX_SetFramerate(uint32_t framerate); +int HIMAX_EnableMD(bool enable); +int HIMAX_SetMDThreshold(uint32_t low, uint32_t high); +int HIMAX_SetLROI(uint32_t x, uint32_t y, uint32_t w, uint32_t h); +int HIMAX_PollMD(); +int HIMAX_ClearMD(); void HIMAX_TestPattern(bool enable = true, bool walking = true); diff --git a/libraries/Portenta_Camera/camera.cpp b/libraries/Portenta_Camera/camera.cpp index f68557d05..323de5f94 100644 --- a/libraries/Portenta_Camera/camera.cpp +++ b/libraries/Portenta_Camera/camera.cpp @@ -12,6 +12,7 @@ static const int CamRes[][2] = { {320, 240}, }; static __IO uint32_t camera_frame_ready = 0; +static md_callback_t user_md_callback = NULL; /* DCMI DMA Stream definitions */ #define CAMERA_DCMI_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE @@ -349,8 +350,6 @@ static int extclk_config(int frequency) */ void BSP_CAMERA_PwrUp(void) { - GPIO_InitTypeDef gpio_init_structure; - mbed::DigitalOut* powerup = new mbed::DigitalOut(PC_13); *powerup = 0; delay(50); @@ -452,6 +451,13 @@ void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) } +void CameraClass::HIMAXIrqHandler() +{ + if (user_md_callback) { + user_md_callback(); + } +} + int CameraClass::begin(uint32_t resolution, uint32_t framerate) { if (resolution >= CAMERA_RMAX) { @@ -477,6 +483,7 @@ int CameraClass::begin(uint32_t resolution, uint32_t framerate) return -1; } + user_md_callback = NULL; this->initialized = true; this->resolution = resolution; return 0; @@ -536,6 +543,74 @@ int CameraClass::standby(bool enable) } } +int CameraClass::setMDThreshold(uint32_t low, uint32_t high) +{ + if (this->initialized == false) { + return -1; + } + return HIMAX_SetMDThreshold(low, high); +} + +int CameraClass::setMDWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + uint32_t width, height; + + if (this->initialized == false) { + return -1; + } + + width = CamRes[this->resolution][0]; + height= CamRes[this->resolution][1]; + + if (((x+w) > width) || ((y+h) > height)) { + return -1; + } + return HIMAX_SetLROI(x, y, x+w, y+h); +} + +int CameraClass::enableMD(bool enable, md_callback_t callback) +{ + if (this->initialized == false) { + return -1; + } + + this->md_irq.rise(0); + + if (enable == false) { + user_md_callback = NULL; + } else { + user_md_callback = callback; + this->md_irq.rise(mbed::Callback(this, &CameraClass::HIMAXIrqHandler)); + this->md_irq.enable_irq(); + } + + return HIMAX_EnableMD(enable); +} + +int CameraClass::pollMD() +{ + int ret = 0; + + if (this->initialized == false) { + return -1; + } + + ret = HIMAX_PollMD(); + if (ret == 1) { + HIMAX_ClearMD(); + } + return ret; +} + +int CameraClass::clearMDFlag() +{ + if (this->initialized == false) { + return -1; + } + + return HIMAX_ClearMD(); +} + int CameraClass::testPattern(bool walking) { if (this->initialized == false) { diff --git a/libraries/Portenta_Camera/camera.h b/libraries/Portenta_Camera/camera.h index e25c29063..c95ec587a 100644 --- a/libraries/Portenta_Camera/camera.h +++ b/libraries/Portenta_Camera/camera.h @@ -4,15 +4,24 @@ enum { CAMERA_RMAX }; +typedef void (*md_callback_t)(); + class CameraClass { private: uint32_t resolution; bool initialized; + mbed::InterruptIn md_irq; + void HIMAXIrqHandler(); public: - CameraClass(): initialized(false) {} + CameraClass(): initialized(false), md_irq(PC_15){} int begin(uint32_t resolution = CAMERA_R320x240, uint32_t framerate = 30); int framerate(uint32_t framerate); int grab(uint8_t *buffer, uint32_t timeout=5000); int standby(bool enable); + int enableMD(bool enable, md_callback_t callback=NULL); + int setMDWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h); + int setMDThreshold(uint32_t low, uint32_t high); + int pollMD(); + int clearMDFlag(); int testPattern(bool walking); }; diff --git a/libraries/Portenta_Camera/examples/Envie_cameraMD/Envie_cameraMD.ino b/libraries/Portenta_Camera/examples/Envie_cameraMD/Envie_cameraMD.ino new file mode 100644 index 000000000..00080d367 --- /dev/null +++ b/libraries/Portenta_Camera/examples/Envie_cameraMD/Envie_cameraMD.ino @@ -0,0 +1,37 @@ +#include "camera.h" + +CameraClass cam; +uint8_t fb[320*240]; +bool motion_detected = false; + +void on_motion() +{ + motion_detected = true; +} + +void setup() { + Serial.begin(115200); + + pinMode(LEDB, OUTPUT); + digitalWrite(LEDB, HIGH); + + // Init the cam QVGA, 30FPS + cam.begin(CAMERA_R320x240, 60); + + cam.setMDThreshold(100, 200); + cam.setMDWindow(0, 0, 320, 240); + cam.enableMD(true, on_motion); +} + +void loop() { + // put your main code here, to run repeatedly: + if (motion_detected) { + Serial.printf("Motion Detected!\n"); + digitalWrite(LEDB, LOW); + delay(500); + cam.clearMDFlag(); + motion_detected =false; + digitalWrite(LEDB, HIGH); + } + delay(10); +}