S3C2440串口FIFO模式的中断机制和处理策略

转载于: https://blog.csdn.net/Stephen_yu/article/details/19199399

引言
  基于S3C2440的串口非FIFO模式的应用文献多有介绍,但少有详细论述FIFO模式的中断机制和应用的。为了深入理解FIFO模式下的串口中断产生条件、中断类型的判断、一批连续的数据发送结束的判断和一批连续数据接收结束的判断等,笔者对比了参考文献〔1〕所示的中文版S3C2440使用手册和参考文献〔2〕所示的英文版S3C2440使用手册中的有关描述,发现两者对发送触发深度的表述有着根本性的矛盾,因此本文将通过实验综合阐述FIFO模式的中断机制和应用要点。 
1 串口内部结构和工作原理 
  S3C2440的每个串口的内部含有发送器和接收器,其中包含了64字节FIFO和数据移位器。将数据写入到FIFO,接着在发送前复制到发送移位器中。随后将在发送数据引脚(TxDn)移出数据。同样从接收数据引脚(RxDn)移入收到的数据,接着从移位器复制到FIFO〔12〕。 
2 FIFO接收中断机制和处理策略 
2.1 接收中断触发深度 
  S3C2440中在UART FIFO 控制寄存器用于设置接收和发送中断的触发深度。若设置Rx FIFO 触发深度为32字节,表示当FIFO中接收到字符达到32个时,就触发中断。如果接收的字符小于32个,在3个周期期间没有收到数据时,就触发接收超时中断。 
2.2 接收中断类型的判断 
  把接收达到触发深度引起的中断称为“接收深度满中断”。由于接收超时中断的处理和接收深度满中断的处理是不同的,有必要对接收中断类型进行判断。 
  对于Phillips公司的LPC2131,可以通过判断其寄存器UxIIR[3:0]中的相应位就可以直接知道串口接收中断类型[3]。而在S3C2440中接收深度满中断和接收超时中断则共用一个中断标志,因此不能直接判断两种类型的中断。 
  S3C2440有3个UART FIFO 状态寄存器 UFSTATn,该寄存器的位[5:0]中的Rx FIFO Count (Rx FIFO计数器)表示当前FIFO中接收到的字符个数。因此,本文采用的方法是当确定是接收中断后,通过读取UFSTATn[5:0],得到当前FIFO中接收字符的个数。若字符个数等于触发深度设置值,则说明该中断是接收深度满中断,否则就是接收超时引起的中断。 
2.3 接收数据的处理策略 
  如果接收的数据长度是随机的,有必要知道一批连续的数据接收结束的时刻,以便进一步处理。假设触发深度设置为32个字符,现有如下两种策略。 
(1) 策略一
  在中断处理的时候,当判定是接收深度满中断后,采用连续读取FIFO数据32个字节;当判定为接收超时中断,采用把FIFO里面的数据读到空为止。 
  若发送方发了33个字符,接收方就会出现两次接收中断。第一个中断是接收深度满中断,接着是接收超时中断,可以利用超时中断的产生来标志一次接收数据的结束。若发送方发了32个或者32的整数倍个字符,接收方触发的都只是接收深度满中断,因此无法确认一批连续数据是否结束。 
(2) 策略二
  在接收深度满中断的处理上,不是连续读取32个字符,而是连续读取31个字符,留1个字符在FIFO中。这样任意长度字符的接收,都会拥有一个接收超时中断,而接收超时中断的发生则认为是一次连续接收数据的结束,本文正是采用此策略。 
2.4 策略实现的验证 
  在实验中,设置串口0为接收FIFO中断模式,接收中断的触发深度为32个字节,串口1设置为非FIFO模式下的查询模式。 
  从外面往串口0送一批连续的数据,若有接收深度满中断的发生就通过串口1发送一个字符 M ;若有接收超时中断的发生就通过串口1发送一个字符 C 。最后,当串口0接收数据结束,把接收到数据全部通过串口1发送出来,对比往串口0发送的数据和串口1发送出来的数据是否相同,从而测试串口0接收中断的处理策略是否正确。 
  串口0中断服务代码中的接收数据策略实现函数UART_receive()如下:
