⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pxa27x_camera.c

📁 Windows CE 6.0 针对PXA270的开发板的BSP参考代码
💻 C
📖 第 1 页 / 共 5 页
字号:
                bFirstVideoCaptureBufferSubmitted = TRUE;
            }

            pXPn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH0;
            pXPn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH1;
            pXPn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH2;

            pXn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH0;
            pXn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH1;
            pXn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH2;

            pLast_Pn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_Pn_CH0;
            pLast_Pn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_Pn_CH1;
            pLast_Pn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_Pn_CH2;

            pLast_n_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_n_CH0;
            pLast_n_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_n_CH1;
            pLast_n_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)VirtAddr_Last_n_CH2;

            // Chain last phantom descriptor XPn to the first phantom descriptor XP1.
            // This loops the phantom descriptor back to itself.
            pXPn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
            if (isYUV_PLANAR) pXPn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
            if (isYUV_PLANAR) pXPn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;

            // Chain the last real descriptor to the start of the phantom descriptor chain
            pXn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
            if (isYUV_PLANAR) pXn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
            if (isYUV_PLANAR) pXn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;

            // Chain the last descriptor to this new descriptor by adding this new descriptor to the end of the chain.
            // We either are already looping on the phantom descriptor by the time this frame buffer is submitted, or
            // we have yet to begin looping on the phantom descriptor.  Therefore, we must program the end of the phantom descriptor
            // to branch to the beginning of the new descriptor.  And, if we were not already looping on the phantom descriptor,
            // then we want to program the last real descriptor so that it branches to the beginning of the new descriptor.
            if (VirtAddr_Last_Pn_CH0)
            {
                pLast_Pn_CH0->DDADR = pDescriptorInfo->pPhysAddr_X1_CH0;
                if (isYUV_PLANAR) pLast_Pn_CH1->DDADR = pDescriptorInfo->pPhysAddr_X1_CH1;
                if (isYUV_PLANAR) pLast_Pn_CH2->DDADR = pDescriptorInfo->pPhysAddr_X1_CH2;

                pLast_n_CH0->DDADR = pDescriptorInfo->pPhysAddr_X1_CH0;
                if (isYUV_PLANAR) pLast_n_CH1->DDADR = pDescriptorInfo->pPhysAddr_X1_CH1;
                if (isYUV_PLANAR) pLast_n_CH2->DDADR = pDescriptorInfo->pPhysAddr_X1_CH2;
            }

            // Update pVirtAddr_Last_Pn and pVirtAddr_Last_n so they point to this new buffer
            VirtAddr_Last_Pn_CH0 = pDescriptorInfo->pVirtAddr_XPn_CH0;
            VirtAddr_Last_Pn_CH1 = pDescriptorInfo->pVirtAddr_XPn_CH1;
            VirtAddr_Last_Pn_CH2 = pDescriptorInfo->pVirtAddr_XPn_CH2;

            VirtAddr_Last_n_CH0 = pDescriptorInfo->pVirtAddr_Xn_CH0;
            VirtAddr_Last_n_CH1 = pDescriptorInfo->pVirtAddr_Xn_CH1;
            VirtAddr_Last_n_CH2 = pDescriptorInfo->pVirtAddr_Xn_CH2;

        } else if (BufferType == STILL_CAPTURE_BUFFER)
        {
          //  if (bFirstStillBufferSubmitted == FALSE)
          //  {
                StillCaptureDescriptorPhysicalStartAddress_CH0 = pDescriptorInfo->pPhysAddr_X1_CH0;
                StillCaptureDescriptorPhysicalStartAddress_CH1 = pDescriptorInfo->pPhysAddr_X1_CH1;
                StillCaptureDescriptorPhysicalStartAddress_CH2 = pDescriptorInfo->pPhysAddr_X1_CH2;
                bFirstStillBufferSubmitted = TRUE;
          //  }

                pXPn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH0;
                pXPn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH1;
                pXPn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_XPn_CH2;

                pXn_CH0 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH0;
                pXn_CH1 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH1;
                pXn_CH2 = (XLLP_DMAC_DESCRIPTOR_T *)pDescriptorInfo->pVirtAddr_Xn_CH2;

                // Chain last phantom descriptor XPn to the first phantom descriptor XP1.
                //  This loops the phantom descriptor back to itself.
                pXPn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
                if (isYUV_PLANAR) pXPn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
                if (isYUV_PLANAR) pXPn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;

                // Chain the last real descriptor to the start of the phantom descriptor chain
                pXn_CH0->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH0;
                if (isYUV_PLANAR) pXn_CH1->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH1;
                if (isYUV_PLANAR) pXn_CH2->DDADR = pDescriptorInfo->pPhysAddr_XP1_CH2;
        }
    } else 
    {
        if (!pBufInfo)
            NKDbgPrintfW(TEXT("Buffer is null.  Submit buffer failed.\r\n"));
        else
            NKDbgPrintfW(TEXT("Buffer list had null entry.  Submit buffer failed.  Buffer ID %d\r\n"),pBufInfo->BufferID);
    }
}

