source: rtems/bsps/arm/atsam/contrib/libraries/libchip/source/twid.c @ 54aabb7

5
Last change on this file since 54aabb7 was 54aabb7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/22/18 at 13:11:43

bsp/atsam: Move libraries to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 21.1 KB
Line 
1/* ---------------------------------------------------------------------------- */
2/*                  Atmel Microcontroller Software Support                      */
3/*                       SAM Software Package License                           */
4/* ---------------------------------------------------------------------------- */
5/* Copyright (c) 2015, Atmel Corporation                                        */
6/*                                                                              */
7/* All rights reserved.                                                         */
8/*                                                                              */
9/* Redistribution and use in source and binary forms, with or without           */
10/* modification, are permitted provided that the following condition is met:    */
11/*                                                                              */
12/* - Redistributions of source code must retain the above copyright notice,     */
13/* this list of conditions and the disclaimer below.                            */
14/*                                                                              */
15/* Atmel's name may not be used to endorse or promote products derived from     */
16/* this software without specific prior written permission.                     */
17/*                                                                              */
18/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
19/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
20/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
21/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
22/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
23/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
24/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
25/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
26/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
27/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
28/* ---------------------------------------------------------------------------- */
29
30/*----------------------------------------------------------------------------
31 *        Headers
32 *----------------------------------------------------------------------------*/
33#include "chip.h"
34
35#include <assert.h>
36
37/*----------------------------------------------------------------------------
38 *        Definition
39 *----------------------------------------------------------------------------*/
40#define TWITIMEOUTMAX 400
41static uint32_t dmaWriteChannel, dmaReadChannel;
42
43extern uint32_t twi_send_stop;
44
45/*----------------------------------------------------------------------------
46 *        Types
47 *----------------------------------------------------------------------------*/
48
49/** TWI driver callback function.*/
50typedef void (*TwiCallback)(Async *);
51
52/** \brief TWI asynchronous transfer descriptor.*/
53typedef struct _AsyncTwi {
54
55        /** Asynchronous transfer status. */
56        volatile uint8_t status;
57        /** Callback function to invoke when transfer completes or fails.*/
58        TwiCallback callback;
59        /** Pointer to the data buffer.*/
60        uint8_t *pData;
61        /** Total number of bytes to transfer.*/
62        uint32_t num;
63        /** Number of already transferred bytes.*/
64        uint32_t transferred;
65
66} AsyncTwi;
67
68/**
69 * \brief Initializes a TWI DMA Read channel.
70 */
71static void TWID_DmaInitializeRead(TwihsDma *pTwiXdma)
72{
73        /* Allocate a XDMA channel, Read accesses into TWI_THR */
74        dmaReadChannel = XDMAD_AllocateChannel(pTwiXdma->pTwiDma, pTwiXdma->Twi_id,
75                                                                                        XDMAD_TRANSFER_MEMORY);
76
77        if (dmaReadChannel == XDMAD_ALLOC_FAILED)
78                printf("-E- Can't allocate XDMA channel\n\r");
79
80        XDMAD_PrepareChannel(pTwiXdma->pTwiDma, dmaReadChannel);
81}
82
83/**
84 * \brief Initializes a TWI DMA write channel.
85 */
86static void TWID_DmaInitializeWrite(TwihsDma *pTwiXdma)
87{
88        /* Allocate a XDMA channel, Write accesses into TWI_THR */
89        dmaWriteChannel = XDMAD_AllocateChannel(pTwiXdma->pTwiDma,
90                                          XDMAD_TRANSFER_MEMORY,
91                                          pTwiXdma->Twi_id);
92
93        if (dmaWriteChannel == XDMAD_ALLOC_FAILED)
94                printf("-E- Can't allocate XDMA channel\n\r");
95
96        XDMAD_PrepareChannel(pTwiXdma->pTwiDma, dmaWriteChannel);
97}
98
99/**
100 * \brief Configure xDMA write linker list for TWI transfer.
101 */
102static uint8_t TWID_XdmaConfigureWrite(TwihsDma *pTwiXdma, uint8_t *buf,
103                                                                           uint32_t len)
104{
105        uint32_t xdmaCndc, Thr, xdmaInt;
106        sXdmadCfg xdmadTxCfg;
107
108        Thr = (uint32_t) & (TWIHS0->TWIHS_THR);
109
110        if (pTwiXdma->Twi_id == ID_TWIHS1)
111                Thr = (uint32_t) & (TWIHS1->TWIHS_THR);
112
113        if (pTwiXdma->Twi_id == ID_TWIHS2)
114                Thr = (uint32_t) & (TWIHS2->TWIHS_THR);
115
116        xdmadTxCfg.mbr_ubc =      XDMA_UBC_NVIEW_NDV0 |
117                                                          XDMA_UBC_NDE_FETCH_DIS |
118                                                          XDMA_UBC_NSEN_UPDATED |  len;
119
120        xdmadTxCfg.mbr_sa = (uint32_t)buf;
121        xdmadTxCfg.mbr_da = Thr;
122        xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
123                                                 XDMAC_CC_MBSIZE_SINGLE |
124                                                 XDMAC_CC_DSYNC_MEM2PER |
125                                                 XDMAC_CC_CSIZE_CHK_1 |
126                                                 XDMAC_CC_DWIDTH_BYTE |
127                                                 XDMAC_CC_SIF_AHB_IF1 |
128                                                 XDMAC_CC_DIF_AHB_IF1 |
129                                                 XDMAC_CC_SAM_INCREMENTED_AM |
130                                                 XDMAC_CC_DAM_FIXED_AM |
131                                                 XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(
132                                                                                        pTwiXdma->Twi_id, XDMAD_TRANSFER_TX));
133
134        xdmadTxCfg.mbr_bc = 0;
135        xdmadTxCfg.mbr_sus = 0;
136        xdmadTxCfg.mbr_dus = 0;
137        xdmaCndc = 0;
138
139        xdmaInt =  (XDMAC_CIE_BIE |
140                                XDMAC_CIE_RBIE  |
141                                XDMAC_CIE_WBIE);
142
143        if (XDMAD_ConfigureTransfer(pTwiXdma->pTwiDma, dmaWriteChannel,
144                                                                 &xdmadTxCfg, xdmaCndc, 0, xdmaInt))
145                return USARTD_ERROR;
146
147        return 0;
148}
149
150
151/**
152 * \brief Configure xDMA read linker list for TWI transfer.
153 */
154static uint8_t TWID_XdmaConfigureRead(TwihsDma *pTwiXdma, uint8_t *buf,
155                                                                          uint32_t len)
156{
157        uint32_t xdmaCndc, Rhr, xdmaInt;
158        sXdmadCfg xdmadRxCfg;
159
160        Rhr = (uint32_t) & (TWIHS0->TWIHS_RHR);
161
162        if (pTwiXdma->Twi_id == ID_TWIHS1)
163                Rhr = (uint32_t) & (TWIHS1->TWIHS_RHR);
164
165        if (pTwiXdma->Twi_id == ID_TWIHS2)
166                Rhr = (uint32_t) & (TWIHS2->TWIHS_RHR);
167
168        xdmadRxCfg.mbr_ubc = XDMA_UBC_NVIEW_NDV0 |
169                                                 XDMA_UBC_NDE_FETCH_DIS |
170                                                 XDMA_UBC_NDEN_UPDATED |
171                                                 len;
172
173        xdmadRxCfg.mbr_da = (uint32_t)buf;
174        xdmadRxCfg.mbr_sa = Rhr;
175
176        xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
177                                                 XDMAC_CC_MBSIZE_SINGLE |
178                                                 XDMAC_CC_DSYNC_PER2MEM |
179                                                 XDMAC_CC_CSIZE_CHK_1 |
180                                                 XDMAC_CC_DWIDTH_BYTE |
181                                                 XDMAC_CC_SIF_AHB_IF1 |
182                                                 XDMAC_CC_DIF_AHB_IF1 |
183                                                 XDMAC_CC_SAM_FIXED_AM |
184                                                 XDMAC_CC_DAM_INCREMENTED_AM |
185                                                 XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(
186                                                                                        pTwiXdma->Twi_id , XDMAD_TRANSFER_RX));
187
188        xdmadRxCfg.mbr_bc = 0;
189        xdmadRxCfg.mbr_sus = 0;
190        xdmadRxCfg.mbr_dus = 0;
191        xdmaCndc = 0;
192        xdmaInt =  (XDMAC_CIE_BIE |
193                                XDMAC_CIE_RBIE  |
194                                XDMAC_CIE_WBIE);
195
196        if (XDMAD_ConfigureTransfer(pTwiXdma->pTwiDma, dmaReadChannel,
197                                                                 &xdmadRxCfg, xdmaCndc, 0, xdmaInt))
198                return 1;
199
200        return 0;
201}
202
203/*----------------------------------------------------------------------------
204 *        Global functions
205 *----------------------------------------------------------------------------*/
206
207/**
208 * \brief Returns 1 if the given transfer has ended; otherwise returns 0.
209 * \param pAsync  Pointer to an Async instance.
210 */
211uint32_t ASYNC_IsFinished(Async *pAsync)
212{
213        return (pAsync->status != ASYNC_STATUS_PENDING);
214}
215
216/**
217 * \brief Initializes a TWI driver instance, using the given TWI peripheral.
218 * \note The peripheral must have been initialized properly before calling this
219 * function.
220 * \param pTwid  Pointer to the Twid instance to initialize.
221 * \param pTwi  Pointer to the TWI peripheral to use.
222 */
223void TWID_Initialize(Twid *pTwid, Twihs *pTwi)
224{
225        TRACE_DEBUG("TWID_Initialize()\n\r");
226        assert(pTwid != NULL);
227        assert(pTwi != NULL);
228
229        /* Initialize driver. */
230        pTwid->pTwi = pTwi;
231        pTwid->pTransfer = 0;
232}
233
234/**
235 * \brief Interrupt handler for a TWI peripheral. Manages asynchronous transfer
236 * occurring on the bus. This function MUST be called by the interrupt service
237 * routine of the TWI peripheral if asynchronous read/write are needed.
238 * \param pTwid  Pointer to a Twid instance.
239 */
240void TWID_Handler(Twid *pTwid)
241{
242        uint8_t status;
243        AsyncTwi *pTransfer;
244        Twihs *pTwi;
245
246        assert(pTwid != NULL);
247
248        pTransfer = (AsyncTwi *)pTwid->pTransfer;
249        assert(pTransfer != NULL);
250        pTwi = pTwid->pTwi;
251        assert(pTwi != NULL);
252
253        /* Retrieve interrupt status */
254        status = TWI_GetMaskedStatus(pTwi);
255
256        /* Byte received */
257        if (TWI_STATUS_RXRDY(status)) {
258
259                pTransfer->pData[pTransfer->transferred] = TWI_ReadByte(pTwi);
260                pTransfer->transferred++;
261
262                /* check for transfer finish */
263                if (pTransfer->transferred == pTransfer->num) {
264
265                        TWI_DisableIt(pTwi, TWIHS_IDR_RXRDY);
266                        TWI_EnableIt(pTwi, TWIHS_IER_TXCOMP);
267                }
268                /* Last byte? */
269                else if (pTransfer->transferred == (pTransfer->num - 1))
270
271                        TWI_Stop(pTwi);
272        }
273        /* Byte sent*/
274        else if (TWI_STATUS_TXRDY(status)) {
275
276                /* Transfer finished ? */
277                if (pTransfer->transferred == pTransfer->num) {
278
279                        TWI_DisableIt(pTwi, TWIHS_IDR_TXRDY);
280                        TWI_EnableIt(pTwi, TWIHS_IER_TXCOMP);
281                        TWI_SendSTOPCondition(pTwi);
282                }
283                /* Bytes remaining */
284                else {
285
286                        TWI_WriteByte(pTwi, pTransfer->pData[pTransfer->transferred]);
287                        pTransfer->transferred++;
288                }
289        }
290        /* Transfer complete*/
291        else if (TWI_STATUS_TXCOMP(status)) {
292
293                TWI_DisableIt(pTwi, TWIHS_IDR_TXCOMP);
294                pTransfer->status = 0;
295
296                if (pTransfer->callback)
297                        pTransfer->callback((Async *) pTransfer);
298
299                pTwid->pTransfer = 0;
300        }
301}
302
303/**
304 * \brief Asynchronously reads data from a slave on the TWI bus. An optional
305 * callback function is triggered when the transfer is complete.
306 * \param pTwid  Pointer to a Twid instance.
307 * \param address  TWI slave address.
308 * \param iaddress  Optional slave internal address.
309 * \param isize  Internal address size in bytes.
310 * \param pData  Data buffer for storing received bytes.
311 * \param num  Number of bytes to read.
312 * \param pAsync  Asynchronous transfer descriptor.
313 * \return 0 if the transfer has been started; otherwise returns a TWI error code.
314 */
315uint8_t TWID_Read(
316        Twid *pTwid,
317        uint8_t address,
318        uint32_t iaddress,
319        uint8_t isize,
320        uint8_t *pData,
321        uint32_t num,
322        Async *pAsync)
323{
324        Twihs *pTwi;
325        AsyncTwi *pTransfer;
326        uint32_t startTime;
327        assert(pTwid != NULL);
328        pTwi = pTwid->pTwi;
329        pTransfer = (AsyncTwi *) pTwid->pTransfer;
330
331        assert((address & 0x80) == 0);
332        assert((iaddress & 0xFF000000) == 0);
333        assert(isize < 4);
334
335        /* Check that no transfer is already pending*/
336        if (pTransfer) {
337
338                TRACE_ERROR("TWID_Read: A transfer is already pending\n\r");
339                return TWID_ERROR_BUSY;
340        }
341
342        /* In single data byte master read, the START and STOP must both be set */
343        twi_send_stop = (num == 1) ? 1 : 0;
344
345        /* Asynchronous transfer*/
346        if (pAsync) {
347
348                /* Update the transfer descriptor */
349                pTwid->pTransfer = pAsync;
350                pTransfer = (AsyncTwi *) pAsync;
351                pTransfer->status = ASYNC_STATUS_PENDING;
352                pTransfer->pData = pData;
353                pTransfer->num = num;
354                pTransfer->transferred = 0;
355
356                /* Enable read interrupt and start the transfer */
357                TWI_EnableIt(pTwi, TWIHS_IER_RXRDY);
358                TWI_StartRead(pTwi, address, iaddress, isize);
359        }
360        /* Synchronous transfer*/
361        else {
362
363                /* Start read*/
364                TWI_StartRead(pTwi, address, iaddress, isize);
365
366                /* Read all bytes, setting STOP before the last byte*/
367                while (num > 0) {
368
369                        /* Last byte ?*/
370                        if (num == 1)
371                                TWI_Stop(pTwi);
372
373                        /* Wait for byte then read and store it*/
374                        startTime = GetTicks();
375
376                        while (!TWI_ByteReceived(pTwi)) {
377                                if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
378                                        TRACE_ERROR("TWID Timeout BR\n\r");
379                                        break;
380                                }
381                        }
382
383                        *pData++ = TWI_ReadByte(pTwi);
384                        num--;
385                }
386
387                /* Wait for transfer to be complete */
388                startTime = GetTicks();
389
390                while (!TWI_TransferComplete(pTwi)) {
391                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
392                                TRACE_ERROR("TWID Timeout TC\n\r");
393                                break;
394                        }
395                }
396        }
397
398        return 0;
399}
400
401/**
402 * \brief Asynchronously sends data to a slave on the TWI bus. An optional
403 * callback function is invoked whenever the transfer is complete.
404 * \param pTwid  Pointer to a Twid instance.
405 * \param address  TWI slave address.
406 * \param iaddress  Optional slave internal address.
407 * \param isize  Number of internal address bytes.
408 * \param pData  Data buffer for storing received bytes.
409 * \param num  Data buffer to send.
410 * \param pAsync  Asynchronous transfer descriptor.
411 * \return 0 if the transfer has been started; otherwise returns a TWI error code.
412 */
413uint8_t TWID_Write(
414        Twid *pTwid,
415        uint8_t address,
416        uint32_t iaddress,
417        uint8_t isize,
418        uint8_t *pData,
419        uint32_t num,
420        Async *pAsync)
421{
422        Twihs *pTwi = pTwid->pTwi;
423        uint32_t startTime;
424        AsyncTwi *pTransfer = (AsyncTwi *) pTwid->pTransfer;
425
426        assert(pTwi != NULL);
427        assert((address & 0x80) == 0);
428        assert((iaddress & 0xFF000000) == 0);
429        assert(isize < 4);
430
431        /* Check that no transfer is already pending */
432        if (pTransfer) {
433                TRACE_ERROR("TWI_Write: A transfer is already pending\n\r");
434                return TWID_ERROR_BUSY;
435        }
436
437        /* Asynchronous transfer */
438        if (pAsync) {
439                /* Update the transfer descriptor */
440                pTwid->pTransfer = pAsync;
441                pTransfer = (AsyncTwi *) pAsync;
442                pTransfer->status = ASYNC_STATUS_PENDING;
443                pTransfer->pData = pData;
444                pTransfer->num = num;
445                pTransfer->transferred = 1;
446
447                /* Enable write interrupt and start the transfer */
448                TWI_StartWrite(pTwi, address, iaddress, isize, *pData);
449                TWI_EnableIt(pTwi, TWIHS_IER_TXRDY);
450
451        } else {
452                /* Synchronous transfer*/
453                // Start write
454                TWI_StartWrite(pTwi, address, iaddress, isize, *pData++);
455                num--;
456
457                /* Send all bytes */
458                while (num > 0) {
459                        /* Wait before sending the next byte */
460                        startTime = GetTicks();
461
462                        while (!TWI_ByteSent(pTwi)) {
463                                if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
464                                        TRACE_ERROR("TWID Timeout BS\n\r");
465                                        break;
466                                }
467                        }
468
469                        TWI_WriteByte(pTwi, *pData++);
470                        num--;
471                }
472
473                /* Wait for actual end of transfer */
474                startTime = GetTicks();
475                /* Send a STOP condition */
476                TWI_SendSTOPCondition(pTwi);
477
478                while (!TWI_TransferComplete(pTwi)) {
479                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
480                                TRACE_ERROR("TWID Timeout TC2\n\r");
481                                break;
482                        }
483                }
484        }
485
486        return 0;
487}
488
489/**
490 * \brief Initializes a TWI driver instance, using the given TWI peripheral.
491 * \note The peripheral must have been initialized properly before calling this
492 * function.
493 * \param pTwid  Pointer to the Twid instance to initialize.
494 * \param pTwi  Pointer to the TWI peripheral to use.
495 */
496void TWID_DmaInitialize(TwihsDma *pTwidma, Twihs *pTwi, uint8_t bPolling)
497{
498        TRACE_DEBUG("TWID_Initialize()\n\r");
499        assert(pTwidma != NULL);
500
501        if ((unsigned int)pTwi == (unsigned int)TWIHS0) pTwidma->Twi_id = ID_TWIHS0;
502
503        if ((unsigned int)pTwi == (unsigned int)TWIHS1) pTwidma->Twi_id = ID_TWIHS1;
504
505        if ((unsigned int)pTwi == (unsigned int)TWIHS2) pTwidma->Twi_id = ID_TWIHS2;
506
507        /* Initialize driver. */
508        pTwidma->pTwid->pTwi = pTwi;
509        pTwidma->pTwid->pTransfer = 0;
510
511        assert(!bPolling);
512}
513
514/**
515 * \brief Asynchronously reads data from a slave on the TWI bus. An optional
516 * callback function is triggered when the transfer is complete.
517 * \param pTwid  Pointer to a Twid instance.
518 * \param address  TWI slave address.
519 * \param iaddress  Optional slave internal address.
520 * \param isize  Internal address size in bytes.
521 * \param pData  Data buffer for storing received bytes.
522 * \param num  Number of bytes to read.
523 * \param pAsync  Asynchronous transfer descriptor.
524 * \param TWI_ID  TWI ID for TWI0, TWIHS1, TWIHS2.
525 * \return 0 if the transfer has been started; otherwise returns a TWI error code.
526 */
527uint8_t TWID_DmaRead(
528        TwihsDma *pTwiXdma,
529        uint8_t address,
530        uint32_t iaddress,
531        uint8_t isize,
532        uint8_t *pData,
533        uint32_t num,
534        Async *pAsync)
535{
536        Twihs *pTwi;
537        AsyncTwi *pTransfer;
538        uint32_t status, startTime;
539
540        assert(pTwiXdma->pTwid != NULL);
541        pTwi = pTwiXdma->pTwid->pTwi;
542        pTransfer = (AsyncTwi *) pTwiXdma->pTwid->pTransfer;
543
544        assert((address & 0x80) == 0);
545        assert((iaddress & 0xFF000000) == 0);
546        assert(isize < 4);
547
548        /* Check that no transfer is already pending*/
549        if (pTransfer) {
550
551                TRACE_ERROR("TWID_Read: A transfer is already pending\n\r");
552                return TWID_ERROR_BUSY;
553        }
554
555        /* Asynchronous transfer*/
556        if (pAsync) {
557                /* Update the transfer descriptor */
558                pTwiXdma->pTwid->pTransfer = pAsync;
559                pTransfer = (AsyncTwi *) pAsync;
560                pTransfer->status = ASYNC_STATUS_PENDING;
561                pTransfer->pData = pData;
562                pTransfer->num = num;
563                pTransfer->transferred = 0;
564
565                /* Enable read interrupt and start the transfer */
566                TWI_EnableIt(pTwi, TWIHS_IER_RXRDY);
567                TWI_StartRead(pTwi, address, iaddress, isize);
568        } else {
569                /* Synchronous transfer*/
570                TWID_DmaInitializeRead(pTwiXdma);
571                TWID_XdmaConfigureRead(pTwiXdma, pData, (num - 2));
572
573                /* Start read*/
574                XDMAD_StartTransfer(pTwiXdma->pTwiDma, dmaReadChannel);
575                TWI_StartRead(pTwi, address, iaddress, isize);
576
577                startTime = GetTicks();
578                status = XDMAD_IsTransferDone(pTwiXdma->pTwiDma, dmaReadChannel);
579
580                while (status != XDMAD_OK) {
581                        status = XDMAD_IsTransferDone(pTwiXdma->pTwiDma, dmaReadChannel);
582
583                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
584                                TRACE_ERROR("TWID DMA not done\n\r");
585                                break;
586                        }
587                }
588
589                if (XDMAD_OK == status)
590                        SCB_InvalidateDCache_by_Addr((uint32_t *)pData, (num - 2));
591
592                status = TWI_GetStatus(pTwi);
593                startTime = GetTicks();
594
595                while (!(status & TWIHS_SR_RXRDY)) {
596                        status = TWI_GetStatus(pTwi);
597
598                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
599                                TRACE_ERROR("TWID DMA not done\n\r");
600                                break;
601                        }
602                }
603
604                TWI_Stop(pTwi);
605
606                pData[num - 2] = TWI_ReadByte(pTwi);
607                status = TWI_GetStatus(pTwi);
608                startTime = GetTicks();
609
610                while (!(status & TWIHS_SR_RXRDY)) {
611                        status = TWI_GetStatus(pTwi);
612
613                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
614                                TRACE_ERROR("TWID Timeout Read\n\r");
615                                break;
616                        }
617                }
618
619                pData[num - 1] = TWI_ReadByte(pTwi);
620                status = TWI_GetStatus(pTwi);
621                startTime = GetTicks();
622
623                while (!(status & TWIHS_SR_TXCOMP)) {
624                        status = TWI_GetStatus(pTwi);
625
626                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
627                                TRACE_ERROR("TWID Timeout Read\n\r");
628                                break;
629                        }
630                }
631
632                XDMAD_StopTransfer(pTwiXdma->pTwiDma, dmaReadChannel);
633                XDMAD_FreeChannel(pTwiXdma->pTwiDma, dmaWriteChannel);
634        }
635
636        return 0;
637}
638
639/**
640 * \brief Asynchronously sends data to a slave on the TWI bus. An optional
641 * callback function is invoked whenever the transfer is complete.
642 * \param pTwid  Pointer to a Twid instance.
643 * \param address  TWI slave address.
644 * \param iaddress  Optional slave internal address.
645 * \param isize  Number of internal address bytes.
646 * \param pData  Data buffer for storing received bytes.
647 * \param num  Data buffer to send.
648 * \param pAsync  Asynchronous transfer descriptor.
649 * \param TWI_ID  TWIHS ID for TWIHS0, TWIHS1, TWIHS2.
650 * \return 0 if the transfer has been started; otherwise returns a TWI error code.
651 */
652uint8_t TWID_DmaWrite(
653        TwihsDma *pTwiXdma,
654        uint8_t address,
655        uint32_t iaddress,
656        uint8_t isize,
657        uint8_t *pData,
658        uint32_t num,
659        Async *pAsync)
660{
661        Twihs *pTwi = pTwiXdma->pTwid->pTwi;
662        AsyncTwi *pTransfer = (AsyncTwi *) pTwiXdma->pTwid->pTransfer;
663        uint32_t status, startTime;
664        //uint8_t singleTransfer = 0;
665        assert(pTwi != NULL);
666        assert((address & 0x80) == 0);
667        assert((iaddress & 0xFF000000) == 0);
668        assert(isize < 4);
669
670        //    if (num == 1) singleTransfer = 1;
671        /* Check that no transfer is already pending */
672        if (pTransfer) {
673
674                TRACE_ERROR("TWI_Write: A transfer is already pending\n\r");
675                return TWID_ERROR_BUSY;
676        }
677
678        /* Asynchronous transfer */
679        if (pAsync) {
680
681                /* Update the transfer descriptor */
682                pTwiXdma->pTwid->pTransfer = pAsync;
683                pTransfer = (AsyncTwi *) pAsync;
684                pTransfer->status = ASYNC_STATUS_PENDING;
685                pTransfer->pData = pData;
686                pTransfer->num = num;
687                pTransfer->transferred = 1;
688
689                /* Enable write interrupt and start the transfer */
690                TWI_StartWrite(pTwi, address, iaddress, isize, *pData);
691                TWI_EnableIt(pTwi, TWIHS_IER_TXRDY);
692        } else {
693                /* Synchronous transfer*/
694                TWID_DmaInitializeWrite(pTwiXdma);
695                TWID_XdmaConfigureWrite(pTwiXdma, pData, (num - 1));
696                /* Set slave address and number of internal address bytes. */
697                pTwi->TWIHS_MMR = 0;
698                pTwi->TWIHS_MMR = (isize << 8) | (address << 16);
699
700                /* Set internal address bytes. */
701                pTwi->TWIHS_IADR = 0;
702                pTwi->TWIHS_IADR = iaddress;
703
704                // cache maintenance before starting DMA Xfr
705                SCB_CleanDCache_by_Addr((uint32_t *)pData, (num - 1));
706                startTime = GetTicks();
707
708                XDMAD_StartTransfer(pTwiXdma->pTwiDma, dmaWriteChannel);
709
710                while ((XDMAD_IsTransferDone(pTwiXdma->pTwiDma, dmaWriteChannel))) {
711                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
712                                TRACE_ERROR("TWID DMA not done, Channel State is %d\n\r",
713                                                        pTwiXdma->pTwiDma->XdmaChannels[dmaWriteChannel].state);
714                                break;
715                        }
716                }
717
718                status = TWI_GetStatus(pTwi);
719                startTime = GetTicks();
720
721                while (!(status & TWIHS_SR_TXRDY)) {
722                        status = TWI_GetStatus(pTwi);
723
724                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
725                                TRACE_ERROR("TWID Timeout TXRDY\n\r");
726                                break;
727                        }
728                }
729
730                /* Send a STOP condition */
731                TWI_Stop(pTwi);
732
733                TWI_WriteByte(pTwi, pData[num - 1]);
734                status = TWI_GetStatus(pTwi);
735                startTime = GetTicks();
736
737                while (!(status & TWIHS_SR_TXCOMP)) {
738                        status = TWI_GetStatus(pTwi);
739
740                        if ((GetDelayInTicks(startTime, GetTicks())) > TWITIMEOUTMAX) {
741                                TRACE_ERROR("TWID Timeout Write\n\r");
742                                break;
743                        }
744                }
745
746                XDMAD_StopTransfer(pTwiXdma->pTwiDma, dmaWriteChannel);
747                XDMAD_FreeChannel(pTwiXdma->pTwiDma, dmaWriteChannel);
748
749        }
750
751        return 0;
752}
Note: See TracBrowser for help on using the repository browser.