summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-01-12 15:34:31 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-01-19 08:36:20 +0100
commite1eeb883d82ce218c2a9c754795cb3c86ac0f36d (patch)
tree646a7c22772297094bb77303953eda0e71679dd9 /c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c
parentbsps/arm: Copy vector table only if necessary (diff)
downloadrtems-e1eeb883d82ce218c2a9c754795cb3c86ac0f36d.tar.bz2
bsp/atsam: Import SAM Software Package
Import selected files of the "SAM V71 / V70 / E70 / S70 Software Package" obtained from the "SAMV71-XULT GNU Software Package 1.5". Converted files via dos2unix before import. Update #2529.
Diffstat (limited to 'c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c')
-rw-r--r--c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c761
1 files changed, 761 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c b/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c
new file mode 100644
index 0000000000..91196dfcef
--- /dev/null
+++ b/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/twid.c
@@ -0,0 +1,761 @@
+/* ---------------------------------------------------------------------------- */
+/* Atmel Microcontroller Software Support */
+/* SAM Software Package License */
+/* ---------------------------------------------------------------------------- */
+/* Copyright (c) 2015, Atmel Corporation */
+/* */
+/* All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following condition is met: */
+/* */
+/* - Redistributions of source code must retain the above copyright notice, */
+/* this list of conditions and the disclaimer below. */
+/* */
+/* Atmel's name may not be used to endorse or promote products derived from */
+/* this software without specific prior written permission. */
+/* */
+/* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */
+/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */
+/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */
+/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
+/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */
+/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
+/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
+/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+/* ---------------------------------------------------------------------------- */
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+#include "chip.h"
+
+#include <assert.h>
+
+/*----------------------------------------------------------------------------
+ * Definition
+ *----------------------------------------------------------------------------*/
+#define TWITIMEOUTMAX 400
+static uint32_t dmaWriteChannel, dmaReadChannel;
+
+extern uint32_t twi_send_stop;
+
+/*----------------------------------------------------------------------------
+ * Types
+ *----------------------------------------------------------------------------*/
+
+/** TWI driver callback function.*/
+typedef void (*TwiCallback)(Async *);
+
+/** \brief TWI asynchronous transfer descriptor.*/
+typedef struct _AsyncTwi {
+
+ /** Asynchronous transfer status. */
+ volatile uint8_t status;
+ /** Callback function to invoke when transfer completes or fails.*/
+ TwiCallback callback;
+ /** Pointer to the data buffer.*/
+ uint8_t *pData;
+ /** Total number of bytes to transfer.*/
+ uint32_t num;
+ /** Number of already transferred bytes.*/
+ uint32_t transferred;
+
+} AsyncTwi;
+
+/**
+ * \brief Initializes a TWI DMA Read channel.
+ */
+static void TWID_DmaInitializeRead(TwihsDma *pTwiXdma)
+{
+ /* Allocate a XDMA channel, Read accesses into TWI_THR */
+ dmaReadChannel = XDMAD_AllocateChannel(pTwiXdma->pTwiDma, pTwiXdma->Twi_id,
+ XDMAD_TRANSFER_MEMORY);
+
+ if (dmaReadChannel == XDMAD_ALLOC_FAILED)
+ printf("-E- Can't allocate XDMA channel\n\r");
+
+ XDMAD_PrepareChannel(pTwiXdma->pTwiDma, dmaReadChannel);
+}
+
+/**
+ * \brief Initializes a TWI DMA write channel.
+ */
+static void TWID_DmaInitializeWrite(TwihsDma *pTwiXdma)
+{
+ /* Allocate a XDMA channel, Write accesses into TWI_THR */
+ dmaWriteChannel = XDMAD_AllocateChannel(pTwiXdma->pTwiDma,
+ XDMAD_TRANSFER_MEMORY,
+ pTwiXdma->Twi_id);
+
+ if (dmaWriteChannel == XDMAD_ALLOC_FAILED)
+ printf("-E- Can't allocate XDMA channel\n\r");
+
+ XDMAD_PrepareChannel(pTwiXdma->pTwiDma, dmaWriteChannel);
+}
+
+/**
+ * \brief Configure xDMA write linker list for TWI transfer.
+ */
+static uint8_t TWID_XdmaConfigureWrite(TwihsDma *pTwiXdma, uint8_t *buf,
+ uint32_t len)
+{
+ uint32_t xdmaCndc, Thr, xdmaInt;
+ sXdmadCfg xdmadTxCfg;
+
+ Thr = (uint32_t) & (TWIHS0->TWIHS_THR);
+
+ if (pTwiXdma->Twi_id == ID_TWIHS1)
+ Thr = (uint32_t) & (TWIHS1->TWIHS_THR);
+
+ if (pTwiXdma->Twi_id == ID_TWIHS2)
+ Thr = (uint32_t) & (TWIHS2->TWIHS_THR);
+
+ xdmadTxCfg.mbr_ubc = XDMA_UBC_NVIEW_NDV0 |
+ XDMA_UBC_NDE_FETCH_DIS |
+ XDMA_UBC_NSEN_UPDATED | len;
+
+ xdmadTxCfg.mbr_sa = (uint32_t)buf;
+ xdmadTxCfg.mbr_da = Thr;
+ xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
+ XDMAC_CC_MBSIZE_SINGLE |
+ XDMAC_CC_DSYNC_MEM2PER |
+ XDMAC_CC_CSIZE_CHK_1 |
+ XDMAC_CC_DWIDTH_BYTE |
+ XDMAC_CC_SIF_AHB_IF1 |
+ XDMAC_CC_DIF_AHB_IF1 |
+ XDMAC_CC_SAM_INCREMENTED_AM |
+ XDMAC_CC_DAM_FIXED_AM |
+ XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(
+ pTwiXdma->Twi_id, XDMAD_TRANSFER_TX));
+
+ xdmadTxCfg.mbr_bc = 0;
+ xdmadTxCfg.mbr_sus = 0;
+ xdmadTxCfg.mbr_dus = 0;
+ xdmaCndc = 0;
+
+ xdmaInt = (XDMAC_CIE_BIE |
+ XDMAC_CIE_RBIE |
+ XDMAC_CIE_WBIE);
+
+ if (XDMAD_ConfigureTransfer(pTwiXdma->pTwiDma, dmaWriteChannel,
+ &xdmadTxCfg, xdmaCndc, 0, xdmaInt))
+ return USARTD_ERROR;
+
+ return 0;
+}
+
+
+/**
+ * \brief Configure xDMA read linker list for TWI transfer.
+ */
+static uint8_t TWID_XdmaConfigureRead(TwihsDma *pTwiXdma, uint8_t *buf,
+ uint32_t len)
+{
+ uint32_t xdmaCndc, Rhr, xdmaInt;
+ sXdmadCfg xdmadRxCfg;
+
+ Rhr = (uint32_t) & (TWIHS0->TWIHS_RHR);
+
+ if (pTwiXdma->Twi_id == ID_TWIHS1)
+ Rhr = (uint32_t) & (TWIHS1->TWIHS_RHR);
+
+ if (pTwiXdma->Twi_id == ID_TWIHS2)
+ Rhr = (uint32_t) & (TWIHS2->TWIHS_RHR);
+
+ xdmadRxCfg.mbr_ubc = XDMA_UBC_NVIEW_NDV0 |
+ XDMA_UBC_NDE_FETCH_DIS |
+ XDMA_UBC_NDEN_UPDATED |
+ len;
+
+ xdmadRxCfg.mbr_da = (uint32_t)buf;
+ xdmadRxCfg.mbr_sa = Rhr;
+
+ xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
+ XDMAC_CC_MBSIZE_SINGLE |
+ XDMAC_CC_DSYNC_PER2MEM |
+ XDMAC_CC_CSIZE_CHK_1 |
+ XDMAC_CC_DWIDTH_BYTE |
+ XDMAC_CC_SIF_AHB_IF1 |
+ XDMAC_CC_DIF_AHB_IF1 |
+ XDMAC_CC_SAM_FIXED_AM |
+ XDMAC_CC_DAM_INCREMENTED_AM |
+ XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(
+ pTwiXdma->Twi_id , XDMAD_TRANSFER_RX));
+
+ xdmadRxCfg.mbr_bc = 0;
+ xdmadRxCfg.mbr_sus = 0;
+ xdmadRxCfg.mbr_dus = 0;
+ xdmaCndc = 0;
+ xdmaInt = (XDMAC_CIE_BIE |
+ XDMAC_CIE_RBIE |
+ XDMAC_CIE_WBIE);
+
+ if (XDMAD_ConfigureTransfer(pTwiXdma->pTwiDma, dmaReadChannel,
+ &xdmadRxCfg, xdmaCndc, 0, xdmaInt))
+ return 1;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * Global functions
+ *----------------------------------------------------------------------------*/
+
+/**
+ * \brief Returns 1 if the given transfer has ended; otherwise returns 0.
+ * \param pAsync Pointer to an Async instance.
+ */
+uint32_t ASYNC_IsFinished(Async *pAsync)
+{
+ return (pAsync->status != ASYNC_STATUS_PENDING);
+}
+
+/**
+ * \brief Initializes a TWI driver instance, using the given TWI peripheral.
+ * \note The peripheral must have been initialized properly before calling this
+ * function.
+ * \param pTwid Pointer to the Twid instance to initialize.
+ * \param pTwi Pointer to the TWI peripheral to use.
+ */
+void TWID_Initialize(Twid *pTwid, Twihs *pTwi)
+{
+ TRACE_DEBUG("TWID_Initialize()\n\r");
+ assert(pTwid != NULL);
+ assert(pTwi != NULL);
+
+ /* Initialize driver. */
+ pTwid->pTwi = pTwi;
+ pTwid->pTransfer = 0;
+}
+
+/**
+ * \brief Interrupt handler for a TWI peripheral. Manages asynchronous transfer
+ * occurring on the bus. This function MUST be called by the interrupt service
+ * routine of the TWI peripheral if asynchronous read/write are needed.
+ * \param pTwid Pointer to a Twid instance.
+ */
+void TWID_Handler(Twid *pTwid)
+{
+ uint8_t status;
+ AsyncTwi *pTransfer;
+ Twihs *pTwi;
+
+ assert(pTwid != NULL);
+
+ pTransfer = (AsyncTwi *)pTwid->pTransfer;
+ assert(pTransfer != NULL);
+ pTwi = pTwid->pTwi;
+ assert(pTwi != NULL);
+
+ /* Retrieve interrupt status */
+ status = TWI_GetMaskedStatus(pTwi);
+
+ /* Byte received */
+ if (TWI_STATUS_RXRDY(status)) {
+
+ pTransfer->pData[pTransfer->transferred] = TWI_ReadByte(pTwi);
+ pTransfer->transferred++;
+
+ /* check for transfer finish */
+ if (pTransfer->transferred == pTransfer->num) {
+
+ TWI_DisableIt(pTwi, TWIHS_IDR_RXRDY);
+ TWI_EnableIt(pTwi, TWIHS_IER_TXCOMP);
+ }
+ /* Last byte? */
+ else if (pTransfer->transferred == (pTransfer->num - 1))
+
+ TWI_Stop(pTwi);
+ }
+ /* Byte sent*/
+ else if (TWI_STATUS_TXRDY(status)) {
+
+ /* Transfer finished ? */
+ if (pTransfer->transferred == pTransfer->num) {
+
+ TWI_DisableIt(pTwi, TWIHS_IDR_TXRDY);
+ TWI_EnableIt(pTwi, TWIHS_IER_TXCOMP);
+ TWI_SendSTOPCondition(pTwi);
+ }
+ /* Bytes remaining */
+ else {
+
+ TWI_WriteByte(pTwi, pTransfer->pData[pTransfer->transferred]);
+ pTransfer->transferred++;
+ }
+ }
+ /* Transfer complete*/
+ else if (TWI_STATUS_TXCOMP(status)) {
+
+ TWI_DisableIt(pTwi, TWIHS_IDR_TXCOMP);
+ pTransfer->status = 0;
+
+ if (pTransfer->callback)
+ pTransfer->callback((Async *) pTransfer);
+
+ pTwid->pTransfer = 0;
+ }
+}
+
+/**
+ * \brief Asynchronously reads data from a slave on the TWI bus. An optional
+ * callback function is triggered when the transfer is complete.
+ * \param pTwid Pointer to a Twid instance.
+ * \param address TWI slave address.
+ * \param iaddress Optional slave internal address.
+ * \param isize Internal address size in bytes.
+ * \param pData Data buffer for storing received bytes.
+ * \param num Number of bytes to read.
+ * \param pAsync Asynchronous transfer descriptor.
+ * \return 0 if the transfer has been started; otherwise returns a TWI error code.
+ */
+uint8_t TWID_Read(
+ Twid *pTwid,
+ uint8_t address,
+ uint32_t iaddress,
+ uint8_t isize,
+ uint8_t *pData,
+ uint32_t num,
+ Async *pAsync)
+{
+ Twihs *pTwi;
+ AsyncTwi *pTransfer;
+ uint32_t startTime;
+ assert(pTwid != NULL);
+ pTwi = pTwid->pTwi;
+ pTransfer = (AsyncTwi *) pTwid->pTransfer;
+
+ assert((address & 0x80) == 0);
+ assert((iaddress & 0xFF000000) == 0);
+ assert(isize < 4);
+
+ /* Check that no transfer is already pending*/
+ if (pTransfer) {
+
+ TRACE_ERROR("TWID_Read: A transfer is already pending\n\r");
+ return TWID_ERROR_BUSY;
+ }
+
+ /* In single data byte master read, the START and STOP must both be set */
+ twi_send_stop = (num == 1) ? 1 : 0;
+
+ /* Asynchronous transfer*/
+ if (pAsync) {
+
+ /* Update the transfer descriptor */
+ pTwid->pTransfer = pAsync;
+ pTransfer = (AsyncTwi *) pAsync;
+ pTransfer->status = ASYNC_STATUS_PENDING;
+ pTransfer->pData = pData;
+ pTransfer->num = num;
+ pTransfer->transferred = 0;
+
+ /* Enable read interrupt and start the transfer */
+ TWI_EnableIt(pTwi, TWIHS_IER_RXRDY);
+ TWI_StartRead(pTwi, address, iaddress, isize);
+ }
+ /* Synchronous transfer*/
+ else {
+
+ /* Start read*/
+ TWI_StartRead(pTwi, address, iaddress, isize);
+
+ /* Read all bytes, setting STOP before the last byte*/
+ while (num > 0) {
+
+ /* Last byte ?*/
+ if (num == 1)
+ TWI_Stop(pTwi);
+
+ /* Wait for byte then read and store it*/
+ startTime = GetTicks();
+
+ while (!TWI_ByteReceived(pTwi)) {
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout BR\n\r");
+ break;
+ }
+ }
+
+ *pData++ = TWI_ReadByte(pTwi);
+ num--;
+ }
+
+ /* Wait for transfer to be complete */
+ startTime = GetTicks();
+
+ while (!TWI_TransferComplete(pTwi)) {
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout TC\n\r");
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Asynchronously sends data to a slave on the TWI bus. An optional
+ * callback function is invoked whenever the transfer is complete.
+ * \param pTwid Pointer to a Twid instance.
+ * \param address TWI slave address.
+ * \param iaddress Optional slave internal address.
+ * \param isize Number of internal address bytes.
+ * \param pData Data buffer for storing received bytes.
+ * \param num Data buffer to send.
+ * \param pAsync Asynchronous transfer descriptor.
+ * \return 0 if the transfer has been started; otherwise returns a TWI error code.
+ */
+uint8_t TWID_Write(
+ Twid *pTwid,
+ uint8_t address,
+ uint32_t iaddress,
+ uint8_t isize,
+ uint8_t *pData,
+ uint32_t num,
+ Async *pAsync)
+{
+ Twihs *pTwi = pTwid->pTwi;
+ uint32_t startTime;
+ AsyncTwi *pTransfer = (AsyncTwi *) pTwid->pTransfer;
+
+ assert(pTwi != NULL);
+ assert((address & 0x80) == 0);
+ assert((iaddress & 0xFF000000) == 0);
+ assert(isize < 4);
+
+ /* Check that no transfer is already pending */
+ if (pTransfer) {
+ TRACE_ERROR("TWI_Write: A transfer is already pending\n\r");
+ return TWID_ERROR_BUSY;
+ }
+
+ /* Asynchronous transfer */
+ if (pAsync) {
+ /* Update the transfer descriptor */
+ pTwid->pTransfer = pAsync;
+ pTransfer = (AsyncTwi *) pAsync;
+ pTransfer->status = ASYNC_STATUS_PENDING;
+ pTransfer->pData = pData;
+ pTransfer->num = num;
+ pTransfer->transferred = 1;
+
+ /* Enable write interrupt and start the transfer */
+ TWI_StartWrite(pTwi, address, iaddress, isize, *pData);
+ TWI_EnableIt(pTwi, TWIHS_IER_TXRDY);
+
+ } else {
+ /* Synchronous transfer*/
+ // Start write
+ TWI_StartWrite(pTwi, address, iaddress, isize, *pData++);
+ num--;
+
+ /* Send all bytes */
+ while (num > 0) {
+ /* Wait before sending the next byte */
+ startTime = GetTicks();
+
+ while (!TWI_ByteSent(pTwi)) {
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout BS\n\r");
+ break;
+ }
+ }
+
+ TWI_WriteByte(pTwi, *pData++);
+ num--;
+ }
+
+ /* Wait for actual end of transfer */
+ startTime = GetTicks();
+ /* Send a STOP condition */
+ TWI_SendSTOPCondition(pTwi);
+
+ while (!TWI_TransferComplete(pTwi)) {
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout TC2\n\r");
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Initializes a TWI driver instance, using the given TWI peripheral.
+ * \note The peripheral must have been initialized properly before calling this
+ * function.
+ * \param pTwid Pointer to the Twid instance to initialize.
+ * \param pTwi Pointer to the TWI peripheral to use.
+ */
+void TWID_DmaInitialize(TwihsDma *pTwidma, Twihs *pTwi, uint8_t bPolling)
+{
+ TRACE_DEBUG("TWID_Initialize()\n\r");
+ assert(pTwidma != NULL);
+
+ if ((unsigned int)pTwi == (unsigned int)TWIHS0) pTwidma->Twi_id = ID_TWIHS0;
+
+ if ((unsigned int)pTwi == (unsigned int)TWIHS1) pTwidma->Twi_id = ID_TWIHS1;
+
+ if ((unsigned int)pTwi == (unsigned int)TWIHS2) pTwidma->Twi_id = ID_TWIHS2;
+
+ /* Initialize driver. */
+ pTwidma->pTwid->pTwi = pTwi;
+ pTwidma->pTwid->pTransfer = 0;
+
+ if (!bPolling) {
+ /* Enable XDMA interrupt and give it priority over any other peripheral
+ interrupt */
+ NVIC_ClearPendingIRQ(XDMAC_IRQn);
+ NVIC_SetPriority(XDMAC_IRQn, 1);
+ NVIC_EnableIRQ(XDMAC_IRQn);
+ }
+
+ /* Initialize XDMA driver instance with polling mode */
+ XDMAD_Initialize(pTwidma->pTwiDma, bPolling);
+}
+
+/**
+ * \brief Asynchronously reads data from a slave on the TWI bus. An optional
+ * callback function is triggered when the transfer is complete.
+ * \param pTwid Pointer to a Twid instance.
+ * \param address TWI slave address.
+ * \param iaddress Optional slave internal address.
+ * \param isize Internal address size in bytes.
+ * \param pData Data buffer for storing received bytes.
+ * \param num Number of bytes to read.
+ * \param pAsync Asynchronous transfer descriptor.
+ * \param TWI_ID TWI ID for TWI0, TWIHS1, TWIHS2.
+ * \return 0 if the transfer has been started; otherwise returns a TWI error code.
+ */
+uint8_t TWID_DmaRead(
+ TwihsDma *pTwiXdma,
+ uint8_t address,
+ uint32_t iaddress,
+ uint8_t isize,
+ uint8_t *pData,
+ uint32_t num,
+ Async *pAsync)
+{
+ Twihs *pTwi;
+ AsyncTwi *pTransfer;
+ uint32_t status, startTime;
+
+ assert(pTwiXdma->pTwid != NULL);
+ pTwi = pTwiXdma->pTwid->pTwi;
+ pTransfer = (AsyncTwi *) pTwiXdma->pTwid->pTransfer;
+
+ assert((address & 0x80) == 0);
+ assert((iaddress & 0xFF000000) == 0);
+ assert(isize < 4);
+
+ /* Check that no transfer is already pending*/
+ if (pTransfer) {
+
+ TRACE_ERROR("TWID_Read: A transfer is already pending\n\r");
+ return TWID_ERROR_BUSY;
+ }
+
+ /* Asynchronous transfer*/
+ if (pAsync) {
+ /* Update the transfer descriptor */
+ pTwiXdma->pTwid->pTransfer = pAsync;
+ pTransfer = (AsyncTwi *) pAsync;
+ pTransfer->status = ASYNC_STATUS_PENDING;
+ pTransfer->pData = pData;
+ pTransfer->num = num;
+ pTransfer->transferred = 0;
+
+ /* Enable read interrupt and start the transfer */
+ TWI_EnableIt(pTwi, TWIHS_IER_RXRDY);
+ TWI_StartRead(pTwi, address, iaddress, isize);
+ } else {
+ /* Synchronous transfer*/
+ TWID_DmaInitializeRead(pTwiXdma);
+ TWID_XdmaConfigureRead(pTwiXdma, pData, (num - 2));
+
+ /* Start read*/
+ XDMAD_StartTransfer(pTwiXdma->pTwiDma, dmaReadChannel);
+ TWI_StartRead(pTwi, address, iaddress, isize);
+
+ startTime = GetTicks();
+ status = XDMAD_IsTransferDone(pTwiXdma->pTwiDma, dmaReadChannel);
+
+ while (status != XDMAD_OK) {
+ status = XDMAD_IsTransferDone(pTwiXdma->pTwiDma, dmaReadChannel);
+
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID DMA not done\n\r");
+ break;
+ }
+ }
+
+ if (XDMAD_OK == status)
+ SCB_InvalidateDCache_by_Addr((uint32_t *)pData, (num - 2));
+
+ status = TWI_GetStatus(pTwi);
+ startTime = GetTicks();
+
+ while (!(status & TWIHS_SR_RXRDY)) {
+ status = TWI_GetStatus(pTwi);
+
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID DMA not done\n\r");
+ break;
+ }
+ }
+
+ TWI_Stop(pTwi);
+
+ pData[num - 2] = TWI_ReadByte(pTwi);
+ status = TWI_GetStatus(pTwi);
+ startTime = GetTicks();
+
+ while (!(status & TWIHS_SR_RXRDY)) {
+ status = TWI_GetStatus(pTwi);
+
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout Read\n\r");
+ break;
+ }
+ }
+
+ pData[num - 1] = TWI_ReadByte(pTwi);
+ status = TWI_GetStatus(pTwi);
+ startTime = GetTicks();
+
+ while (!(status & TWIHS_SR_TXCOMP)) {
+ status = TWI_GetStatus(pTwi);
+
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout Read\n\r");
+ break;
+ }
+ }
+
+ XDMAD_StopTransfer(pTwiXdma->pTwiDma, dmaReadChannel);
+ XDMAD_FreeChannel(pTwiXdma->pTwiDma, dmaWriteChannel);
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Asynchronously sends data to a slave on the TWI bus. An optional
+ * callback function is invoked whenever the transfer is complete.
+ * \param pTwid Pointer to a Twid instance.
+ * \param address TWI slave address.
+ * \param iaddress Optional slave internal address.
+ * \param isize Number of internal address bytes.
+ * \param pData Data buffer for storing received bytes.
+ * \param num Data buffer to send.
+ * \param pAsync Asynchronous transfer descriptor.
+ * \param TWI_ID TWIHS ID for TWIHS0, TWIHS1, TWIHS2.
+ * \return 0 if the transfer has been started; otherwise returns a TWI error code.
+ */
+uint8_t TWID_DmaWrite(
+ TwihsDma *pTwiXdma,
+ uint8_t address,
+ uint32_t iaddress,
+ uint8_t isize,
+ uint8_t *pData,
+ uint32_t num,
+ Async *pAsync)
+{
+ Twihs *pTwi = pTwiXdma->pTwid->pTwi;
+ AsyncTwi *pTransfer = (AsyncTwi *) pTwiXdma->pTwid->pTransfer;
+ uint32_t status, startTime;
+ //uint8_t singleTransfer = 0;
+ assert(pTwi != NULL);
+ assert((address & 0x80) == 0);
+ assert((iaddress & 0xFF000000) == 0);
+ assert(isize < 4);
+
+ // if (num == 1) singleTransfer = 1;
+ /* Check that no transfer is already pending */
+ if (pTransfer) {
+
+ TRACE_ERROR("TWI_Write: A transfer is already pending\n\r");
+ return TWID_ERROR_BUSY;
+ }
+
+ /* Asynchronous transfer */
+ if (pAsync) {
+
+ /* Update the transfer descriptor */
+ pTwiXdma->pTwid->pTransfer = pAsync;
+ pTransfer = (AsyncTwi *) pAsync;
+ pTransfer->status = ASYNC_STATUS_PENDING;
+ pTransfer->pData = pData;
+ pTransfer->num = num;
+ pTransfer->transferred = 1;
+
+ /* Enable write interrupt and start the transfer */
+ TWI_StartWrite(pTwi, address, iaddress, isize, *pData);
+ TWI_EnableIt(pTwi, TWIHS_IER_TXRDY);
+ } else {
+ /* Synchronous transfer*/
+ TWID_DmaInitializeWrite(pTwiXdma);
+ TWID_XdmaConfigureWrite(pTwiXdma, pData, (num - 1));
+ /* Set slave address and number of internal address bytes. */
+ pTwi->TWIHS_MMR = 0;
+ pTwi->TWIHS_MMR = (isize << 8) | (address << 16);
+
+ /* Set internal address bytes. */
+ pTwi->TWIHS_IADR = 0;
+ pTwi->TWIHS_IADR = iaddress;
+
+ // cache maintenance before starting DMA Xfr
+ SCB_CleanDCache_by_Addr((uint32_t *)pData, (num - 1));
+ startTime = GetTicks();
+
+ XDMAD_StartTransfer(pTwiXdma->pTwiDma, dmaWriteChannel);
+
+ while ((XDMAD_IsTransferDone(pTwiXdma->pTwiDma, dmaWriteChannel))) {
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID DMA not done, Channel State is %d\n\r",
+ pTwiXdma->pTwiDma->XdmaChannels[dmaWriteChannel].state);
+ break;
+ }
+ }
+
+ status = TWI_GetStatus(pTwi);
+ startTime = GetTicks();
+
+ while (!(status & TWIHS_SR_TXRDY)) {
+ status = TWI_GetStatus(pTwi);
+
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout TXRDY\n\r");
+ break;
+ }
+ }
+
+ /* Send a STOP condition */
+ TWI_Stop(pTwi);
+
+ TWI_WriteByte(pTwi, pData[num - 1]);
+ status = TWI_GetStatus(pTwi);
+ startTime = GetTicks();
+
+ while (!(status & TWIHS_SR_TXCOMP)) {
+ status = TWI_GetStatus(pTwi);
+
+ if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
+ TRACE_ERROR("TWID Timeout Write\n\r");
+ break;
+ }
+ }
+
+ XDMAD_StopTransfer(pTwiXdma->pTwiDma, dmaWriteChannel);
+ XDMAD_FreeChannel(pTwiXdma->pTwiDma, dmaWriteChannel);
+
+ }
+
+ return 0;
+}