// Given a buffer allocated by the application, this function maps the buffer into discreet 4K chunks in the physical
// address space, then builds a DMA descriptor chain that performs a scatter gather DMA sequence using these 
// 4K chunks as individual target buffers.  It also builds a phantom descriptor chain which is executed after
// the primary descriptor chain completes.  The phantom descriptor chain is created so that the DMA can run
// continuously in the background, even if there is no client ready to read the data from the primary chain.  This 
// way primary buffers will remain untouched, the dma activity is undisturbed, the sensor is unaware of the flow control,
// and the primary buffers remain ready for their consumption by the application that submitted them.
// Buffers are chained together based on the order in which they are submitted by the application.  In this way,
// the application can now manage the buffer memory according to its own needs.  If an application needs to lock
// down a buffer, it simply chooses not to resubmit that buffer until it has completed using it.
int CameraPrepareBuffer(P_CAMERA_DMA_BUFFER_INFO pBufInfo, int BufferType)
{
        int limit = 0;
        int i = 0;
        int j = 0;
        int num_descriptors;
        int memory_required;
        int planes_number;

        DESCRIPTOR_INFO_T *pDescriptorInfo;
        DWORD *pPhysicalBufferAddress;
        DWORD *pPhysicalDescriptorBufferAddress;
        DWORD *VirtAddr;

        int fifo0_num_descriptors = 0;
        int fifo1_num_descriptors = 0;
        int fifo2_num_descriptors = 0;

        int fifo0_transfer_size = 0;
        int fifo1_transfer_size = 0;
        int fifo2_transfer_size = 0;
        int frame_size = (VIDEO_CAPTURE_BUFFER == BufferType ? g_HwContext.XllpCAMERA.Video_capture_width : g_HwContext.XllpCAMERA.Still_capture_width) * \
                                         (VIDEO_CAPTURE_BUFFER == BufferType ? g_HwContext.XllpCAMERA.Video_capture_height : g_HwContext.XllpCAMERA.Still_capture_height) * 2;

        unsigned int capture_onput_format;


        if (VIDEO_CAPTURE_BUFFER == BufferType)
        {
            capture_onput_format = g_HwContext.XllpCAMERA.Video_capture_output_format;
        }
        else
        {
            capture_onput_format = g_HwContext.XllpCAMERA.Still_capture_output_format;

        }

        // Determine the length of the image transfer.  This is the sum of each fifo transfer length.
        switch(capture_onput_format) 
        {
                case XLLP_CAMERA_IMAGE_FORMAT_RGB555:
                case XLLP_CAMERA_IMAGE_FORMAT_RGB565:
                        fifo0_transfer_size = frame_size;
                        planes_number = 1;
                        break;
                case XLLP_CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
                        fifo0_transfer_size = frame_size;
                        planes_number = 1;
                        break;
                case XLLP_CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
                        fifo0_transfer_size = frame_size / 2;
                        fifo1_transfer_size = frame_size / 4;
                        fifo2_transfer_size = frame_size / 4;
                        planes_number = 3;
                        break;
                default:
                        NKDbgPrintfW(TEXT("Unsupported capture format.\r\n"));
                        return FALSE;
                        break;
        }

        // Allocate some memory to store the physical address of each descriptor used to map each 4K segment
        // We need one set of descriptors to DMA the data to a real buffer.  We need another set of descriptors
        // (phantom descriptors) to DMA the data to non-incrementing address that will be used only for flow control.
        // Therefore, twice as many descriptors are required for the whole chain, than for just the primary DMA sequence.
        // We can obtain physical addresses with 4K granularity.  And the pages are not guaranteed to be contiguous.  
        // Therefore, we'll dedicate one descriptor for every 4K of image data.

        fifo0_num_descriptors = (( fifo0_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                                 / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
        fifo1_num_descriptors = (( fifo1_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                                 / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;
        fifo2_num_descriptors = (( fifo2_transfer_size + SINGLE_DESCRIPTOR_TRANSFER_MAX -1 )
                                 / SINGLE_DESCRIPTOR_TRANSFER_MAX) * 2;

        num_descriptors = fifo0_num_descriptors + fifo1_num_descriptors + fifo2_num_descriptors;
        
        memory_required = ((num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX);
        
        if (pBufInfo->size < memory_required)
        {
                pBufInfo->size = memory_required;
                //NKDbgPrintfW(TEXT("Memory size inadequate.  Need %d bytes\r\n"),pBufInfo->size);
                return FALSE;
        }

        if (NumBuffers >= MAX_CAMERA_DMA_BUFFERS)
        {
                NKDbgPrintfW(TEXT("Max number of buffers reached.\r\n"));
                return FALSE;
        }

        MasterBufferList[NumBuffers] = (DESCRIPTOR_INFO_T *)malloc(sizeof(DESCRIPTOR_INFO_T));
        if (MasterBufferList[NumBuffers] == NULL)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for entry into MasterBufferList.\r\n"));
                return FALSE;
        }

        pDescriptorInfo = MasterBufferList[NumBuffers];
        memset(pDescriptorInfo, 0x0, sizeof(DESCRIPTOR_INFO_T));
        
        // Assign a unique frame ID
        pDescriptorInfo->FrameID = NumBuffers;
        pBufInfo->BufferID = NumBuffers;

        pDescriptorInfo->dwPlanesNumber = planes_number;
		VirtAddr = (DWORD *)pBufInfo->VirtAddr;



        // Set the memory to uncached, unbuffered
        VirtualSetAttributes((void *)VirtAddr, memory_required, 0, 0xC, NULL);

        pBufInfo->pY = (DWORD *)pBufInfo->VirtAddr;
        pBufInfo->pCb = (DWORD *)pBufInfo->VirtAddr + (((fifo0_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4);
        pBufInfo->pCr = (DWORD *)pBufInfo->VirtAddr + (((fifo0_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4)
                                                    + (((fifo1_num_descriptors / 2) * SINGLE_DESCRIPTOR_TRANSFER_MAX) / 4);

        // This list holds a pointer to each physical destination buffer
        pDescriptorInfo->pBufferPhyAddress = (DWORD *)malloc(num_descriptors * sizeof(DWORD));
        if (pDescriptorInfo->pBufferPhyAddress == NULL)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pBufferPhyAddress.\r\n"));
                return FALSE;
        }

        pDescriptorInfo->pBufferVirtAddress = VirtAddr;


        // Allocate memory for the descriptor buffer list, plus one dummy entry in order to simplify the buffer chaining logic
        // The last entry in the descriptor chain needs an entry for the DDADR register, and if we allocate an extra unused entry
        // in this list, we can assign the dummy value without any harm.
        pDescriptorInfo->pDescriptorBufferPhyAddress = (DWORD *)malloc((num_descriptors + 1) * sizeof(DWORD));
        if (!pDescriptorInfo->pDescriptorBufferPhyAddress)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pDescriptorBufferPhyAddress\r\n"));
                return FALSE;
        }


        pDescriptorInfo->pDescriptorBufferVirtAddress = (DWORD *)malloc((num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
        if (!pDescriptorInfo->pDescriptorBufferVirtAddress)
        {
                NKDbgPrintfW(TEXT("Unable to allocate memory for pDescriptorInfo->pDescriptorBufferVirtAddress\r\n"));
                return FALSE;
        }

        memset(pDescriptorInfo->pDescriptorBufferVirtAddress, 0x0, (num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));

        // Set the descriptor memory to uncached, unbuffered so that the descriptors have valid data in them when read by the DMA engine later.
        VirtualSetAttributes((void *)pDescriptorInfo->pDescriptorBufferVirtAddress, (num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T), 0, 0xC, NULL);

        // Create the lookup table that maps the user allocated virtual buffer address to the corresponding physical address.
        // We know that buffers are contiguous within each 4K segment.

        pPhysicalBufferAddress = pDescriptorInfo->pBufferPhyAddress;
        limit = (DWORD)VirtAddr + pBufInfo->size;
        // Now determine the physical addresses for each 4K segment and store them in the array maintained for this descriptor chain
        for (i = (DWORD)VirtAddr; i < limit; i+= SINGLE_DESCRIPTOR_TRANSFER_MAX)
        {
                getPhyAddress ((DWORD *)i, pPhysicalBufferAddress);
                //NKDbgPrintfW(TEXT("Target Buffer Virtual Address 0x%x has Physical address 0x%x\r\n"),i, *pPhysicalBufferAddress);
                pPhysicalBufferAddress++;
        }

        // Create the lookup table that maps the virtual address space that was just allocated for the descriptors to the corresponding physical address.
        pPhysicalDescriptorBufferAddress = pDescriptorInfo->pDescriptorBufferPhyAddress;        
        limit = (DWORD)(pDescriptorInfo->pDescriptorBufferVirtAddress) + ((num_descriptors + 1) * sizeof(XLLP_DMA_DESCRIPTOR_T));
        // Now determine the physical addresses for each descriptor address and store them in the array maintained for this descriptor chain
        for (i = (DWORD)(pDescriptorInfo->pDescriptorBufferVirtAddress); i < limit; i+= sizeof(XLLP_DMA_DESCRIPTOR_T))
        {
                getPhyAddress ((DWORD *)i, pPhysicalDescriptorBufferAddress);
                //NKDbgPrintfW(TEXT("Descriptor Virtual Address 0x%x has Physical address 0x%x\r\n"),i, *pPhysicalDescriptorBufferAddress);
                pPhysicalDescriptorBufferAddress++;
        }

        // Make sure we align the buffer
        if (VirtAddr_Phantom_Buffer == 0x0)
        {
                VirtAddr_Phantom_Buffer_Base_Address = (DWORD)((DWORD *)malloc(SINGLE_DESCRIPTOR_TRANSFER_MAX + 0xFFF));
                if (VirtAddr_Phantom_Buffer_Base_Address == 0x0)
                {
                        NKDbgPrintfW(TEXT("Unable to allocate memory for VirtAddr_Phantom_Buffer\r\n"));
                        return FALSE;
                }

                VirtAddr_Phantom_Buffer = VirtAddr_Phantom_Buffer_Base_Address;

                if (VirtAddr_Phantom_Buffer & 0xFFF)
                {
                        VirtAddr_Phantom_Buffer += 0x1000 - (VirtAddr_Phantom_Buffer & 0xFFF);
                }

                getPhyAddress ((DWORD *)VirtAddr_Phantom_Buffer, &((DWORD)PhysAddr_Phantom_Buffer));
                //NKDbgPrintfW(TEXT("Phantom buffer Virtual Address 0x%x has Physical address 0x%x\r\n"),VirtAddr_Phantom_Buffer, PhysAddr_Phantom_Buffer);
        }

        pDescriptorInfo->pPhysAddr_Phantom = PhysAddr_Phantom_Buffer;

        GenerateDMAChain( pDescriptorInfo, fifo0_transfer_size, fifo1_transfer_size, fifo2_transfer_size);

        NumBuffers++;

//      return (int)pDescriptorInfo->FrameID;
        return TRUE;
}

// Generate a primary descriptor chain that fills the provided buffers.
// Generate a phantom descriptor chain that executes after the primary chain.
// When buffers are chained together, each primary chain is linked to the next primary
// descriptor chain.  The last primary descriptor chain is linked to the phantom descriptor chain.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -