/************************************************************************************************** * @fn npSpiRxIsr * * @brief This function handles the DMA Rx complete interrupt. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void HalSpiRxIsr(void) { uint8 type = halSpiBuf[1] & RPC_CMD_TYPE_MASK; uint8 *pBuf, rdy = 1; NP_SPI_ASSERT(halSpiState == NP_SPI_WAIT_RX); switch (type) { case RPC_CMD_AREQ: // call client with message type so it can schedule an OSAL event // ISN'T THIS PROBLEMATIC? IF THE BUFFER HASN'T BEEN COPIED, OR THE DMA // POINTER CHANGED, WHAT'S TO STOP THE MASTER FROM SENDING ANOTHER AREQ? // THE STATE MIGHT CAUSE AN ASSERT, BUT THIS DOESN'T SEEM LIKE THE RIGHT // SOLUTION. HAL_SPI_DBG_LOG(0x12); npSpiReqCallback( RPC_CMD_AREQ ); halSpiState = NP_SPI_WAIT_AREQ; break; case RPC_CMD_SREQ: // synchronous request received, so need to send back a synchronous reply // call client with message type so it can schedule an OSAL event HAL_SPI_DBG_LOG(0x13); npSpiReqCallback( RPC_CMD_SREQ ); halSpiState = NP_SPI_WAIT_TX; rdy = 0; // keep SRDY asserted until SRSP is ready to be sent, then deassert so master can read back SRSP break; case RPC_CMD_POLL: // callback to assign pBuf with AREQ to send from slave // Note: this AREQ was already queued by the slave when it wanted to send // an asynchronous command to the master by asserting SRDY. HAL_SPI_DBG_LOG(0x14); if ( (pBuf = npSpiPollCallback()) == NULL ) { // nothing was queued, which is odd, so just send an empty frame? halSpiBuf[0] = 0; halSpiBuf[1] = 0; halSpiBuf[2] = 0; pBuf = halSpiBuf; } halSpiState = NP_SPI_WAIT_TX; DMA_TX(pBuf); break; default: HAL_SPI_DBG_LOG(0x15); halSpiState = NP_SPI_IDLE; break; } NP_RDYOut = rdy; }
/************************************************************************************************** * @fn npSpiMonitor * * @brief This function monitors the SPI signals for error conditions and for the end of a * transaction. If an error is detected it attempts to recover. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void npSpiMonitor(void) { switch (halSpiState) { case NP_SPI_SYNCH: break; case NP_SPI_IDLE: NP_SPI_ASSERT((NP_RDYIn_IFG & NP_RDYIn_BIT) == 0); break; case NP_SPI_WAIT_RX: NP_SPI_ASSERT((HAL_DMA_CHECK_IRQ(HAL_DMA_CH_RX)) == 0); break; case NP_SPI_WAIT_TX: NP_SPI_ASSERT((HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX)) == 0); break; case NP_SPI_WAIT_AREQ: break; default: NP_SPI_ASSERT(0); break; } if (halSpiState == NP_SPI_IDLE) { /* Poll for MRDY in case it was set before slave had setup the ISR. * Also, async responses may get queued, so flush them out here. */ if ((NP_RDYIn == 0) || (npSpiReadyCallback())) { npSpiAReqReady(); } } }
/************************************************************************************************** * @fn npSpiSRspAlloc * * @brief This function is called by MT to allocate a buffer in which to build an SRSP frame. * MT must only call this function after processing a received SREQ frame. * * input parameters * * @param len - Length of the buffer required. * * output parameters * * None. * * @return NULL for failure; a pointer to the halSpiBuf on success. Success is determined by * the correct halSpiState and H/W signals as well as a valid length request. ************************************************************************************************** */ uint8 *npSpiSRspAlloc(uint8 len) { // Remove unused parameter warning when NP_SPI_ASSERT macro is not enabled (void) len; if (halSpiState == NP_SPI_WAIT_TX) { NP_SPI_ASSERT(len <= HAL_SPI_BUF_LEN); return halSpiBuf; } else { return NULL; } }
/************************************************************************************************** * @fn npSpiRxIsr * * @brief This function handles the DMA Rx complete interrupt. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void npSpiRxIsr(void) { uint8 *pBuf; mtRpcCmdType_t type = (mtRpcCmdType_t)(npSpiBuf[1] & MT_RPC_CMD_TYPE_MASK); NP_SPI_ASSERT(npSpiState == NP_SPI_WAIT_RX); switch (type) { case MT_RPC_CMD_POLL: npSpiState = NP_SPI_WAIT_TX; if ((pBuf = npSpiPollCallback()) != NULL) { /* Send TX packet using uDMA */ spi_tx(pBuf); osal_msg_deallocate((uint8 *)pBuf); } else { /* If there is no data in the queue, send 3 zeros. */ pBuf = npSpiBuf; npSpiBuf[0] = npSpiBuf[1] = npSpiBuf[2] = 0; /* Send TX packet using uDMA */ spi_tx(pBuf); } break; case MT_RPC_CMD_SREQ: npSpiState = NP_SPI_WAIT_SREQ; osal_set_event(znpTaskId, ZNP_SPI_RX_SREQ_EVENT); break; case MT_RPC_CMD_AREQ: npSpiState = NP_SPI_WAIT_AREQ; osal_set_event(znpTaskId, ZNP_SPI_RX_AREQ_EVENT); break; default: npSpiState = NP_SPI_IDLE; break; } }
/************************************************************************************************** * @fn npSpiTxIsr * * @brief This function handles the DMA Tx complete interrupt. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void HalSpiTxIsr(void) { halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); uint16 src; HAL_SPI_DBG_LOG(0x20); NP_SPI_ASSERT(halSpiState == NP_SPI_WAIT_TX); HAL_DMA_GET_SOURCE( ch, src ); if ((uint8 *)src != halSpiBuf) { osal_msg_deallocate((uint8 *)src); } halSpiState = NP_SPI_IDLE; // Callback is required so that client can schedule to call npSpiMonitor // function. npSpiTxCompleteCallback(); }