ARM&WINCE 多通道数据采集驱动实现思路(求高手指点)
[复制链接]
本人要编一个多通道数据采集的驱动程序,硬件采用S3C2410A,操作系统是wince,开发工具是PB。第一次接触这些东西,思路有些乱:
数据采集的频率由S3C2410A自带的PWM Timer实现,通过设置PMW寄存器的预分频值、分频值、TCNTB0, TCMPB0,输出一定频率和脉宽的波形,在脉宽的下降沿触发中断,该中断触发线程,将中断与事件关联,实现AD转换。在调用的AD转换函数中实现采样数据读取,放入缓存,更改采样通道的设置。
在ADC_Init()中应用VirtualAlloc()和VirtualCopy()完成物理地址映射成虚拟地址,需要该操作的寄存器有PWM、ADC、GPIO,不确定是否涉及INT。线程函数也放在这里。
DWORD ADC_Init(DWORD dwcontext)
{
DWORD IDThread;
RETAILMSG( 1, (TEXT("Initialing pADCIOreg!\r\n")));
//分配空间
pADCIOreg = ( ADCreg * )VirtualAlloc( 0, sizeof(ADCreg), MEM_RESERVE, PAGE_NOACCESS );
if( !pADCIOreg )
{
RETAILMSG( 1, (TEXT("Unable to alloc memory for ADCIOreg!\r\n")));
return NULL;
}
if( !VirtualCopy((PVOID)pADCIOreg, (PVOID)(ADC_BASE), sizeof(ADCreg),
PAGE_READWRITE | PAGE_NOCACHE ))
{
RETAILMSG(1, (TEXT("For ADCIOreg, virtual copy failed!\r\n")));
return NULL;
}
pPWMIOreg = ( PWMreg * )VirtualAlloc( 0, sizeof(PWMreg), MEM_RESERVE, PAGE_NOACCESS ); //PWMreg,结构体,定义在s2410.h中
if( !pPWMIOreg )
{
RETAILMSG( 1, (TEXT("Unable to alloc memory for PWMIOreg!\r\n")));
return NULL;
}
if( !VirtualCopy((PVOID)pPWMIOreg, (PVOID)(PWM_BASE), sizeof(PWMreg),
PAGE_READWRITE | PAGE_NOCACHE ))
{
RETAILMSG(1, (TEXT("For PWMIOreg, virtual copy failed!\r\n")));
return NULL;
}
pIOPIOreg = ( IOPreg * )VirtualAlloc( 0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS );
if( !pIOPIOreg )
{
RETAILMSG( 1, (TEXT("Unable to alloc memory for IOPIOreg!\r\n")));
return NULL;
}
if( !VirtualCopy((PVOID)pIOPIOreg, (PVOID)(IOP_BASE), sizeof(IOPreg),
PAGE_READWRITE | PAGE_NOCACHE ))
{
RETAILMSG(1, (TEXT("For IOPIOreg, virtual copy failed!\r\n")));
return NULL;
}
pINTIOreg = ( INTreg * )VirtualAlloc( 0, sizeof(INTreg), MEM_RESERVE, PAGE_NOACCESS ); ???????????????????????????????
if( !pINTIOreg )
{
RETAILMSG( 1, (TEXT("Unable to alloc memory for INTIOreg!\r\n")));
return NULL;
}
if( !VirtualCopy((PVOID)pINTIOreg, (PVOID)(INT_BASE), sizeof(INTreg),
PAGE_READWRITE | PAGE_NOCACHE ))
{
RETAILMSG(1, (TEXT("For INTIOreg, virtual copy failed!\r\n")));
return NULL;
}
if(!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&g_ADCIrq,sizeof(UINT32),&g_ADCIrq,sizeof(UINT32),NULL)) //在底层调用OAL层实现的OEMIoContorl函数
{
RETAILMSG(1,(TEXT("ERROR:EINTKey:Failed to request sysintr value for Timer interrupt.\r\n")));
return(0);
}
RETAILMSG(1,(TEXT("INFO:EINTKey:Mapped Irq 0x%x to SysIntr 0x%x.\r\n"),g_ADCIrq,g_ADCSysIntr));
gADCIntrThread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)ADCTIMER_IntrThread,0,0,&IDThread);
if(gADCIntrThread==NULL)
{
RETAILMSG(1,(TEXT(":::ADC_Init:CreateThread() Fail.\r\n")));
KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR,&g_ADCSysIntr,sizeof(UINT32),NULL,0,NULL);
return 0;
}
gADCEvent[0]=CreateEvent(NULL,FALSE,FALSE,NULL); //创建两个事件
gADCEvent[1]=CreateEvent(NULL,FALSE,FALSE,NULL);
RETAILMSG(1,(TEXT(":::ADC_Init Successfully!\r\n")));
return (DWORD)1;
}
DWORD ADCTIMER_IntrThread(PVOID pArg) //中断服务线程,进行定时器中断时的中断处理
{
DWORD ret;
gWaitEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
if(!(InterruptInitialize(g_ADCSysIntr,gWaitEvent,0,0))) //(1)IST使用InterruptInitialize注册自己,将一个中断和一个事件相关联 ???????????????????????????????
{
RETAILMSG(1,(TEXT("ERROR:ADCTIMER:InterruptInitialize failed.\r\n")));
CloseHandle(gWaitEvent);
return 0;
}
while(1)
{
ret=WaitForSingleObject(gWaitEvent,INFINITE); //(2)等待中断请求。线程等待,INFINITE: 无限期等待
if((ret==WAIT_OBJECT_0)&&(g_KillIST==FALSE))
{
SetEvent(gADCEvent[0]);
RETAILMSG(1,(TEXT(":::it's time to ad convert!\r\n")));
}
else
{
CloseHandle(gWaitEvent);
RETAILMSG(1,(TEXT(":::ADCTIMER_IntrThread exit!\r\n")));
return 0;
}
InterruptDone(g_ADCSysIntr);
}
return 1;
}
采样相关的函数主要在ADC_IOControl()中实现。启动AD转换部分不太懂。
BOOL ADC_IOControl(volatile ADCreg* pADCIOreg,DWORD dwCode,PBYTE pBufIn,DWORD dwLenIn,
PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut )
{
int iDigiValue = 0;
BOOL bErr = FALSE;
DWORD ret;
switch(dwCode)
{
case IOCTL_PWM_SET_PRESCALER:
if (dwLenIn >= 2) /* 需要2个字节缓冲区 */
{
PWM_SetPrescaler(pBufIn[0], pBufIn[1]);//参一:定时器号,参二:预分频值
bErr = TRUE;
}
break;
case IOCTL_PWM_SET_DIVIDER:
if (dwLenIn >= 2) /* 需要2个字节缓冲区 */
bErr = PWM_SetDivider(pBufIn[0], pBufIn[1]);
// 设置分频值 (定时器编号, 分频值)
break;
case IOCTL_PWM_START: //设置采样率(即:pwm波形频率及占空比)
if (dwLenIn >= 3) /* 需要3个字缓冲区 */
{
DWORD t_num = *((DWORD *)pBufIn);
DWORD cycle = *((DWORD *)(pBufIn + 4));
DWORD duty = *((DWORD *)(pBufIn + 8));
// pINTIOreg->rINTMSK&=~(0x1<<10);//不屏蔽timer0的中断,即开timer0的中断
bErr = PWM_StartPWM(t_num, cycle, duty);//定时器号,TCNTB value,TCMPB value
}
break;
case IOCTL_PWM_GET_FREQUENCY:
if ((dwLenIn >= 0) && (dwLenOut > 0))
{
DWORD t_num = *((DWORD *)pBufIn);
bErr = PWM_GetFrequency(t_num, (DWORD *)pBufOut);
*pdwActualOut = 1;
}
break;
case IOCTL_SET_UP:
{
ret=WaitForMultipleObjects(2,gADCEvent,FALSE,INFINITE); //两个同步对象,gADCEvent:指向包含的所有的同步对象,FALSE:只要一个线程处于有信号状态,线程就被唤醒而继续运行。等待时间无限期
if(ret==WAIT_OBJECT_0)
{
ResetEvent(gADCEvent[0]);
//////////????????????????????????????????
//////////?????????????????????????????
/////////////////启动ad
iDigiValue = Read_Adc( pADCIOreg,*pBufIn);
*( int* )pBufOut = iDigiValue;
}
else if(ret==(WAIT_OBJECT_0+1))
{
ResetEvent(gADCEvent[1]);
}
}
break;
default:
break;
}
}
int Read_Adc( volatile ADCreg* pADCIOreg,int ch )
{
RETAILMSG(1, (TEXT("channel:%d\r\n")),ch);
pADCIOreg->rADCCON = (1<<14)|(ch<<3)|(19<<6); // setup channel (19<<6)是设置你的分频值的,19是根据你的采样频率来设置的。
//pADCIOreg->rADCCON |= 0<<3; // setup channel
pADCIOreg->rADCCON |= 0x1; // start adc
while(pADCIOreg->rADCCON & 0x1); //check if Enable_start is low
while(!(pADCIOreg->rADCCON & 0x8000)); //check if End of Conversion flag is high
return ( (int)pADCIOreg->rADCDAT0 & 0x3ff ); //return the digital value
}
望高手帮忙整理一下思路。不胜感激!