//----设定中断同步------------------------------------------------------------- //功能: 阻塞正在处理的事件的线程,直到指定的中断线的中断发生、响应并返回,然后才 // 激活线程。调用前确保该中断线被禁止,调用本函数将导致中断线被使能(是直接 // 使能,不是调用int_save_asyn_line),并在返回后恢复禁止状态。 //参数: ufl_line,等待的目标中断线 //返回: false = 该中断已经被其他线程等待,直接返回。 // true = 成功同步,并在该中断发生后返回。 //备注: 1.中断是一种临界资源,不宜在中断函数中太多的事情,故中断同步的功能比较简 // 单,每条中断线同一时刻只能有一个线程等待,也不允许设置超时等待 // 2.秉承djyos一贯风格,中断同步函数只能把自己置入等待状态,而不能控制别的 // 线程,故函数原型不能是 bool_t int_sync(ufast_t line,uint16_t event_id) // 3.实时中断设置等待无效,调用本函数时,如果line已经被设置为实时中断,则 // 直接返回false,如果调用本函数后,line不能被设置为实时中断。 // 4.为正确实现功能,须在调用前确保该中断线是被禁止的。 //----------------------------------------------------------------------------- bool_t Int_AsynSignalSync(ufast_t ufl_line) { if( (ufl_line > CN_INT_LINE_LAST) || (tg_pIntLineTable[ufl_line] == NULL) ) return false; if( !Djy_QuerySch()) { //禁止调度,不能进入异步信号同步状态。 Djy_SaveLastError(EN_KNL_CANT_SCHED); return false; } Int_SaveAsynSignal(); //在操作就绪队列期间不能发生中断 //实时中断不能设置同步,一个中断只接受一个同步事件 if((tg_pIntLineTable[ufl_line]->int_type == CN_REAL) || (tg_pIntLineTable[ufl_line]->sync_event != NULL)) { Int_RestoreAsynSignal(); return false; //实时中断或已经有同步事件 }else { if(Int_QueryLine(ufl_line) == true) //中断已经发生,同步条件达到 { Int_ClearLine(ufl_line); Int_RestoreAsynSignal(); return true; } //以下三行从就绪链表中取出running事件 __Djy_CutReadyEvent(g_ptEventRunning); g_ptEventRunning->next = NULL; g_ptEventRunning->previous = NULL; g_ptEventRunning->event_status = CN_STS_WAIT_ASYN_SIGNAL; tg_pIntLineTable[ufl_line]->sync_event = g_ptEventRunning; } Int_EnableAsynLine(ufl_line); Int_RestoreAsynSignal(); //调用本函数将引发线程切换,正在处理的事件被 //挂起。 Int_DisableAsynLine(ufl_line); g_ptEventRunning->wakeup_from = CN_STS_WAIT_ASYN_SIGNAL; g_ptEventRunning->event_status = CN_STS_EVENT_READY; return true; }
// ============================================================================= // 功能:数据传送函数,完成数据的发送和接收。该函数完成的功能如下: // 1.若器件驱动为了避免组包的麻烦,可先发命令再发送数据,分多次调用,多次调用前 // 后被CSActive和CsInactive函数包裹; // 2.根据Dev查找所属SPI总线; // 3.若缓冲区大于发送字节数,则直接将数据填入缓冲区; // 4.若为阻塞发送,则等待总线信号量,若为非阻塞,则等待buf信号量; // 5.发生超时或错误时,拉高CS并释放信号量 // 参数:Dev,器件指针 // spidata,SPI数据结构体 // block_option,阻塞选项,为true时,表明最后一次传输为阻塞方式,否则为非阻塞 // timeout,超时参数,us // 返回:返回发送状态,超时或错误或无错误 // ============================================================================= s32 SPI_Transfer(struct tagSPI_Device *Dev,struct tagSPI_DataFrame *spidata, u8 block_option,u32 timeout) { struct tagSPI_CB *SPI; // struct semaphore_LCB *spi_semp; s32 result ; u32 written=0; u32 base_time = 0,rel_timeout = timeout; if(NULL == Dev) return CN_SPI_EXIT_PARAM_ERR; SPI = (struct tagSPI_CB *)Rsc_GetParent(&Dev->DevNode);//查找该器件属于哪条总线 if(NULL == SPI) return CN_SPI_EXIT_PARAM_ERR; base_time = (u32)DjyGetTime(); //若配置需自动片选,则本函数内部需拉低片选 if(Dev->AutoCs == true) { if(false == Lock_SempPend(SPI->SPI_BusSemp,timeout)) //需要等待总线空闲 { result = CN_SPI_EXIT_TIMEOUT; goto exit_from_bus_timeout; } __SPI_AutoCsActive(SPI,Dev); } Lock_SempPend(SPI->SPI_BlockSemp,0); //相当于重置信号量 //禁止调试或未登记pTransferTxRx,使用轮询方式通信 if((Djy_QuerySch() == false) || (SPI->pTransferTxRx == NULL) || (SPI->Flag & CN_SPI_FLAG_POLL)) { if(SPI->pTransferPoll != NULL) { SPI->pTransferPoll(SPI->SpecificFlag,spidata->SendBuf,spidata->SendLen, spidata->RecvBuf,spidata->RecvLen,spidata->RecvOff); if(Dev->AutoCs == true) __SPI_AutoCsInactive(SPI,Dev->Cs); result = CN_SPI_EXIT_NOERR; } goto exit_from_no_err; } if(spidata->RecvLen) block_option = true; //接收数据自动转为阻塞 SPI->SPI_Buf.Offset = 0; //发送前先清空缓冲区 SPI->Frame = *spidata; SPI->BlockOption = block_option; //如果非阻塞方式,且缓冲区够大,则直接写入缓冲区 //若不是,则先发送调用者提供的缓冲区,直到剩余字节数能够填充到缓冲区 if((!block_option) && (spidata->SendLen <= SPI->SPI_Buf.MaxLen)) { memcpy(SPI->SPI_Buf.pBuf,spidata->SendBuf,spidata->SendLen); written = spidata->SendLen; } //调用启动时序的回调函数 if(true == SPI->pTransferTxRx(SPI->SpecificFlag, spidata->SendLen, spidata->RecvLen, spidata->RecvOff )) { rel_timeout = (u32)DjyGetTime(); if(rel_timeout - base_time < timeout) rel_timeout = timeout - (rel_timeout - base_time); else { result = CN_SPI_EXIT_TIMEOUT; goto exit_from_timeout; } //需要等待的情况:1.阻塞发送;2.数据未全部填到缓冲区 if((true == block_option) || (written < spidata->SendLen)) { //等待中断函数释放信号量 if(!Lock_SempPend(SPI->SPI_BlockSemp,rel_timeout)) { result = CN_SPI_EXIT_TIMEOUT; goto exit_from_timeout; } } result = CN_SPI_EXIT_NOERR; goto exit_from_no_err; }else { result = CN_SPI_EXIT_UNKNOW_ERR; goto exit_from_timeout; } exit_from_timeout: if(Dev->AutoCs == true) //自动片选时,返回前需拉低片选 { __SPI_AutoCsInactive(SPI,Dev->Cs); } exit_from_bus_timeout: exit_from_no_err: return result; }