/* * Copyright 2020-2022 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_imu.h" /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.imu" #endif /******************************************************************************* * Variables ******************************************************************************/ /****************************************************************************** * Code *****************************************************************************/ /* * Initializes the IMU module. * * This function sets IMU to initialized state, including: * * - Flush the send FIFO. * - Unlock the send FIFO. * - Set the water mark to (IMU_MAX_MSG_FIFO_WATER_MARK) * */ status_t IMU_Init(imu_link_t link) { status_t status; if (link >= kIMU_LinkMax) { status = kStatus_InvalidArgument; } else { IMU_FlushSendFifo(link); IMU_LockSendFifo(link, false); IMU_SetSendFifoWaterMark(link, IMU_MAX_MSG_FIFO_WATER_MARK); /* Flush RX FIFO. */ while (!IMU_RX_FIFO_EMPTY(link)) { (void)IMU_RD_MSG(link); } status = kStatus_Success; } return status; } /* * De-initializes the IMU module. * */ void IMU_Deinit(imu_link_t link) { } /* * Blocking to send messages. * * This function blocks until all messages have been filled to TX FIFO. * * - If the TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED. * - If TX FIFO not locked, this function waits the available empty slot in TX FIFO, * and fills the message to TX FIFO. * - To lock TX FIFO after filling all messages, set lockSendFifo to true. * * param link IMU link. * param msgs The messages to send. * param msgCount Message count, one message is a 32-bit word. * param lockSendFifo If set to true, the TX FIFO is locked after all messages filled to TX FIFO. * return If TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED, * otherwise, this function returns the actual message count sent out, it equals msgCount * because this function is blocking function, it returns until all messages have been * filled into TX FIFO. */ int32_t IMU_SendMsgsBlocking(imu_link_t link, const uint32_t *msgs, int32_t msgCount, bool lockSendFifo) { int32_t ret; int32_t curSent; int32_t fifoEmptySpace; if (msgCount <= 0) { ret = 0; } else if (IMU_TX_FIFO_LOCKED(link)) { ret = IMU_ERR_TX_FIFO_LOCKED; } else { ret = msgCount; /* Send the first (msgCount - 1), the last message should * be sent with the lock configuration. */ msgCount--; while (msgCount > 0) { fifoEmptySpace = (int32_t)IMU_GetSendFifoEmptySpace(link); curSent = MIN(msgCount, fifoEmptySpace); msgCount -= curSent; while (0 != (curSent--)) { IMU_WR_MSG(link, *msgs); msgs++; } } /* To lock TX FIFO, set the lock bit before last message write. */ if (lockSendFifo) { IMU_LOCK_TX_FIFO(link); } /* Send the last. */ while (0UL == IMU_GetSendFifoEmptySpace(link)) { } IMU_WR_MSG(link, *msgs); } return ret; } /* * Try to send messages. * * This function is similar with @ref IMU_SendMsgsBlocking, the difference is, * this function tries to send as many as possible, if there is not enough * empty slot in TX FIFO, this function fills messages to available empty slots * and returns how many messages have been filled. * * - If the TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED. * - If TX FIFO not locked, this function fills messages to TX FIFO empty slot, * and returns how many messages have been filled. * - If lockSendFifo is set to true, TX FIFO is locked after all messages have * been filled to TX FIFO. In other word, TX FIFO is locked if the function * return value equals msgCount, when lockSendFifo set to true. * * param link IMU link. * param msgs The messages to send. * param msgCount Message count, one message is a 32-bit word. * param lockSendFifo If set to true, the TX FIFO is locked after all messages filled to TX FIFO. * return If TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED, * otherwise, this function returns the actual message count sent out. */ int32_t IMU_TrySendMsgs(imu_link_t link, const uint32_t *msgs, int32_t msgCount, bool lockSendFifo) { int32_t ret; int32_t curSent; int32_t fifoEmptySpace; if (msgCount <= 0) { ret = 0; } else if (IMU_TX_FIFO_LOCKED(link)) { ret = IMU_ERR_TX_FIFO_LOCKED; } else { ret = 0; /* Send the first (msgCount - 1), the last message should * be sent with the lock configuration. */ msgCount--; while (true) { fifoEmptySpace = (int32_t)IMU_GetSendFifoEmptySpace(link); if (fifoEmptySpace == 0) { break; } /* If this is the last and have FIFO space to send. */ else if (0 == msgCount) { if (lockSendFifo) { IMU_LOCK_TX_FIFO(link); } /* Send the last. */ IMU_WR_MSG(link, *msgs); ret++; break; } else { curSent = MIN(msgCount, fifoEmptySpace); /* Send the data. */ msgCount -= curSent; ret += curSent; while (0 != (curSent--)) { IMU_WR_MSG(link, *msgs); msgs++; } } } } return ret; } /* * Try to receive messages. * * This function tries to read messages from RX FIFO. It reads the messages already * exists in RX FIFO and returns the actual read count. * * - If the RX FIFO has enough messages, this function reads the messages and returns. * - If the RX FIFO does not have enough messages, this function the messages in RX FIFO * and returns the actual read count. * - During message reading, if RX FIFO is empty and locked, in this case peer CPU will not * send message until current CPU send lock ack message. Then this function * returns the message count actually received, and sets needAckLock to true * to inform upper layer. * * param link IMU link. * param msgs The buffer to read messages. * param desiredMsgCount Desired read count, one message is a 32-bit word. * param needAckLock Upper layer should always check this value. When this is * set to true by this function, upper layer should send lock ack message to peer CPU. * return Count of messages actually received. */ int32_t IMU_TryReceiveMsgs(imu_link_t link, uint32_t *msgs, int32_t desiredMsgCount, bool *needAckLock) { int32_t receivedCount = 0; int32_t rxFifoMsgCount; int32_t countToRead; uint32_t rxFifoStatus; bool localNeedAckLock = false; while (true) { rxFifoStatus = IMU_RX_FIFO_STATUS(link); rxFifoMsgCount = (int32_t)(uint32_t)IMU_RX_FIFO_MSG_COUNT_FROM_STATUS(rxFifoStatus); if (0 == rxFifoMsgCount) { if (IMU_RX_FIFO_LOCKED_FROM_STATUS(rxFifoStatus)) { localNeedAckLock = true; } break; } /* * Dont need to check RX FIFO lock status, only notify upper layer * when last message read out. */ if (0 == desiredMsgCount) { break; } countToRead = MIN(desiredMsgCount, rxFifoMsgCount); receivedCount += countToRead; desiredMsgCount -= countToRead; while (0 != (countToRead--)) { *msgs++ = IMU_RD_MSG(link); } } if (needAckLock != NULL) { *needAckLock = localNeedAckLock; } return receivedCount; } /* * Blocking to receive messages. * * This function blocks until all desired messages have been received or the RX FIFO * is locked. * * - If the RX FIFO has enough messages, this function reads the messages and returns. * - If the RX FIFO does not have enough messages, this function waits for the new * messages. * - During message reading, if RX FIFO is empty and locked, in this case peer CPU will not * send message until current CPU send lock ack message. Then this function * returns the message count actually received, and sets needAckLock to true * to inform upper layer. * * param link IMU link. * param msgs The buffer to read messages. * param desiredMsgCount Desired read count, one message is a 32-bit word. * param needAckLock Upper layer should always check this value. When this is * set to true by this function, upper layer should send lock ack message to peer CPU. * return Count of messages actually received. */ int32_t IMU_ReceiveMsgsBlocking(imu_link_t link, uint32_t *msgs, int32_t desiredMsgCount, bool *needAckLock) { int32_t receivedCount = 0; int32_t rxFifoMsgCount; int32_t countToRead; uint32_t rxFifoStatus; bool localNeedAckLock; while (true) { rxFifoStatus = IMU_RX_FIFO_STATUS(link); rxFifoMsgCount = (int32_t)(uint32_t)IMU_RX_FIFO_MSG_COUNT_FROM_STATUS(rxFifoStatus); if ((0 == rxFifoMsgCount) && (IMU_RX_FIFO_LOCKED_FROM_STATUS(rxFifoStatus))) { localNeedAckLock = true; break; } if (0 == desiredMsgCount) { localNeedAckLock = false; break; } countToRead = MIN(desiredMsgCount, rxFifoMsgCount); receivedCount += countToRead; desiredMsgCount -= countToRead; while (0 != (countToRead--)) { *msgs++ = IMU_RD_MSG(link); } } if (NULL != needAckLock) { *needAckLock = localNeedAckLock; } return receivedCount; } /* * brief Blocking to send messages pointer. * * Compared with @ref IMU_SendMsgsBlocking, this function fills message pointer * to TX FIFO, but not the message content. * * This function blocks until the message pointer is filled to TX FIFO. * * - If the TX FIFO is locked, this function returns IMU_ERR_TX_FIFO_LOCKED. * - If TX FIFO not locked, this function waits the available empty slot in TX FIFO, * and fills the message pointer to TX FIFO. * - To lock TX FIFO after filling the message pointer, set lockSendFifo to true. * * param link IMU link. * param msgPtr The buffer pointer to message to send. * param needAckLock Upper layer should always check this value. When this is * set to true by this function, upper layer should send lock ack message to peer CPU. * retval 0 The message pointer set successfully. * retval IMU_ERR_TX_FIFO_LOCKED The TX FIFO is locked, send failed. */ int32_t IMU_SendMsgPtrBlocking(imu_link_t link, uint32_t msgPtr, bool lockSendFifo) { int32_t ret = 0; if (IMU_TX_FIFO_LOCKED(link)) { ret = IMU_ERR_TX_FIFO_LOCKED; } else { while (IMU_TX_FIFO_ALMOST_FULL(link)) { } if (lockSendFifo) { IMU_LOCK_TX_FIFO(link); } IMU_WR_MSG(link, msgPtr); } return ret; } /* * brief Flush the send FIFO. * * Flush all messages in send FIFO. * * param link IMU link. */ void IMU_FlushSendFifo(imu_link_t link) { IMU_TX_FIFO_CNTL(link) |= IMU_MSG_FIFO_CNTL_FIFO_FLUSH_MASK; IMU_TX_FIFO_CNTL(link) &= ~IMU_MSG_FIFO_CNTL_FIFO_FLUSH_MASK; } /* * Gets the IMU status flags. * * param link IMU link. * return Bit mask of the IMU status flags, see _imu_status_flags. */ uint32_t IMU_GetStatusFlags(imu_link_t link) { uint32_t txFifoStatus = IMU_TX_FIFO_STATUS(link); uint32_t rxFifoStatus = IMU_RX_FIFO_STATUS(link); return txFifoStatus | (rxFifoStatus << 8U); }