"); //-->
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代码。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。