5730|10

73

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

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
}

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



此帖出自WindowsCE论坛

最新回复

顶~~  详情 回复 发表于 2010-6-7 21:51
点赞 关注
 

回复
举报

88

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
帮顶吧
此帖出自WindowsCE论坛
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
条理较乱
从程序中并没看到PWM的作用。 没看到你用什么作为采样开始的中断源。
用芯片的timer作中断源不可以么?
if(!(InterruptInitialize(g_ADCSysIntr,gWaitEvent,0,0)))
也没有用
因为你read_adc是通过轮询来保证转换完成的。
此帖出自WindowsCE论坛
 
 
 

回复

65

帖子

0

TA的资源

一粒金砂(初级)

4
 
通过设置PMW寄存器的预分频值、分频值、TCNTB0, TCMPB0,输出一定频率和脉宽的波形,在脉宽的下降沿触发中断,该中断触发线程,将中断与事件关联,实现AD转换

你是打算设置PWM输出,然后再输入到外部中断口?我觉得,你不如直接开一个PWM中断,这样还省了一个步骤。
此帖出自WindowsCE论坛
 
 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

5
 
引用 2 楼 rushonin 的回复:
条理较乱
从程序中并没看到PWM的作用。 没看到你用什么作为采样开始的中断源。
用芯片的timer作中断源不可以么?
if(!(InterruptInitialize(g_ADCSysIntr,gWaitEvent,0,0)))
也没有用
因为你read_adc是通过轮询来保证转换完成的。

那我用PWM timer做中断源,用什么语句触发中断呢?
此帖出自WindowsCE论坛
 
 
 

回复

90

帖子

0

TA的资源

一粒金砂(初级)

6
 
引用 3 楼 peasant_lee 的回复:
通过设置PMW寄存器的预分频值、分频值、TCNTB0, TCMPB0,输出一定频率和脉宽的波形,在脉宽的下降沿触发中断,该中断触发线程,将中断与事件关联,实现AD转换

你是打算设置PWM输出,然后再输入到外部中断口?我觉得,你不如直接开一个PWM中断,这样还省了一个步骤。

想了一下,就用PWM中断了。
此帖出自WindowsCE论坛
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(初级)

7
 
既然上了系统,还用什么PWM TIME啊,直接在系统应用程序中用一个线程来控制采集就行了。搞这么繁琐做什么.....





此帖出自WindowsCE论坛
 
 
 

回复

83

帖子

0

TA的资源

一粒金砂(初级)

8
 
引用 6 楼 linux_lee 的回复:
既然上了系统,还用什么PWM TIME啊,直接在系统应用程序中用一个线程来控制采集就行了。搞这么繁琐做什么.....

可是我要以一定的频率采集信号啊?
此帖出自WindowsCE论坛
 
 
 

回复

69

帖子

0

TA的资源

一粒金砂(初级)

9
 
一般的芯片都会有个timer作为中断源的啊,你片子有吗?
直接用timer定时中断就行了啊。
如果你用pwm 还要设置io口是电平还是脉冲中断,是下降沿还是上升沿中断。

timer会有对应的irq,然后通过系统映射成sysintr, 然后initializeinterrupt(sysintr,isEvent。。)
然后在一个线程里面等待isEvent, 然后read_adc 然后interruptdone。
此帖出自WindowsCE论坛
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(初级)

10
 
引用 7 楼 appleoflove 的回复:
引用 6 楼 linux_lee 的回复:
既然上了系统,还用什么PWM TIME啊,直接在系统应用程序中用一个线程来控制采集就行了。搞这么繁琐做什么.....

可是我要以一定的频率采集信号啊?


设置下线程的超时等待时间就行了。实现一个类似于定时中断的效果
此帖出自WindowsCE论坛
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

11
 
引用 8 楼 rushonin 的回复:
一般的芯片都会有个timer作为中断源的啊,你片子有吗?
直接用timer定时中断就行了啊。
如果你用pwm 还要设置io口是电平还是脉冲中断,是下降沿还是上升沿中断。

timer会有对应的irq,然后通过系统映射成sysintr, 然后initializeinterrupt(sysintr,isEvent。。)
然后在一个线程里面等待isEvent, 然后read_adc 然后int……


顶~~
此帖出自WindowsCE论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表