ARM&WINCE 多通道数据采集驱动实现思路(求高手指点)

来源:互联网 发布:求二叉树的高度算法 编辑:程序博客网 时间:2024/04/29 22:10

     本人要编一个多通道数据采集的驱动程序,硬件采用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
}

     望高手帮忙整理一下思路。不胜感激! 

原创粉丝点击