From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- drivers/twi/twid.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/twi/twid.h | 92 ++++++++++++++ 2 files changed, 436 insertions(+) create mode 100644 drivers/twi/twid.c create mode 100644 drivers/twi/twid.h (limited to 'drivers/twi') diff --git a/drivers/twi/twid.c b/drivers/twi/twid.c new file mode 100644 index 0000000..d08d96a --- /dev/null +++ b/drivers/twi/twid.c @@ -0,0 +1,344 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are 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. + * ---------------------------------------------------------------------------- + */ + + +#define TWITIMEOUTMAX 50000 + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "twid.h" +#include +#include +#include + +//------------------------------------------------------------------------------ +// Local types +//------------------------------------------------------------------------------ + +/// TWI driver callback function. +typedef void (*TwiCallback)(Async *); + +//------------------------------------------------------------------------------ +/// TWI asynchronous transfer descriptor. +//------------------------------------------------------------------------------ +typedef struct _AsyncTwi { + + /// Asynchronous transfer status. + volatile unsigned char status; + // Callback function to invoke when transfer completes or fails. + TwiCallback callback; + /// Pointer to the data buffer. + unsigned char *pData; + /// Total number of bytes to transfer. + unsigned int num; + /// Number of already transferred bytes. + unsigned int transferred; + +} AsyncTwi; + +//------------------------------------------------------------------------------ +// Global functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes a TWI driver instance, using the given TWI peripheral. 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, AT91S_TWI *pTwi) +{ + TRACE_DEBUG("TWID_Initialize()\n\r"); + SANITY_CHECK(pTwid); + SANITY_CHECK(pTwi); + + // Initialize driver + pTwid->pTwi = pTwi; + pTwid->pTransfer = 0; +} + +//------------------------------------------------------------------------------ +/// Interrupt handler for a TWI peripheral. Manages asynchronous transfer +/// occuring 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) +{ + unsigned char status; + AsyncTwi *pTransfer = (AsyncTwi *) pTwid->pTransfer; + AT91S_TWI *pTwi = pTwid->pTwi; + + SANITY_CHECK(pTwid); + + // Retrieve interrupt status + status = TWI_GetMaskedStatus(pTwi); + + // Byte received + if (TWI_STATUS_RXRDY(status)) { + + pTransfer->pData[pTransfer->transferred] = TWI_ReadByte(pTwi); + pTransfer->transferred++; + + // Transfer finished ? + if (pTransfer->transferred == pTransfer->num) { + + TWI_DisableIt(pTwi, AT91C_TWI_RXRDY); + TWI_EnableIt(pTwi, AT91C_TWI_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, AT91C_TWI_TXRDY); + TWI_EnableIt(pTwi, AT91C_TWI_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, AT91C_TWI_TXCOMP); + pTransfer->status = 0; + if (pTransfer->callback) { + + pTransfer->callback((Async *) pTransfer); + } + pTwid->pTransfer = 0; + } +} + +//----------------------------------------------------------------------------- +/// Asynchronously reads data from a slave on the TWI bus. An optional +/// callback function is triggered when the transfer is complete. +/// Returns 0 if the transfer has been started; otherwise returns a TWI error +/// code. +/// \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. +//----------------------------------------------------------------------------- +unsigned char TWID_Read( + Twid *pTwid, + unsigned char address, + unsigned int iaddress, + unsigned char isize, + unsigned char *pData, + unsigned int num, + Async *pAsync) +{ + AT91S_TWI *pTwi = pTwid->pTwi; + AsyncTwi *pTransfer = (AsyncTwi *) pTwid->pTransfer; + unsigned int timeout; + + //TRACE_DEBUG("TWID_Read()\n\r"); + SANITY_CHECK(pTwid); + SANITY_CHECK((address & 0x80) == 0); + SANITY_CHECK((iaddress & 0xFF000000) == 0); + SANITY_CHECK(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; + } + + // Set STOP signal if only one byte is sent + if (num == 1) { + + TWI_Stop(pTwi); + } + + // 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, AT91C_TWI_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 + timeout = 0; + while( !TWI_ByteReceived(pTwi) && (++timeoutpTwi; + AsyncTwi *pTransfer = (AsyncTwi *) pTwid->pTransfer; + unsigned int timeout; + + //TRACE_DEBUG("TWID_Write()\n\r"); + //TRACE_DEBUG("0x%X\n\r", pData[0]); + SANITY_CHECK(pTwi); + SANITY_CHECK((address & 0x80) == 0); + SANITY_CHECK((iaddress & 0xFF000000) == 0); + SANITY_CHECK(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, AT91C_TWI_TXRDY); + } + // Synchronous transfer + else { + + // Start write + TWI_StartWrite(pTwi, address, iaddress, isize, *pData++); + num--; + + // Send all bytes + while (num > 0) { + + // Wait before sending the next byte + timeout = 0; + while( !TWI_ByteSent(pTwi) && (++timeout +#include + +//------------------------------------------------------------------------------ +// Global definitions +//------------------------------------------------------------------------------ + +/// TWI driver is currently busy. +#define TWID_ERROR_BUSY 1 +/// TWI driver operation timeout. +#define TWID_ERROR_TIMEOUT 2 + +//------------------------------------------------------------------------------ +// Global types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// TWI driver structure. Holds the internal state of the driver. +//------------------------------------------------------------------------------ +typedef struct _Twid { + + /// Pointer to the underlying TWI peripheral. + AT91S_TWI *pTwi; + /// Current asynchronous transfer being processed. + Async *pTransfer; + +} Twid; + +//------------------------------------------------------------------------------ +// Global functions +//------------------------------------------------------------------------------ + +extern void TWID_Initialize(Twid *pTwid, AT91S_TWI *pTwi); + +extern void TWID_Handler(Twid *pTwid); + +extern unsigned char TWID_Read( + Twid *pTwid, + unsigned char address, + unsigned int iaddress, + unsigned char isize, + unsigned char *pData, + unsigned int num, + Async *pAsync); + +extern unsigned char TWID_Write( + Twid *pTwid, + unsigned char address, + unsigned int iaddress, + unsigned char isize, + unsigned char *pData, + unsigned int num, + Async *pAsync); + +#endif //#ifndef TWID_H + -- cgit v1.2.3