void UART_receive(void){ 
  char temp ;
  char count;
  count=rUFSTAT0&0x3F;
  /*接收超时中断的处理*/
if(count<32){
  while((rUFSTAT0&0x3F)){//读取里面字符,直到FIFO为空
    temp=rURXH0;
    ReceiveBuffer[ReceiveIndex]=temp;
    ReceiveIndex++;
  }
  ReceiveIndex= ReceiveIndex-1; //ReceiveIndex为接收数组的元素位置索引
  flag_Receive_end=1;//flag_Receive_end为接收结束标志,值为1表示一次数据接收结束
  UART1_send_byte( C );//通过串口1发送一个字符 C ,标志接收超时中断
  }
/*接收深度满中断的处理*/
else{
  int i; 
  for(i=0; i<=30; i++){ //先读取31个,留1个
    temp=rURXH0;
    ReceiveBuffer[ReceiveIndex]=temp;
    ReceiveIndex++;
  }
  flag_Receive_end=0; //该值为0表示接收还没有结束UART1_send_byte( M );通过串口1发送一个字符 M ,标志接收深度满中断的产生 
}
/*把串口0接收到的数据通过串口1发送出去*/ 
if(flag_Receive_end==1) {
  UART1_send_string(ReceiveBuffer, ReceiveIndex+1);//调用串口1发送字符串函数
  flag_Receive_end=0;//发送完毕,恢复初值
  ReceiveIndex=0;//发送完毕,恢复初值
  }
}
  往串口0送“b12345678c12345678d12345678f12341 23456789987654321a1234567b12345” 64个字符,得到从串口1送出的数据是:
MMCb12345678c12345678d12345678f12341234567899876 54321a1234567b12345
“MMC”中的“M”表示接收深度满中断标志,“C”表示接收超时中断标志。说明接收64个字符需要三个中断,头两个是接收深度满中断,最后一个是接收超时中断。分别往串口0送27个字符、32个字符、65个字符以及100个字符,测试都能得到预想的结果,证明该处理策略是可靠的。 
3 FIFO发送中断机制和处理策略 
3.1 发送中断的产生讨论 
  参考文献[1]与参考文献[2]给出的发送FIFO中断产生的条件有矛盾。若设置发送中断触发深度为16,参考文献[1]会认为发送中断产生的时刻是从FIFO中移出16个字符的时候,而参考文献[2]则认为是从FIFO里面移出数据直到剩下16个字符的时候。 
3.2 实验方法 
  通过控制寄存器UFCONn来设置发送中断触发深度为16字节。按照笔者对参考文献[2]的理解,编写测试程序。串口0设置为FIFO中断模式,串口1设置为非FIFO查询模式。字符串通过串口0发送出去,观察串口0发送中断产生的时刻。一旦串口0有发送中断发生,则通过串口1发送一个字符 S 作为标志。 
3.3 发送策略与实现 
  由于发送数据是主动的,必然会知道需要发送数据的长度。若需要发送的字符个数大于或者等于48个字符,先把前48个字符一次性写入FIFO。当发送中断发生后,接着对剩下的字符进行发送。若不足48个,批量一次性把剩下的字符写入FIFO,否则把前48个字符一次性写入FIFO;发送中断发生,重复上述过程,直到数据发送完毕。 
  用一个公式来表达数据长度与发送周期和剩下字符数的关系,如下: 
  SendLength(数据长度)=48×Send_Cycle(发送周期)+Send_Remainder(剩下字符数) 
  若要发送100个字符,有SendLength=100,Send_Cycle=2,Send_Remainder=4。即前2次分别发送了48个字符,后一次发送了剩下的4个字符。 
  串口0中断服务程序中的发送中断处理部分关键代码如下:
void __irq UART0_interrupt(void){  
  /*发送中断处理*/
  if((rSUBSRCPND&0x1<<1)==2){
    UART1_send_byte( S ); //串口1送出字符 S ,表示串口0发送中断的产生
    /*串口0数据发送结束的处理*/
  if(flag_Send_end==1){ //flag_Send_end为数据发//送结束标志,为1表示数据发送结束
    Send_Index=0;//发送的字符在数组中的位置索引,恢复初值为0
    flag_Send_end=0;//恢复初值为0
  }
  /*串口0数据发送还没有结束的处理*/
  else{
    if(Send_Cycle!=0) {
      for(int i=0;i<48;i++){ //连续发送48个字符
        rUTXH0 = P_Send[Send_Index]; 
        Send_Index++;
      }
      Send_Cycle--;
    }
    else{
      for(int i=0;i<Send_Remainder;i++){//连续发送最后剩下的字符
        rUTXH0 = P_Send[Send_Index]; 
        Send_Index++;
      }
      flag_Send_end=1; //给一个数据发送完毕的标志
    }
  }
  /*清除中断标志位*/
  rSUBSRCPND |=0x2;
  rSRCPND |=1<<28 ;
  rINTPND |=1<<28 ;
  }
}
  main.c中其他相关代码如下:
