summaryrefslogtreecommitdiff
path: root/twi_master_driver.c
diff options
context:
space:
mode:
authorWolfgang Draxinger <Wolfgang.Draxinger@draxit.de>2013-12-22 16:44:10 +0100
committerWolfgang Draxinger <Wolfgang.Draxinger@draxit.de>2013-12-22 16:44:10 +0100
commit217ddb1e32dcb4cde11ecca88418be428895f2dc (patch)
tree8e84c0cecc506f9da54f87d82af95f59d348b3de /twi_master_driver.c
parent3e8ce25f77700dcef050601412435950dc7dfa7b (diff)
downloadvgaedidinjector-217ddb1e32dcb4cde11ecca88418be428895f2dc.tar.gz
vgaedidinjector-217ddb1e32dcb4cde11ecca88418be428895f2dc.tar.bz2
Makefile separator errors fixed
Diffstat (limited to 'twi_master_driver.c')
-rw-r--r--twi_master_driver.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/twi_master_driver.c b/twi_master_driver.c
new file mode 100644
index 0000000..c7f9695
--- /dev/null
+++ b/twi_master_driver.c
@@ -0,0 +1,399 @@
+/* This file has been prepared for Doxygen automatic documentation generation.*/
+/*! \file *********************************************************************
+ *
+ * \brief
+ * XMEGA TWI master driver source file.
+ *
+ * This file contains the function implementations the XMEGA master TWI
+ * driver.
+ *
+ * The driver is not intended for size and/or speed critical code, since
+ * most functions are just a few lines of code, and the function call
+ * overhead would decrease code performance. The driver is intended for
+ * rapid prototyping and documentation purposes for getting started with
+ * the XMEGA TWI master module.
+ *
+ * For size and/or speed critical code, it is recommended to copy the
+ * function contents directly into your application instead of making
+ * a function call.
+ *
+ * Several functions use the following construct:
+ * "some_register = ... | (some_parameter ? SOME_BIT_bm : 0) | ..."
+ * Although the use of the ternary operator ( if ? then : else ) is
+ * discouraged, in some occasions the operator makes it possible to write
+ * pretty clean and neat code. In this driver, the construct is used to
+ * set or not set a configuration bit based on a boolean input parameter,
+ * such as the "some_parameter" in the example above.
+ *
+ * \par Application note:
+ * AVR1308: Using the XMEGA TWI
+ *
+ * \par Documentation
+ * For comprehensive code documentation, supported compilers, compiler
+ * settings and supported devices see readme.html
+ *
+ * \author
+ * Atmel Corporation: http://www.atmel.com \n
+ * Support email: avr@atmel.com
+ *
+ * $Revision: 1569 $
+ * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $ \n
+ *
+ * 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:
+ *
+ * 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. The name of ATMEL may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "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 EXPRESSLY AND
+ * SPECIFICALLY 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.
+ *****************************************************************************/
+
+#include "twi_master_driver.h"
+
+
+/*! \brief Initialize the TWI module.
+ *
+ * TWI module initialization function.
+ * Enables master read and write interrupts.
+ * Remember to enable interrupts globally from the main application.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ * \param module The TWI module to use.
+ * \param intLevel Master interrupt level.
+ * \param baudRateRegisterSetting The baud rate register value.
+ */
+void TWI_MasterInit(TWI_Master_t *twi,
+ TWI_t *module,
+ TWI_MASTER_INTLVL_t intLevel,
+ uint8_t baudRateRegisterSetting)
+{
+ twi->interface = module;
+ twi->interface->MASTER.CTRLA = intLevel |
+ TWI_MASTER_RIEN_bm |
+ TWI_MASTER_WIEN_bm |
+ TWI_MASTER_ENABLE_bm;
+ twi->interface->MASTER.BAUD = baudRateRegisterSetting;
+ twi->interface->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
+}
+
+
+/*! \brief Returns the TWI bus state.
+ *
+ * Returns the TWI bus state (type defined in device headerfile),
+ * unknown, idle, owner or busy.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ *
+ * \retval TWI_MASTER_BUSSTATE_UNKNOWN_gc Bus state is unknown.
+ * \retval TWI_MASTER_BUSSTATE_IDLE_gc Bus state is idle.
+ * \retval TWI_MASTER_BUSSTATE_OWNER_gc Bus state is owned by the master.
+ * \retval TWI_MASTER_BUSSTATE_BUSY_gc Bus state is busy.
+ */
+TWI_MASTER_BUSSTATE_t TWI_MasterState(TWI_Master_t *twi)
+{
+ TWI_MASTER_BUSSTATE_t twi_status;
+ twi_status = (TWI_MASTER_BUSSTATE_t) (twi->interface->MASTER.STATUS &
+ TWI_MASTER_BUSSTATE_gm);
+ return twi_status;
+}
+
+
+/*! \brief Returns true if transaction is ready.
+ *
+ * This function returns a boolean whether the TWI Master is ready
+ * for a new transaction.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ *
+ * \retval true If transaction could be started.
+ * \retval false If transaction could not be started.
+ */
+bool TWI_MasterReady(TWI_Master_t *twi)
+{
+ bool twi_status = (twi->status & TWIM_STATUS_READY);
+ return twi_status;
+}
+
+
+/*! \brief TWI write transaction.
+ *
+ * This function is TWI Master wrapper for a write-only transaction.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ * \param address Slave address.
+ * \param writeData Pointer to data to write.
+ * \param bytesToWrite Number of data bytes to write.
+ *
+ * \retval true If transaction could be started.
+ * \retval false If transaction could not be started.
+ */
+bool TWI_MasterWrite(TWI_Master_t *twi,
+ uint8_t address,
+ uint8_t *writeData,
+ uint8_t bytesToWrite)
+{
+ bool twi_status = TWI_MasterWriteRead(twi, address, writeData, bytesToWrite, 0);
+ return twi_status;
+}
+
+
+/*! \brief TWI read transaction.
+ *
+ * This function is a TWI Maste wrapper for read-only transaction.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ * \param address The slave address.
+ * \param bytesToRead The number of bytes to read.
+ *
+ * \retval true If transaction could be started.
+ * \retval false If transaction could not be started.
+ */
+bool TWI_MasterRead(TWI_Master_t *twi,
+ uint8_t address,
+ uint8_t bytesToRead)
+{
+ bool twi_status = TWI_MasterWriteRead(twi, address, 0, 0, bytesToRead);
+ return twi_status;
+}
+
+
+/*! \brief TWI write and/or read transaction.
+ *
+ * This function is a TWI Master write and/or read transaction. The function
+ * can be used to both write and/or read bytes to/from the TWI Slave in one
+ * transaction.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ * \param address The slave address.
+ * \param writeData Pointer to data to write.
+ * \param bytesToWrite Number of bytes to write.
+ * \param bytesToRead Number of bytes to read.
+ *
+ * \retval true If transaction could be started.
+ * \retval false If transaction could not be started.
+ */
+bool TWI_MasterWriteRead(TWI_Master_t *twi,
+ uint8_t address,
+ uint8_t *writeData,
+ uint8_t bytesToWrite,
+ uint8_t bytesToRead)
+{
+ /*Parameter sanity check. */
+ if (bytesToWrite > TWIM_WRITE_BUFFER_SIZE) {
+ return false;
+ }
+ if (bytesToRead > TWIM_READ_BUFFER_SIZE) {
+ return false;
+ }
+
+ /*Initiate transaction if bus is ready. */
+ if (twi->status == TWIM_STATUS_READY) {
+
+ twi->status = TWIM_STATUS_BUSY;
+ twi->result = TWIM_RESULT_UNKNOWN;
+
+ twi->address = address<<1;
+
+ /* Fill write data buffer. */
+ for (uint8_t bufferIndex=0; bufferIndex < bytesToWrite; bufferIndex++) {
+ twi->writeData[bufferIndex] = writeData[bufferIndex];
+ }
+
+ twi->bytesToWrite = bytesToWrite;
+ twi->bytesToRead = bytesToRead;
+ twi->bytesWritten = 0;
+ twi->bytesRead = 0;
+
+ /* If write command, send the START condition + Address +
+ * 'R/_W = 0'
+ */
+ if (twi->bytesToWrite > 0) {
+ uint8_t writeAddress = twi->address & ~0x01;
+ twi->interface->MASTER.ADDR = writeAddress;
+ }
+
+ /* If read command, send the START condition + Address +
+ * 'R/_W = 1'
+ */
+ else if (twi->bytesToRead > 0) {
+ uint8_t readAddress = twi->address | 0x01;
+ twi->interface->MASTER.ADDR = readAddress;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/*! \brief Common TWI master interrupt service routine.
+ *
+ * Check current status and calls the appropriate handler.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ */
+void TWI_MasterInterruptHandler(TWI_Master_t *twi)
+{
+ uint8_t currentStatus = twi->interface->MASTER.STATUS;
+
+ /* If arbitration lost or bus error. */
+ if ((currentStatus & TWI_MASTER_ARBLOST_bm) ||
+ (currentStatus & TWI_MASTER_BUSERR_bm)) {
+
+ TWI_MasterArbitrationLostBusErrorHandler(twi);
+ }
+
+ /* If master write interrupt. */
+ else if (currentStatus & TWI_MASTER_WIF_bm) {
+ TWI_MasterWriteHandler(twi);
+ }
+
+ /* If master read interrupt. */
+ else if (currentStatus & TWI_MASTER_RIF_bm) {
+ TWI_MasterReadHandler(twi);
+ }
+
+ /* If unexpected state. */
+ else {
+ TWI_MasterTransactionFinished(twi, TWIM_RESULT_FAIL);
+ }
+}
+
+
+/*! \brief TWI master arbitration lost and bus error interrupt handler.
+ *
+ * Handles TWI responses to lost arbitration and bus error.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ */
+void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi)
+{
+ uint8_t currentStatus = twi->interface->MASTER.STATUS;
+
+ /* If bus error. */
+ if (currentStatus & TWI_MASTER_BUSERR_bm) {
+ twi->result = TWIM_RESULT_BUS_ERROR;
+ }
+ /* If arbitration lost. */
+ else {
+ twi->result = TWIM_RESULT_ARBITRATION_LOST;
+ }
+
+ /* Clear interrupt flag. */
+ twi->interface->MASTER.STATUS = currentStatus | TWI_MASTER_ARBLOST_bm;
+
+ twi->status = TWIM_STATUS_READY;
+}
+
+
+/*! \brief TWI master write interrupt handler.
+ *
+ * Handles TWI transactions (master write) and responses to (N)ACK.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ */
+void TWI_MasterWriteHandler(TWI_Master_t *twi)
+{
+ /* Local variables used in if tests to avoid compiler warning. */
+ uint8_t bytesToWrite = twi->bytesToWrite;
+ uint8_t bytesToRead = twi->bytesToRead;
+
+ /* If NOT acknowledged (NACK) by slave cancel the transaction. */
+ if (twi->interface->MASTER.STATUS & TWI_MASTER_RXACK_bm) {
+ twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
+ twi->result = TWIM_RESULT_NACK_RECEIVED;
+ twi->status = TWIM_STATUS_READY;
+ }
+
+ /* If more bytes to write, send data. */
+ else if (twi->bytesWritten < bytesToWrite) {
+ uint8_t data = twi->writeData[twi->bytesWritten];
+ twi->interface->MASTER.DATA = data;
+ ++twi->bytesWritten;
+ }
+
+ /* If bytes to read, send repeated START condition + Address +
+ * 'R/_W = 1'
+ */
+ else if (twi->bytesRead < bytesToRead) {
+ uint8_t readAddress = twi->address | 0x01;
+ twi->interface->MASTER.ADDR = readAddress;
+ }
+
+ /* If transaction finished, send STOP condition and set RESULT OK. */
+ else {
+ twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
+ TWI_MasterTransactionFinished(twi, TWIM_RESULT_OK);
+ }
+}
+
+
+/*! \brief TWI master read interrupt handler.
+ *
+ * This is the master read interrupt handler that takes care of
+ * reading bytes from the TWI slave.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ */
+void TWI_MasterReadHandler(TWI_Master_t *twi)
+{
+ /* Fetch data if bytes to be read. */
+ if (twi->bytesRead < TWIM_READ_BUFFER_SIZE) {
+ uint8_t data = twi->interface->MASTER.DATA;
+ twi->readData[twi->bytesRead] = data;
+ twi->bytesRead++;
+ }
+
+ /* If buffer overflow, issue STOP and BUFFER_OVERFLOW condition. */
+ else {
+ twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
+ TWI_MasterTransactionFinished(twi, TWIM_RESULT_BUFFER_OVERFLOW);
+ }
+
+ /* Local variable used in if test to avoid compiler warning. */
+ uint8_t bytesToRead = twi->bytesToRead;
+
+ /* If more bytes to read, issue ACK and start a byte read. */
+ if (twi->bytesRead < bytesToRead) {
+ twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
+ }
+
+ /* If transaction finished, issue NACK and STOP condition. */
+ else {
+ twi->interface->MASTER.CTRLC = TWI_MASTER_ACKACT_bm |
+ TWI_MASTER_CMD_STOP_gc;
+ TWI_MasterTransactionFinished(twi, TWIM_RESULT_OK);
+ }
+}
+
+
+/*! \brief TWI transaction finished handler.
+ *
+ * Prepares module for new transaction.
+ *
+ * \param twi The TWI_Master_t struct instance.
+ * \param result The result of the operation.
+ */
+void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result)
+{
+ twi->result = result;
+ twi->status = TWIM_STATUS_READY;
+}