116 lines
4.1 KiB
C
116 lines
4.1 KiB
C
#include "dvp.h"
|
|
#include "ch32v30x_dvp.h"
|
|
#include "eth_driver.h"
|
|
#include "string.h"
|
|
#include "qdx_port.h"
|
|
|
|
__attribute__((aligned(4))) uint8_t DMA_LineBuf0[BYTES_PER_LINE];
|
|
__attribute__((aligned(4))) uint8_t DMA_LineBuf1[BYTES_PER_LINE];
|
|
|
|
volatile uint8_t Line_Ready_Flag = 0;
|
|
volatile uint8_t *Ready_Line_Ptr = NULL;
|
|
volatile uint32_t current_line_idx = 0;
|
|
volatile uint32_t dvp_frame_count = 0;
|
|
volatile uint32_t dvp_row_irq_cnt = 0;
|
|
|
|
extern u8 socket[];
|
|
extern volatile uint32_t sys_tick_ms;
|
|
|
|
void DVP_Init(void)
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
|
NVIC_InitTypeDef NVIC_InitStructure = {0};
|
|
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE);
|
|
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DVP, ENABLE);
|
|
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_9 | GPIO_Pin_10;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_11;
|
|
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_8 | GPIO_Pin_9;
|
|
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
|
|
|
/* Step 1: Reset DVP logic */
|
|
DVP->CR1 = RB_DVP_ALL_CLR | RB_DVP_RCV_CLR;
|
|
DVP->CR1 = 0x00; /* release reset */
|
|
|
|
/* Step 2: Configure mode - 8-bit data, Video/RGB, continuous capture */
|
|
DVP->CR0 = 0; /* clear everything first */
|
|
DVP_Mode(RB_DVP_D8_MOD, Video_Mode);
|
|
/* Mini212G2 polarity: PCLK normal(rising), VSYNC high-active, HSYNC high-active */
|
|
DVP->CR0 &= ~(RB_DVP_P_POLAR | RB_DVP_V_POLAR | RB_DVP_H_POLAR);
|
|
DVP->CR0 |= RB_DVP_V_POLAR; /* VSYNC active-high (FIELD_VALID=HIGH) */
|
|
|
|
/* Step 3: Configure DMA buffers */
|
|
DVP->DMA_BUF0 = (uint32_t)DMA_LineBuf0;
|
|
DVP->DMA_BUF1 = (uint32_t)DMA_LineBuf1;
|
|
|
|
/* Step 4: Configure image dimensions */
|
|
DVP->ROW_NUM = 1;
|
|
DVP->COL_NUM = BYTES_PER_LINE;
|
|
|
|
/* Step 5: Enable interrupts */
|
|
DVP_INTCfg(ENABLE, RB_DVP_IE_STR_FRM | RB_DVP_IE_ROW_DONE);
|
|
|
|
NVIC_InitStructure.NVIC_IRQChannel = DVP_IRQn;
|
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
|
NVIC_Init(&NVIC_InitStructure);
|
|
|
|
/* Step 6: Enable DMA, then enable DVP */
|
|
DVP->CR1 = RB_DVP_DMA_EN; /* DMA on, CM=0 continuous, no reset bits */
|
|
DVP->CR0 |= RB_DVP_ENABLE;
|
|
|
|
DBG_INIT("DVP CR0=0x%02x CR1=0x%02x ROW=%d COL=%d\r\n",
|
|
(int)(DVP->CR0 & 0xFF), (int)(DVP->CR1 & 0xFF),
|
|
(int)DVP->ROW_NUM, (int)DVP->COL_NUM);
|
|
DBG_INIT("DVP DMA_BUF0=0x%08x DMA_BUF1=0x%08x\r\n",
|
|
(int)DVP->DMA_BUF0, (int)DVP->DMA_BUF1);
|
|
}
|
|
|
|
#define PROTOCOL_HEADER_RESERVE 64
|
|
|
|
__attribute__((aligned(4))) uint8_t FrameBuffer[SENSOR_HEIGHT][BYTES_PER_LINE];
|
|
volatile uint8_t Frame_Ready_Flag = 0;
|
|
volatile uint32_t Ready_Frame_Count = 0;
|
|
|
|
void DVP_Task(void)
|
|
{
|
|
/* Line copying is done directly in DVP_IRQHandler to prevent
|
|
* line drops when the task runs slower than the DVP pixel clock.
|
|
* This function is intentionally empty. */
|
|
}
|
|
|
|
void DVP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
|
void DVP_IRQHandler(void)
|
|
{
|
|
if (DVP->IFR & RB_DVP_IF_STR_FRM)
|
|
{
|
|
DVP->IFR = RB_DVP_IF_STR_FRM;
|
|
current_line_idx = 0;
|
|
dvp_frame_count++;
|
|
}
|
|
if (DVP->IFR & RB_DVP_IF_ROW_DONE)
|
|
{
|
|
DVP->IFR = RB_DVP_IF_ROW_DONE;
|
|
/* Capture src and idx before incrementing to fix off-by-one:
|
|
* STR_FRM sets idx=0, so first ROW_DONE copies to FrameBuffer[0]. */
|
|
uint8_t *src = (DVP->CR1 & RB_DVP_BUF_TOG) ? DMA_LineBuf0 : DMA_LineBuf1;
|
|
uint32_t idx = current_line_idx;
|
|
current_line_idx++;
|
|
dvp_row_irq_cnt++;
|
|
if (idx < SENSOR_HEIGHT)
|
|
{
|
|
memcpy(FrameBuffer[idx], src, BYTES_PER_LINE);
|
|
if (idx == SENSOR_HEIGHT - 1)
|
|
{
|
|
Frame_Ready_Flag = 1;
|
|
Ready_Frame_Count = dvp_frame_count;
|
|
}
|
|
}
|
|
}
|
|
}
|