char SendBuffer[2000]="b12345678c12345678d12345678 f1234123456789987654321a1234567b12345p12345678998765432 1a1234567b12345MKL";
char *P_Send;//发送数据指针
U16 SendLength=100;//自定义发送字符个数
U16 Send_Cycle;//48个字符发送的循环周期数
U16 Send_Remainder ;//剩下字符数
U16 Send_Index=0;//发送字符在数组中的索引位置
char flag_Send_end=0;//从0变为1表示一次连续发送结束,处理后重新置0
……
void SendData(char* Data, U16 Length){//串口0发送指定长度的字符串函数
  Send_Index=0;
  flag_Send_end=0;
  P_Send=Data;
  Send_Cycle=Length/48;
  Send_Remainder=Length%48;
  if(Send_Cycle!=0){
    for(int i=0;i<48;i++){
      rUTXH0 = Data[Send_Index]; 
      Send_Index++;
    }
    Send_Cycle--;
  }
  else{
    for(int i=0;i<Send_Remainder;i++){
      rUTXH0 = Data[Send_Index]; 
      Send_Index++;
    }
    flag_Send_end=1;//给一个数据发送完毕的标志
  }
}
int main(void){
  ……
  SendData(SendBuffer,SendLength);//启动串口0发送指定长度字符串
  return 0;
}
3.4 测试结果分析 
  main.c中的SendBuffer[2000]字符数组用于存放测试用的发送数据,根据发送数据长度的需要设置发送长度SendLength的大小。 
  运行程序后,从串口0送出的数据为: 
  b12345678c12345678d12345678f1234123456789987 654321a1234567b12345p123456789987654321a1234567b12 345MKL 
  该结果跟指定发送的字符数组里面的数据一致,说明串口0成功发送了数据。 
  从串口1送出的数据为:SSS。该结果说明发生了3次发送中断,分析如下: 
  先往FIFO里面写入前48个字符。在硬件的机制作用下,一个个字符从FIFO里面移出,FIFO里面剩下16个字符时就触发中断,中断处理时,继续写入剩下数据中的前48个字符。新写入的48个字符不会覆盖FIFO中剩下的16个字符,由于48加上16刚好等于64,而FIFO有64个字节空间,而且写入的时候,剩下的16个字符也会一个个移出,所以不会有新数据把旧数据覆盖的可能写入48个字符后,退出中断。在内部机制的作用下,随着字符的一个个移出,当重新剩下16个字符时触发中断,中断处理时把最后剩下的4个字符写入FIFO,并给一个数据发送完毕的标志,退出中断服务。随着一个一个字符从FIFO里面移出,当FIFO里面又重新剩下16个字符时就触发中断,不过这次中断在中断处理时,根据判断数据已经有发送完毕的标志,不再作任何处理,退出中断,因此共发生了3次中断。 
  改变程序的SendBuffer[2000]里面的数据和发送长度,分别测试发送64个字符和200个字符,结果与预想分析一致。 
  因此对参考文献[2]中的关于发送FIFO中断触发深度值的正确理解是:若设置的触发深度为N,当FIFO中剩下N个字符的时候,触发中断。而参考文献[1]的中文版使用手册认为是当移出去N个字符的时候,就触发中断,应当给予修正,以免误导开发者。 
结语 
  本文就串口FIFO模式的中断机制进行详细描述,其中修正了中文版使用手册上关于发送中断发生时刻的错误,同时对两者在中断处理上提出了一种实用的处理策略,对正确使用串口的FIFO模式有一定参考价值。 
  编者注:本文为期刊缩略版,全文见本刊网站www.mesnet.com.cn

参考文献
[1] S3C2440全套中文手册[EB/OL]. [20130107].http://wenku.baidu.com/view/009346fc770bf78a6529 54bb.html.
[2] S3C2440A_UserManual_Rev3[EB/OL].[20130107].http://wenku.baidu.com/view/2b88b9607e21af45b307a8dd.html.
[3] 周立功,张华. 深入浅出ARM7——LPC213x/214x(上册)[M].北京:北京航空航天大学出版社,2005:168 .

陈海生(讲师),主要研究方向为嵌入式智能控制系统;郭晓云(博士),主要研究方向为视频编码和处理;邓锐(讲师),主要研究方向为模式识别;王峰(讲师),主要研究方向为嵌入式系统及应用;陈亮(讲师),主要研究方向为嵌入式智能控制系统。

转载于:https://www.cnblogs.com/tureno/articles/11006697.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值