| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 |
- /*
- * Copyright (C) 2001-2005 by EmbeddedIT, Ole Reinhardt
- * Copyright (C) 2009 by Rittal GmbH & Co. KG, Ulrich Prinz
- * Copyright 2009 by egnite GmbH
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS 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.
- *
- * For additional information see http://www.ethernut.de/
- *
- */
- /*
- * $Id: at91_twi.c 5472 2013-12-06 00:16:28Z olereinhardt $
- */
- #include <arch/arm.h>
- #include <dev/irqreg.h>
- #include <string.h>
- #include <sys/event.h>
- #include <sys/atom.h>
- #include <sys/timer.h>
- #include <sys/thread.h>
- #include <sys/heap.h>
- #include <dev/twif.h>
- /*!
- * \addtogroup xgNutArchArmAt91Twi
- */
- /*@{*/
- /*
- * Set ports for known targets.
- */
- #if defined(MCU_AT91SAM7X)
- #define TWI_TWD PA10_TWD_A
- #define TWI_TWCK PA11_TWCK_A
- #elif defined(MCU_AT91SAM7S) || defined(MCU_AT91SAM7SE)
- #define TWI_TWD PA3_TWD_A
- #define TWI_TWCK PA4_TWCK_A
- #elif defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE)
- #define TWI_TWD PA23_TWD_A
- #define TWI_TWCK PA24_TWCK_A
- #elif defined (MCU_AT91SAM9G45)
- #define TWI_TWD PA20_TWD0_A
- #define TWI_TWCK PA21_TWCK0_A
- #endif
- /*
- * Set port defaults, assume PIOA.
- */
- #ifndef TWI_PIO_ASR
- #define TWI_PIO_ASR PIOA_ASR
- #endif
- #ifndef TWI_PIO_PDR
- #define TWI_PIO_PDR PIOA_PDR
- #endif
- #ifndef TWI_PIO_MDER
- #define TWI_PIO_MDER PIOA_MDER
- #endif
- #if 0
- static uint8_t *tw_mm_buf; /* Pointer to the master transfer buffer. */
- static volatile size_t tw_mm_len; /* Number of bytes to transmit in master mode. */
- static volatile size_t tw_mm_idx; /* Current master transmit buffer index. */
- #endif
- /*
- * TWI interrupt handler.
- */
- static void TwInterrupt(void *arg)
- {
- register unsigned int twsr;
- NUTTWIBUS *bus = arg;
- NUTTWIICB *icb = bus->bus_icb;
- /* Read the status register and check for errors. */
- twsr = inr(TWI_SR);
- if (twsr & (TWI_NACK | TWI_OVRE | TWI_ARBLST)) {
- if (twsr & TWI_NACK) {
- icb->tw_mm_err = TWERR_SLA_NACK;
- } else {
- icb->tw_mm_err = TWERR_BUS;
- }
- }
- /* Mask inactive interrupt flags. */
- twsr &= inr(TWI_IMR);
- if (twsr & TWI_TXRDY) {
- /* Byte has been transmitted. */
- if (icb->tw_mm_idx < icb->tw_mm_len) {
- /* More bytes in buffer, send next one. */
- outb(TWI_THR, icb->tw_mm_buf[icb->tw_mm_idx]);
- icb->tw_mm_idx++;
- } else {
- /* All bytes sent, wait for completion. */
- #if defined(MCU_AT91SAM9XE)
- /* On the SAM9XE the stop condition is not sent automatically
- when the transmitter runs out of data. */
- outr(TWI_CR, TWI_STOP);
- #endif
- outr(TWI_IDR, TWI_TXRDY);
- outr(TWI_IER, TWI_TXCOMP);
- }
- } else if (twsr & TWI_RXRDY) {
- /* Byte has been received. */
- if (icb->tw_mm_idx < icb->tw_mm_len) {
- /* Store byte in receive buffer. */
- icb->tw_mm_buf[icb->tw_mm_idx++] = inb(TWI_RHR);
- if (icb->tw_mm_idx == icb->tw_mm_len - 1) {
- /* Next byte will be last, set STOP condition. */
- outr(TWI_CR, TWI_STOP);
- } else if (icb->tw_mm_idx == icb->tw_mm_len) {
- /* This was the last byte, wait for completion. */
- outr(TWI_IDR, TWI_RXRDY);
- outr(TWI_IER, TWI_TXCOMP);
- }
- }
- } else if (twsr & TWI_TXCOMP) {
- /* Transfer is complete, disable interrupts
- ** and signal waiting threads */
- outr(TWI_IDR, 0xFFFFFFFF);
- NutEventPostFromIrq(&icb->tw_mm_mtx);
- }
- }
- /*!
- * \brief Transmit and/or receive data as a master.
- *
- * The two-wire serial interface must have been initialized by calling
- * TwInit() before this function can be used.
- *
- * \param sla Slave address of the destination. This slave address
- * must be specified as a 7-bit address. For example, the
- * PCF8574A may be configured to slave addresses from 0x38
- * to 0x3F.
- * \param txdata Points to the data to transmit. Ignored, if the number
- * of data bytes to transmit is zero.
- * \param txlen Number of data bytes to transmit. If zero, then the
- * interface will not send any data to the slave device
- * and will directly enter the master receive mode.
- * \param rxdata Points to a buffer, where the received data will be
- * stored. Ignored, if the maximum number of bytes to
- * receive is zero.
- * \param rxsiz Maximum number of bytes to receive. Set to zero, if
- * no bytes are expected from the slave device.
- * \param tmo Timeout in milliseconds. To disable timeout, set this
- * parameter to NUT_WAIT_INFINITE.
- *
- * \return The number of bytes received, -1 in case of an error or timeout.
- */
- int NutTwiMasterTranceive(NUTTWIBUS *bus, uint8_t sla, const void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
- {
- int rc = -1;
- NUTTWIICB *icb = bus->bus_icb;
- /* This routine is marked reentrant, so lock the interface. */
- if (NutEventWait(&bus->bus_mutex, tmo)) {
- icb->tw_mm_error = TWERR_IF_LOCKED;
- return -1;
- }
- /* Clear errors. */
- icb->tw_mm_err = 0;
- /* Check if there is something to transmit. */
- if (txlen) {
- /* Set transmit parameters. */
- icb->tw_mm_buf = (uint8_t *) txdata;
- icb->tw_mm_len = (size_t) txlen;
- icb->tw_mm_idx = 1;
- /* Start transmit to specified slave address. */
- outr(TWI_MMR, (unsigned int) sla << TWI_DADR_LSB);
- outr(TWI_THR, icb->tw_mm_buf[0]);
- outr(TWI_IER, TWI_TXRDY);
- /* Wait for transmission complete. */
- // TODO: Mustn't this be NutEventWaitNext() ??
- if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
- icb->tw_mm_err = TWERR_TIMEOUT;
- }
- }
- if (icb->tw_mm_err == 0) {
- /* Reset receive counter. We need this below to set
- ** the return value. */
- icb->tw_mm_idx = 0;
- /* Check if there is something to receive. */
- if (rxsiz) {
- /* Set remaining receive parameters. */
- icb->tw_mm_buf = (uint8_t *) rxdata;
- icb->tw_mm_len = (size_t) rxsiz;
- /* Start receive from specified slave address. */
- outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | TWI_MREAD);
- if (rxsiz == 1) {
- /* Set STOP condition if this is the last byte. */
- outr(TWI_CR, TWI_START | TWI_STOP);
- } else {
- outr(TWI_CR, TWI_START);
- }
- outr(TWI_IER, TWI_RXRDY);
- /* Wait for receiver complete. */
- if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
- icb->tw_mm_err = TWERR_TIMEOUT;
- }
- }
- }
- /* Make sure that all interrupts are disabled. */
- outr(TWI_IDR, 0xFFFFFFFF);
- /* Check for errors that may have been detected
- ** by the interrupt routine. */
- if (icb->tw_mm_err) {
- icb->tw_mm_error = icb->tw_mm_err;
- } else {
- rc = (int) icb->tw_mm_idx;
- }
- /* Release the interface. */
- NutEventPost(&bus->bus_mutex);
- return rc;
- }
- /*!
- * \brief Receive data as a master from a device having internal addressable registers
- *
- * The two-wire serial interface must have been initialized by calling
- * TwInit() before this function can be used.
- *
- * \param sla Slave address of the destination. This slave address
- * must be specified as a 7-bit address. For example, the
- * PCF8574A may be configured to slave addresses from 0x38
- * to 0x3F.
- * \param iadr Address send to the device to access certain registers
- * or memory addresses of it.
- * \param iadrlen Number of bytes to send as address, maximum 3 bytes are
- * supported from AT91SAM7
- * \param rxdata Points to a buffer, where the received data will be
- * stored.
- * \param rxsiz Maximum number of bytes to receive.
- * \param tmo Timeout in milliseconds. To disable timeout, set this
- * parameter to NUT_WAIT_INFINITE.
- *
- * \return The number of bytes received, -1 in case of an error or timeout.
- */
- int NutTwiMasterRegRead(NUTTWIBUS *bus, uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
- {
- int rc = -1;
- NUTTWIICB *icb = bus->bus_icb;
- if (rxsiz == 0) {
- return -1;
- }
- /* This routine is marked reentrant, so lock the interface. */
- if (NutEventWait(&bus->bus_mutex, tmo)) {
- icb->tw_mm_error = TWERR_IF_LOCKED;
- return -1;
- }
- icb->tw_mm_err = 0;
- if (rxsiz) {
- icb->tw_mm_buf = rxdata;
- icb->tw_mm_len = (size_t) rxsiz;
- icb->tw_mm_idx = 0;
- /* Set TWI Internal Address Register if needed */
- outr(TWI_IADRR, iadr);
- /* Set the TWI Master Mode Register */
- outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8) | TWI_MREAD);
- /* Send start condition. If read only one byte send stop as well */
- if (rxsiz == 1) {
- outr(TWI_CR, TWI_START | TWI_STOP);
- } else {
- outr(TWI_CR, TWI_START);
- }
- outr(TWI_IER, TWI_RXRDY);
- /* Wait for master transmission to be done. */
- if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
- icb->tw_mm_error = TWERR_TIMEOUT;
- } else if (icb->tw_mm_err) {
- icb->tw_mm_error = icb->tw_mm_err;
- } else {
- rc = (int) icb->tw_mm_idx;
- }
- outr(TWI_IDR, 0xFFFFFFFF);
- }
- /* Release the interface. */
- NutEventPost(&bus->bus_mutex);
- return rc;
- }
- /*!
- * \brief Transmit data as a master to a device having internal addressable registers
- *
- * The two-wire serial interface must have been initialized by calling
- * TwInit() before this function can be used.
- *
- * \param sla Slave address of the destination. This slave address
- * must be specified as a 7-bit address. For example, the
- * PCF8574A may be configured to slave addresses from 0x38
- * to 0x3F.
- * \param iadr Address send to the device to access certain registers
- * or memory addresses of it.
- * \param iadrlen Number of bytes to send as address, maximum 3 bytes are
- * supported from AT91SAM7
- * \param txdata Points to a buffer, where the data to transmit will be
- * stored.
- * \param txsiz Maximum number of bytes to transmit.
- * \param tmo Timeout in milliseconds. To disable timeout, set this
- * parameter to NUT_WAIT_INFINITE.
- *
- * \return The number of bytes transmitted, -1 in case of an error
- * or timeout. Number could be less if slave end transmission
- * with NAK.
- */
- int NutTwiMasterRegWrite(NUTTWIBUS *bus,
- uint8_t sla,
- uint32_t iadr,
- uint8_t iadrlen,
- const void *txdata,
- uint16_t txsiz,
- uint32_t tmo)
- {
- int rc = -1;
- NUTTWIICB *icb = bus->bus_icb;
- /* This routine is marked reentrant, so lock the interface. */
- if (NutEventWait(&bus->bus_mutex, tmo)) {
- icb->tw_mm_err = TWERR_IF_LOCKED;
- return -1;
- }
- icb->tw_mm_err = 0;
- if (txsiz) {
- icb->tw_mm_buf = (uint8_t *) txdata;
- icb->tw_mm_len = (size_t) txsiz;
- icb->tw_mm_idx = 1;
- /* Set TWI Internal Address Register */
- outr(TWI_IADRR, iadr);
- /* Set the TWI Master Mode Register */
- outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8));
- outb(TWI_THR, icb->tw_mm_buf[0]);
- outr(TWI_IER, TWI_TXRDY);
- /* Wait for master transmission to be done. */
- if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
- icb->tw_mm_error = TWERR_TIMEOUT;
- } else if (icb->tw_mm_err) {
- icb->tw_mm_error = icb->tw_mm_err;
- } else {
- rc = (int) icb->tw_mm_idx;
- }
- outr(TWI_IDR, 0xFFFFFFFF);
- }
- /* Release the interface. */
- NutEventPost(&bus->bus_mutex);
- return rc;
- }
- /*!
- * \brief Get last master mode error.
- *
- * You may call this function to determine the specific cause
- * of an error after twi transaction failed.
- *
- */
- int NutTwiMasterError(NUTTWIBUS *bus)
- {
- int rc = bus->bus_icb->tw_mm_error;
- bus->bus_icb->tw_mm_error = 0;
- return rc;
- }
- /*!
- * \brief Listen for incoming data from a master.
- *
- * If this function returns without error, the bus is blocked. The caller
- * must immediately process the request and return a response by calling
- * TwSlaveRespond().
- *
- * \note Slave mode is not implemented in the AT91 driver.
- * Thus the function always returns -1.
- *
- * \param sla Points to a byte variable, which receives the slave
- * address sent by the master. This can be used by the
- * caller to determine whether the the interface has been
- * addressed by a general call or its individual address.
- * \param rxdata Points to a data buffer where the received data bytes
- * are stored.
- * \param rxsiz Specifies the maximum number of data bytes to receive.
- * \param tmo Timeout in milliseconds. To disable timeout,
- * set this parameter to NUT_WAIT_INFINITE.
- *
- * \return The number of bytes received, -1 in case of an error or timeout.
- *
- */
- int NutTwiSlaveListen(NUTTWIBUS *bus, uint8_t *sla, void *rxdata, uint16_t rxsiz, uint32_t tmo)
- {
- return -1;
- }
- /*!
- * \brief Send response to a master.
- *
- * This function must be called as soon as possible after TwSlaveListen()
- * returned successfully, even if no data needs to be returned. Not doing
- * so will completely block the bus.
- *
- * \note Slave mode is not implemented in the AT91 driver.
- * Thus the function always returns -1.
- *
- * \param txdata Points to the data to transmit. Ignored, if the
- * number of bytes to transmit is zero.
- * \param txlen Number of data bytes to transmit.
- * \param tmo Timeout in milliseconds. To disable timeout,
- * set this parameter to NUT_WAIT_INFINITE.
- *
- * \return The number of bytes transmitted, -1 in case of an error or timeout.
- */
- extern int NutTwiSlaveRespond(NUTTWIBUS *bus, void *txdata, uint16_t txlen, uint32_t tmo)
- {
- return -1;
- }
- /*!
- * \brief Get last slave mode error.
- *
- * You may call this function to determine the specific cause
- * of an error after TwSlaveListen() or TwSlaveRespond() failed.
- *
- * \return Error code or 0 if no error occurred.
- *
- * \note Slave mode is not implemented in the AT91 driver.
- * Thus the function always returns TWERR_BUS.
- */
- extern int NutTwiSlaveError(NUTTWIBUS *bus)
- {
- return TWERR_BUS;
- }
- /*!
- * \brief Get last transfer results.
- *
- * \todo Do we really need this. It may not work with competing threads.
- *
- * You may call this function to determine how many bytes where
- * transferred before the twi transaction failed.
- *
- */
- uint16_t NutTwiIndexes( NUTTWIBUS *bus, uint8_t idx )
- {
- NUTTWIICB *icb = bus->bus_icb;
- switch ( idx ) {
- case 0:
- return (uint16_t) icb->tw_mm_error;
- case 1:
- return (uint16_t) icb->tw_mm_len;
- case 2:
- return (uint16_t) icb->tw_mm_len;
- default:
- return 0;
- }
- }
- /*!
- * \brief Set Speed of I2C Interface.
- *
- * Setup Interface Speed
- */
- int NutTwiSetSpeed( NUTTWIBUS *bus, uint32_t speed)
- {
- int rc = -1;
- uint32_t ckdiv = 1;
- uint32_t cldiv;
- if (speed > 400000) {
- /* Speed out of range */
- return rc;
- }
- if (bus==NULL) {
- /* No bus selected */
- return rc;
- }
- /*
- * CLDIV = ((Tlow x 2^CKDIV) -3) x Tmck
- * CHDIV = ((THigh x 2^CKDIV) -3) x Tmck
- * Only CLDIV is computed since CLDIV = CHDIV (50% duty cycle)
- */
- while ((cldiv = ((NutClockGet(NUT_HWCLK_PERIPHERAL) / (2 * speed)) - 3) / (1 << ckdiv)) > 255) {
- ckdiv++;
- }
- /* BUG 41.2.7.1, datasheet SAM7X256 p. 626 */
- if (cldiv * (1 << ckdiv) > 8191) {
- return rc;
- }
- else {
- outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
- rc = 0;
- }
- return 0;
- }
- /*!
- * \brief Request Current Speed of I2C Interface.
- *
- * \return 0..400000 for speed, -1 in case of error.
- */
- uint32_t NutTwiGetSpeed( NUTTWIBUS *bus)
- {
- uint32_t rc;
- uint32_t ckdiv = 1;
- uint32_t cldiv;
- if (bus) {
- cldiv = inr(TWI_CWGR) & 0x000000FF;
- ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
- rc = NutGetCpuClock() / ((cldiv * 2 << ckdiv) - 3);
- }
- else
- rc = -1;
- return rc;
- }
- /*!
- * \brief Perform TWI control functions.
- *
- * \param req Requested control function. May be set to one of the
- * following constants:
- * - TWI_SETSPEED, if conf points to an uint32_t value containing the bitrate.
- * - TWI_GETSPEED, if conf points to an uint32_t value receiving the current bitrate.
- * \param conf Points to a buffer that contains any data required for
- * the given control function or receives data from that
- * function.
- * \return 0 on success, -1 otherwise.
- *
- * \note Timeout is limited to the granularity of the system timer.
- *
- */
- int NutTwiIOCtl( NUTTWIBUS *bus, int req, void *conf )
- {
- int rc = 0;
- NUTTWIICB *icb = bus->bus_icb;
- switch (req) {
- case TWI_SETSPEED:
- rc = NutTwiSetSpeed(bus, *((uint32_t *)conf));
- break;
- case TWI_GETSPEED:
- *((uint32_t *)conf) = NutTwiGetSpeed(bus);
- break;
- case TWI_GETSTATUS:
- rc = 0;
- break;
- case TWI_SETSTATUS:
- rc = 0;
- break;
- case TWI_GETSLAVEADDRESS:
- // TODO: Slave handling
- *(uint32_t*)conf = (uint32_t)icb->tw_mm_sla;
- break;
- case TWI_SETSLAVEADDRESS:
- // TODO: Slave handling
- icb->tw_mm_sla = *((uint16_t*)conf);
- break;
- default:
- rc = -1;
- break;
- }
- return rc;
- }
- /*!
- * \brief Initialize TWI interface hardware.
- */
- int At91TwiInit(void)
- {
- int rc = 0;
- /* Set TWD and TWCK as peripheral line. */
- outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
- /* Let periperal control the PIO lines. */
- outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
- /* Enabled OpenDrain output on both lines. */
- outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
- /* Enable TWI clock in PMC. */
- outr(PMC_PCER, _BV(TWI_ID));
- /* Disable all interrupts. */
- outr(TWI_IDR, 0xFFFFFFFF);
- /* Reset bus. */
- outr(TWI_CR, TWI_SWRST);
- /* Enable master mode. */
- outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
- return rc;
- }
- /*!
- * \brief Initialize TWI interface bus.
- *
- * The specified slave address is not used here as we don't support twi-slave
- * on AT91SAM7X
- *
- * \note This function is only available on AT91SAM7xxxx systems.
- *
- * \param sla Slave address, must be specified as a 7-bit address,
- * always lower than 128.
- */
- int NutRegisterTwiBus( NUTTWIBUS *bus, uint8_t sla )
- {
- int rc = 0;
- uint32_t speed = 100000;
- NUTTWIICB *icb = NULL;
- /* Check if bus was already registered */
- if( bus->bus_icb) {
- return 0;
- }
- /* Allocate ICB for this bus */
- icb = NutHeapAlloc(sizeof(NUTTWIICB));
- if( icb == NULL) {
- return rc;
- }
- memset( icb, 0, sizeof(NUTTWIICB));
- /* Link bus and ICB */
- bus->bus_icb = icb;
- /* Initialize interface hardware */
- if (bus->bus_initbus) {
- rc = bus->bus_initbus();
- }
- #ifdef I2C_DEFAULT_SPEED
- speed = I2C_DEFAULT_SPEED*1000UL;
- #endif
- /* Set initial rate. */
- if( (rc = NutTwiSetSpeed( bus, speed))) {
- return rc;
- }
- /* Register IRQ Handler */
- if( (rc = NutRegisterIrqHandler( bus->bus_sig_ev, TwInterrupt, bus))) {
- return rc;
- }
- /* Enable level triggered interrupts. */
- NutIrqSetMode(bus->bus_sig_ev, NUT_IRQMODE_LEVEL);
- NutIrqEnable(bus->bus_sig_ev);
- /* Initialize mutex semaphores. */
- NutEventPost(&bus->bus_mutex);
- return rc;
- }
- int NutDestroyTwiBus( NUTTWIBUS *bus)
- {
- if (bus->bus_icb) {
- NutIrqDisable(bus->bus_sig_ev);
- NutHeapFree( bus->bus_icb);
- }
- return 0;
- }
- /*!
- * \brief TWI/I2C bus structure.
- */
- NUTTWIBUS At91TwiBus = {
- /*.bus_base = */ TWI_CR, /* Bus base address. */
- /*.bus_sig_ev = */ &sig_TWI, /* Bus data and event interrupt handler. */
- /*.bus_sig_er = */ NULL, /* Bus error interrupt handler. */
- /*.bus_mutex = */ NULL, /* Bus lock queue. */
- /*.bus_icb = */ NULL, /* Bus Runtime Data Pointer */
- /*.bus_dma_tx = */ 0, /* DMA channel for TX direction. */
- /*.bus_dma_rx = */ 0, /* DMA channel for RX direction. */
- /*.bus_initbus =*/ At91TwiInit, /* Initialize bus controller. */
- /*.bus_recover =*/ NULL, /* Recover bus controller */
- };
- /*@}*/
|