#pragma once
#include "DMACtrl.h"
class CLumDataCtrl //父类 通用类
{
public:
// 构造函数
CLumDataCtrl(const string & sDMADriverFile, int iType = 1);
// 析构函数
~CLumDataCtrl();
// 初始化
int iInitilize(int iDataLen);
public:
// 采集亮度数据
int iSampleLumData(unsigned char * &lumData, int &iLen);
private:
// DMA控制
CDMACtrl *m_pDmaCtrl;
};
#include <unistd.h>
#include "LumDataCtrl.h"
#include "DMAProxyCtrl.h"
// 最大轮询次数
const int cniLoopNum = 3;
// 构造函数
CLumDataCtrl::CLumDataCtrl(const string & sDMADriverFile, int iType)
{
if (1 == iType)
{
m_pDmaCtrl = new CDMAProxyCtrl(sDMADriverFile);
}
else
{
m_pDmaCtrl = new CDMACtrl(sDMADriverFile);
}
return;
}
CLumDataCtrl::~CLumDataCtrl()
{
if (nullptr != m_pDmaCtrl)
{
delete m_pDmaCtrl;
m_pDmaCtrl = nullptr;
}
return;
}
// 初始化
int CLumDataCtrl::iInitilize(int iDataLen)
{
return m_pDmaCtrl->iInitialize(iDataLen);
}
// 采集亮度数据
int CLumDataCtrl::iSampleLumData(unsigned char * &lumData, int &iLen)
{
if (0 != m_pDmaCtrl->iStartSample())
{
return EXIT_FAILURE;
}
int iCounter = 0;
while (m_pDmaCtrl->iGetSampleFinishedStatus() != 0 && iCounter < cniLoopNum)
{
usleep(1);
iCounter++;
}
if (m_pDmaCtrl->iReadDMAData(lumData, iLen) < 0)
{
printf("iReadDMAData fail !");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
子类 read方式传输:
#pragma once
#include <string>
using namespace std;
const int cniRowDataSize = 2048;
const int cniRowDescSize = 128;
const int cniOnceSampleRowNum = 64;
const int cniOnceDMADataSize = (cniRowDataSize + cniRowDescSize) * cniOnceSampleRowNum;
class CDMACtrl
{
public:
// 构造函数
CDMACtrl(const string & sDriverFile);
// 析构函数
virtual ~CDMACtrl();
// 初始化
virtual int iInitialize(int iDataLen);
public:
inline void SetDriverFile(const string &sDriverFile)
{
m_sDriverFile = sDriverFile;
return;
}
inline string sGetDriverFile() const
{
return m_sDriverFile;
}
inline int iGetDriverHandle() const
{
return m_iDriverHandle;
}
// 开始采集
virtual int iStartSample();
// 采集完成标识
virtual int iGetSampleFinishedStatus();
// 读取DMA数据
virtual int iReadDMAData(unsigned char * &rdBuf, int &iLen);
private:
// 驱动文件句柄
int m_iDriverHandle;
// 驱动文件
string m_sDriverFile;
// 驱动文件映射内存
//void * m_pMap;
};
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "DMACtrl.h"
#define IOCTL_ARG1 0xFB
#define DMA_START_RD_COMMAND _IO(IOCTL_ARG1,1)
#define DMA_START_WR_COMMAND _IO(IOCTL_ARG1,2)
#define DMA_WAIT_WR_FINISH_COMMAND _IO(IOCTL_ARG1,3)
#define DMA_WAIT_RD_FINISH_COMMAND _IO(IOCTL_ARG1,4)
const unsigned int cnuiMapAddrSize = 0x22000;
// 构造函数
CDMACtrl::CDMACtrl(const string & sDriverFile)
{
m_sDriverFile = sDriverFile;
m_iDriverHandle = -1;
//m_pMap = MAP_FAILED;
return;
}
// 析构函数
CDMACtrl::~CDMACtrl()
{
/*if (MAP_FAILED != m_pMap)
{
munmap(m_pMap, cnuiMapAddrSize);
}*/
if (-1 != m_iDriverHandle)
{
close(m_iDriverHandle);
m_iDriverHandle = -1;
}
return;
}
// 初始化
int CDMACtrl::iInitialize(int iDataLen)
{
m_iDriverHandle = open(m_sDriverFile.c_str(), O_RDWR);
if (m_iDriverHandle < 0)
{
return EXIT_FAILURE;
}
else
{
/*m_pMap = mmap(nullptr, cnuiMapAddrSize, PROT_READ|PROT_WRITE, MAP_SHARED, m_iDriverHandle, 0);
if (MAP_FAILED == m_pMap)
{
ostringstream os;
os << "failed to mmap [" << m_sDriverFile << "]" << endl;
CLog::GetInstance()->WriteLog(__FUNCTION__, __LINE__, os.str(), Log_Error);
}*/
return EXIT_SUCCESS;
}
}
// 开始采集
int CDMACtrl::iStartSample()
{
int iLen = cniOnceDMADataSize * 4;
return ioctl(m_iDriverHandle, DMA_START_RD_COMMAND, &iLen);
}
// 采集完成标识
int CDMACtrl::iGetSampleFinishedStatus()
{
int iLen = cniOnceDMADataSize * 4;
return ioctl(m_iDriverHandle, DMA_WAIT_RD_FINISH_COMMAND, &iLen);
}
// 读取DMA数据
int CDMACtrl::iReadDMAData(unsigned char * &rdBuf, int &iLen)
{
//iLen = cniOnceDMADataSize;
rdBuf = new unsigned char[iLen];
/*if (MAP_FAILED != m_pMap)
{
memcpy(rdBuf, m_pMap, cniOnceDMADataSize);
return iLen;
}
else*/
{
int len = read(m_iDriverHandle, rdBuf, iLen);
return len;
}
}
子类mmap方式传输:
#pragma once
#include <string>
#include "DMACtrl.h"
#include "dma-proxy.h"
using namespace std;
class CDMAProxyCtrl:public CDMACtrl
{
public:
// 构造函数
CDMAProxyCtrl(const string & sDriverFile);
// 析构函数
~CDMAProxyCtrl();
// 初始化
int iInitialize(int iDataLen);
public:
// 开始采集
virtual int iStartSample();
// 采集完成标识
virtual int iGetSampleFinishedStatus();
// 读取DMA数据
virtual int iReadDMAData(unsigned char * &rdBuf, int &iLen);
private:
// 驱动文件句柄
channel_buffer *m_pChannelBuffer;
};
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "DMAProxyCtrl.h"
#include <string>
#include<iostream>
using namespace std;
// 构造函数
CDMAProxyCtrl::CDMAProxyCtrl(const string & sDriverFile)
:CDMACtrl(sDriverFile)
{
m_pChannelBuffer = (channel_buffer *)MAP_FAILED;
return;
}
// 析构函数
CDMAProxyCtrl::~CDMAProxyCtrl()
{
if (MAP_FAILED != m_pChannelBuffer)
{
munmap(m_pChannelBuffer, sizeof(struct channel_buffer));
m_pChannelBuffer = nullptr;
}
return;
}
// 初始化
int CDMAProxyCtrl::iInitialize(int iDataLen)
{
if (EXIT_FAILURE == CDMACtrl::iInitialize(iDataLen))
{
return EXIT_FAILURE;
}
m_pChannelBuffer = (struct channel_buffer *)mmap(NULL, sizeof(struct channel_buffer) * RX_BUFFER_COUNT,
PROT_READ | PROT_WRITE, MAP_SHARED, iGetDriverHandle(), 0);
m_pChannelBuffer[0].length = iDataLen; //m_pChannelBuffer->length = cniOnceDMADataSize;
return EXIT_SUCCESS;
}
// 开始采集
int CDMAProxyCtrl::iStartSample()
{
int iChannelIndex = 0;
return ioctl(iGetDriverHandle(), START_XFER, &iChannelIndex);
}
// 采集完成标识
int CDMAProxyCtrl::iGetSampleFinishedStatus()
{
int iChannelIndex = 0;
return ioctl(iGetDriverHandle(), FINISH_XFER, &iChannelIndex);
}
// 读取DMA数据
int CDMAProxyCtrl::iReadDMAData(unsigned char * &rdBuf, int &iLen)
{
//iLen = cniOnceDMADataSize;
rdBuf = new unsigned char[iLen];
if (MAP_FAILED != m_pChannelBuffer)
{
//string *p = new string[iLen];
//p = 9;
//memcpy((void*)m_pChannelBuffer->buffer, p, sizeof(unsigned int));
memcpy(rdBuf, (void*)m_pChannelBuffer->buffer, iLen);
//memcpy(rdBuf, (void*)m_pChannelBuffer->buffer, cniOnceDMADataSize);
return iLen;
}
else
{
printf("transport by read");
return read(iGetDriverHandle(), rdBuf, iLen);
}
}
主程序测试最佳带宽main:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<iostream>
#include <iomanip>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string>
#include "LumDataCtrl.h"
#include <time.h>
#include <fstream>
#include<sys/stat.h>
#include<sys/types.h>
using namespace std;
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define BASE_ADDR 0x40000000
#define PAGE_SIZE ((size_t) getpagesize()) // 分配地址大小
#define PAGE_MASK ((uint32_t)(long)~(PAGE_SIZE-1)) // 分配地址掩码
#define DEV_MEM_SIZE (PAGE_SIZE*2)
#define DEV_MEM_MASK ((uint32_t)(long)~(DEV_MEM_SIZE-1)) // 分配地址掩码
#define WR_DMARDLEN_OFFSET 60 // 写DMA读长度寄存器偏移值
#define CAPTURE_OFFSET 24
const int cniScanRowLowerLimit = 0;
const int cniScanRowUpperLimit = 1023;
int main(int argv, char ** args)
{
if (argv < 2)
{
cout << "Please Enter DMAType(0 or 1)" << endl;
return EXIT_FAILURE;
}
int iDMAType = 1;
if ("0" == string(args[1]) || "1" == string(args[1]))
{
iDMAType = stoi(args[1]);
}
ofstream ofs;
ofs.open("DMA_test_bind.txt", ios::out);
unsigned char *m_bsRawLumData = nullptr;
int m_iDataLen;// 原始亮度数据长度
int cniRawLumRowDataSize = 2176*64;
const string cnsDMADriverName = "/dev/axiDmaPoxy";
CLumDataCtrl lumDataCtrl(cnsDMADriverName, iDMAType);
//int iLen = cniOnceDMADataSize;
int rowNum = 128; //初始row 开始的行数
int DMAiLen = 2176 * rowNum; //一次传输数据的大小
unsigned char *bsData = nullptr;
double ibandwidth = 0; //带宽 MB/S
double ibandwidth_next = 0;
while (1) //外循环 退出循环条件是带宽发生下降或者大于了驱动的内存大小
{
//********************************
if (EXIT_FAILURE == lumDataCtrl.iInitilize(DMAiLen))
{
cout << "failed to initialize LumDataCtrl" << endl;
return EXIT_FAILURE;
}
int fd = -1;
volatile void *addr = NULL;
volatile void * virt_addr = NULL;
//打开文件
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (-1 == fd)
{
printf("error:failed to open file[/dev/mem]\n");
return 1;
}
//映射到内存
addr = mmap(NULL, DEV_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDR);
if (MAP_FAILED == addr)
{
close(fd);
printf("failed to mmap phy-addr to virtual-addr\n");
return 1;
}
virt_addr = (volatile void *)((uint32_t)addr & DEV_MEM_MASK);
printf("PhyAddr:%x mamped to VirtAddr:%x, reg0:%x\n", BASE_ADDR, (uint32_t)virt_addr, *(volatile uint32_t *)(virt_addr));
// 停止扫描
unsigned int uiParam = (4 << 28) | (cniScanRowLowerLimit << 16) | cniScanRowUpperLimit;
memcpy(((char*)virt_addr + CAPTURE_OFFSET), (void*)&uiParam, sizeof(unsigned int)); // 写方式一
// 设置函数
unsigned int uiLineNum = rowNum | (0x5a5a << 16);
memcpy(((char*)virt_addr + WR_DMARDLEN_OFFSET), (void*)&uiLineNum, sizeof(unsigned int)); // 写方式一
//(unsigned int *)(virt_addr+WR_DMARDLEN_OFFSET) = uiLineNum; // 写方式二
//开始扫描
uiParam = (5 << 28) | (cniScanRowLowerLimit << 16) | cniScanRowUpperLimit;
memcpy(((char*)virt_addr + CAPTURE_OFFSET), (void*)&uiParam, sizeof(unsigned int)); // 写方式一
//断开映射
munmap((void *)addr, BASE_ADDR);
//关闭文件
close(fd);
//********************************
int i = 0;
time_t tStartTime = time(NULL);
int iInterval = 0;
while (1) //内循环, 退出循环条件达到十分钟
{
if (EXIT_FAILURE == lumDataCtrl.iSampleLumData(bsData, DMAiLen))
{
cout << "failed to sample lumData" << endl;
return EXIT_FAILURE;
}
i++; //记录次数
if (nullptr != bsData) //清空数据缓存
{
delete bsData;
bsData = nullptr;
}
if ((iInterval = time(NULL) - tStartTime)> 10) //更新时间 计算时间间隔
{
ofs << " 600s end! /n" << endl;
break;
}
}
ofs << " times = " << i << endl; //记录结束次数*/
long long Mbit = 1048576;
long long j = i;
long long size_MB = Mbit * 10;
long long size_DMA = j * DMAiLen;
long long ibandwidth = size_DMA / size_MB; //记录性能带宽
if (ibandwidth < ibandwidth_next) //判断这次计算的带宽和上次的带宽MB/S
{
ofs << " bind = " << ibandwidth << endl;
ofs << " best_bind = " << ibandwidth_next << endl; //带宽开始下降,停止运行获取最优带宽, 最优带宽
ofs << " row = " << rowNum << endl;
ofs << " DMAiLen = " << DMAiLen << endl;
// break;
}
else
{
ofs << " bind = " << ibandwidth << endl; //当前带宽
ofs << " row = " << rowNum << endl;
ofs << " DMAiLen = " << DMAiLen << endl;
}
ibandwidth_next = ibandwidth; //保存这次记录的带宽*/
// 一次循环后长度加倍 呈现2的指数上升
rowNum = rowNum + 16; // 行数加倍*/
DMAiLen = 2176 * rowNum;
}
ofs.close();
return 0;
}
主程序验证正确性main:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<iostream>
#include <iomanip>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string>
#include "LumDataCtrl.h"
#include <time.h>
#include <fstream>
#include<sys/types.h>
#include<sys/stat.h>
using namespace std;
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define BASE_ADDR 0x40000000
#define PAGE_SIZE ((size_t) getpagesize()) // 分配地址大小
#define PAGE_MASK ((uint32_t)(long)~(PAGE_SIZE-1)) // 分配地址掩码
#define DEV_MEM_SIZE (PAGE_SIZE*2)
#define DEV_MEM_MASK ((uint32_t)(long)~(DEV_MEM_SIZE-1)) // 分配地址掩码
#define WR_DMARDLEN_OFFSET 60 // 写DMA读长度寄存器偏移值
#define CAPTURE_OFFSET 24
const int cniScanRowLowerLimit = 0;
const int cniScanRowUpperLimit = 1023;
int main(int argv, char ** args)
{
if (argv < 2)
{
cout << "Please Enter DMAType(0 or 1)" << endl;
return EXIT_FAILURE;
}
int iDMAType = 1;
if ("0" == string(args[1]) || "1" == string(args[1]))
{
iDMAType = stoi(args[1]);
}
ofstream ofs;
ofs.open("DMA_test_bind.txt", ios::out);
int fd = -1;
volatile void *addr = NULL;
volatile void * virt_addr = NULL;
unsigned char *bsData = nullptr;
int rowNum = 1024; //初始row
int iDMALen = 2176 * rowNum;
const string cnsDMADriverName = "/dev/axiDmaPoxy";
CLumDataCtrl lumDataCtrl(cnsDMADriverName, iDMAType);
if (EXIT_FAILURE == lumDataCtrl.iInitilize(iDMALen))
{
cout << "failed to initialize LumDataCtrl" << endl;
return EXIT_FAILURE;
}
//打开文件
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (-1 == fd)
{
printf("error:failed to open file[/dev/mem]\n");
return 1;
}
//映射到内存
addr = mmap(NULL, DEV_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDR);
if (MAP_FAILED == addr)
{
close(fd);
printf("failed to mmap phy-addr to virtual-addr\n");
return 1;
}
virt_addr = (volatile void *)((uint32_t)addr & DEV_MEM_MASK);
printf("PhyAddr:%x mamped to VirtAddr:%x, reg0:%x\n", BASE_ADDR, (uint32_t)virt_addr, *(volatile uint32_t *)(virt_addr));
// 停止扫描
unsigned int uiParam = (4 << 28) | (cniScanRowLowerLimit << 16) | cniScanRowUpperLimit;
memcpy(((char*)virt_addr + CAPTURE_OFFSET), (void*)&uiParam, sizeof(unsigned int)); // 写方式一
// 设置函数
unsigned int uiLineNum = rowNum | (0x5a5a << 16);
memcpy(((char*)virt_addr + WR_DMARDLEN_OFFSET), (void*)&uiLineNum, sizeof(unsigned int)); // 写方式一
//(unsigned int *)(virt_addr+WR_DMARDLEN_OFFSET) = uiLineNum; // 写方式二
//开始扫描
uiParam = (5 << 28) | (cniScanRowLowerLimit << 16) | cniScanRowUpperLimit;
memcpy(((char*)virt_addr + CAPTURE_OFFSET), (void*)&uiParam, sizeof(unsigned int)); // 写方式一
//断开映射
munmap((void *)addr, BASE_ADDR);
//关闭文件
close(fd);
unsigned int data_dma = 0;
unsigned int data_dma2 = 0;
while(1)
{
if (EXIT_FAILURE == lumDataCtrl.iSampleLumData(bsData, iDMALen))
{
cout << "failed to sample lumData" << endl;
return EXIT_FAILURE;
}
data_dma = *(unsigned int*)(bsData+24);
if ((data_dma-data_dma2) != rowNum)
{
cout << "failed to DMAData transform, preIndex:" << hex << setw(8) << setfill('0') << data_dma2;
cout << ", CurIndex:" << hex << setw(8) << setfill('0') << data_dma << endl;
}
if (nullptr != bsData) //清空数据缓存
{
delete bsData;
bsData = nullptr;
}
data_dma2 = data_dma;
}
/*cout << " DMA data:" << endl;
for (int i = 0; i < DMAiLen; i++)
{
if (i != 0 && 0 == i % 16)
{
cout << endl;
}
cout << hex << setw(2) << setfill('0') << (int)bsData[i];
}*/
ofs.close();
return 0;
}
逻辑框图:
对应地址: