新闻  |   论坛  |   博客  |   在线研讨会
原代码:ZRTOS的任务篇(2)SPI
0750long | 2009-04-06 10:58:48    阅读:1586   发布文章

原代码:ZRTOS的任务篇(2)SPI

 

1、问题综述:
SPI具有连线少,速度较异步串口(UART)快,一个控制口可接多个SPI设备等优点,因此在嵌入式系统中得到广泛的应用。然而在“大循环”或某些RTOS中,对SPI编程往往会遇到代码效率低、速度慢、可读性和保性差等问题。使用ZRTOS的API int spi_Nbytes(SYN_SCI_SD_TYPE * )和用户定义的任务,可以很好地解决SPI的编程问题。其中SYN_SCI_SD_TYPE 在 sci.h 定义为:
typedef struct {
  U16 to_sd;//number of bytes need to be synchronously sent
  U8 * data;//data to be sent/exchanged;
} SYN_SCI_SD_TYPE;   
 以下原代码选自控制芯片与时钟芯片(DS1305)的SPI的介面C代码。在实施过程中系统的其它任务(比如每秒读一次时间、设定新的时间、闹铃等)把要做的事先写入ring buffer(rtc_data), 然后任务rtc_send()依次用spi_Nbytes(SYN_SCI_SD_TYPE * )完成这些使命。任务rtc_send有两个执行状态(two command steps),step 1是在开始call spi_Nbytes()时,由于SPI需要时间来完成,rtc_send 将进入等待状态,让出CPU给其他任务;step 2是SPI完成了数据传递/交换,任务rtc_send重新掌控CPU。
以下是部分原代码:
void rtc_Init(void)//initialization
{
  int n;
  SYN_SCI_SD_TYPE reg;
  U8 tmp[SYN_SCI_BUFFER_SIZE];
  reg.data = tmp;

  smid = rtos_semBCreate(0, SEM_FULL);//create a semaphone to wake up
                                      //task rtc_send
  rtc_step = 0; //initialized as command step 1
  rtc_data.head = rtc_data.tail = 0; //clear ring buffer
 
  rtos_taskSpawn(RTOS_PEND_FOREVER_PRI+1, (RTOS_FUNCPTR) rtc_send, 0);//spawn
  //a task rtc_send to handle SPI interface
 
  //other initialization here...
}

static void rtc_send(void)//task to handle SPI interface
{
  int status; //to hold the return value of spi_Nbytes()
  long results = rtos_semTake(smid, WAIT_FOREVER);//may pended here forever
   
  if (!rtc_step) { //
    //task rtc_send() in step 1
    if (rtc_data.head == rtc_data.tail) {
      return;//there is no data to send
    }        
   
    RTC_CE_ON(1); //CE enable   
    rtc_in_sending = 1;//going to step 2
    rtos_semGive(smid);//release the semaphone to itself so that the task
                       //will continue
    spi_Nbytes(&rtc_data.rtc_rcv[rtc_data.head]);//pend itself never back
  } else { //sending complete
    status = spi_Nbytes(&rtc_data.rtc_rcv[rtc_data.head]);//get the return value
    RTC_CE_ON(0); //CE disable
    rtc_step = 0;//back to step 1
    rtos_semGive(smid););//release the semaphone to itself so that the task
                         //will continue
   
    if (status == SPI_RESET) return;//SPI failed, may try again
   
    //return with data here
    rtc_parse();//process the clock data
    rtc_data.head++;//goto the next
   
    if (rtc_data.head == RTC_BUFFER_SIZE) { //ring over
      rtc_data.head = 0;
    }   
  }
}

2、结论
在上例中对SPI的编程是以所谓client/server的方式进行的,即其他任务向ring buffer(rtc_data) 输入要求,而由任务rtc_send从rtc_data中取得要求,完成SPI的功能,此时任务rtc_send有两个command steps(即上例中的 step 1 和 step 2)。用类似的方法,还可以对SPI进行其他方式的编程,比方说对上述SPI时钟(DS1305)也可以用线程(Threads)的方式进行,这样的话ring buffer(RAM)就可省去,但可能要更多的C代码。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客