331 lines
11 KiB
C
331 lines
11 KiB
C
/* This file has been prepared for Doxygen automatic documentation generation.*/
|
|
/*! \file *********************************************************************
|
|
*
|
|
* \brief
|
|
* XMEGA TWI slave driver source file.
|
|
*
|
|
* This file contains the function implementations the XMEGA TWI slave
|
|
* 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 slave 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: 2660 $
|
|
* $Date: 2009-08-11 12:28:58 +0200 (ti, 11 aug 2009) $ \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_slave_driver.h"
|
|
|
|
|
|
/*! \brief Initalizes TWI slave driver structure.
|
|
*
|
|
* Initialize the instance of the TWI Slave and set the appropriate values.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
* \param module Pointer to the TWI module.
|
|
* \param processDataFunction Pointer to the function that handles incoming data.
|
|
*/
|
|
void TWI_SlaveInitializeDriver(TWI_Slave_t *twi,
|
|
TWI_t *module,
|
|
TWI_SlaveProc processDataFunction)
|
|
{
|
|
twi->interface = module;
|
|
twi->Process_Data = processDataFunction;
|
|
twi->bytesReceived = 0;
|
|
twi->bytesSent = 0;
|
|
twi->status = TWIS_STATUS_READY;
|
|
twi->result = TWIS_RESULT_UNKNOWN;
|
|
twi->abort = false;
|
|
}
|
|
|
|
|
|
/*! \brief Initialize the TWI module.
|
|
*
|
|
* Enables interrupts on address recognition and data available.
|
|
* Remember to enable interrupts globally from the main application.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
* \param address Slave address for this module.
|
|
* \param intLevel Interrupt level for the TWI slave interrupt handler.
|
|
*/
|
|
void TWI_SlaveInitializeModule(TWI_Slave_t *twi,
|
|
uint8_t address,
|
|
TWI_SLAVE_INTLVL_t intLevel,
|
|
uint8_t *recvData,
|
|
uint8_t bytesMaxRecv )
|
|
{
|
|
twi->bytesMaxRecv = bytesMaxRecv;
|
|
twi->recvData = recvData;
|
|
|
|
twi->interface->SLAVE.CTRLA = intLevel |
|
|
TWI_SLAVE_DIEN_bm |
|
|
TWI_SLAVE_APIEN_bm |
|
|
TWI_SLAVE_ENABLE_bm;
|
|
twi->interface->SLAVE.ADDR = (address << 1);
|
|
}
|
|
|
|
|
|
/*! \brief Common TWI slave interrupt service routine.
|
|
*
|
|
* Handles all TWI transactions and responses to address match, data reception,
|
|
* data transmission, bus error and data collision.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
*/
|
|
void TWI_SlaveInterruptHandler(TWI_Slave_t *twi)
|
|
{
|
|
uint8_t const currentStatus = twi->interface->SLAVE.STATUS;
|
|
|
|
/* If bus error. */
|
|
if (currentStatus & TWI_SLAVE_BUSERR_bm) {
|
|
twi->bytesReceived = 0;
|
|
twi->bytesSent = 0;
|
|
twi->result = TWIS_RESULT_BUS_ERROR;
|
|
twi->status = TWIS_STATUS_READY;
|
|
} else
|
|
|
|
/* If transmit collision. */
|
|
if (currentStatus & TWI_SLAVE_COLL_bm) {
|
|
twi->bytesReceived = 0;
|
|
twi->bytesSent = 0;
|
|
twi->result = TWIS_RESULT_TRANSMIT_COLLISION;
|
|
twi->status = TWIS_STATUS_READY;
|
|
} else
|
|
|
|
/* If address match. */
|
|
if ((currentStatus & TWI_SLAVE_APIF_bm) &&
|
|
(currentStatus & TWI_SLAVE_AP_bm)) {
|
|
|
|
TWI_SlaveAddressMatchHandler(twi);
|
|
} else
|
|
|
|
/* If stop (only enabled through slave read transaction). */
|
|
if (currentStatus & TWI_SLAVE_APIF_bm) {
|
|
TWI_SlaveStopHandler(twi);
|
|
} else
|
|
|
|
/* If data interrupt. */
|
|
if (currentStatus & TWI_SLAVE_DIF_bm) {
|
|
TWI_SlaveDataHandler(twi);
|
|
}
|
|
|
|
/* If unexpected state. */
|
|
else {
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_FAIL);
|
|
}
|
|
}
|
|
|
|
/*! \brief TWI address match interrupt handler.
|
|
*
|
|
* Prepares TWI module for transaction when an address match occures.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
*/
|
|
void TWI_SlaveAddressMatchHandler(TWI_Slave_t *twi)
|
|
{
|
|
/* If application signalling need to abort (error occured). */
|
|
if (twi->abort) {
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc;
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_ABORTED);
|
|
twi->abort = false;
|
|
} else {
|
|
twi->status = TWIS_STATUS_BUSY;
|
|
twi->result = TWIS_RESULT_UNKNOWN;
|
|
|
|
/* Disable stop interrupt. */
|
|
uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA;
|
|
twi->interface->SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm;
|
|
|
|
twi->bytesReceived = 0;
|
|
twi->bytesSent = 0;
|
|
|
|
/* Send ACK, wait for data interrupt. */
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc;
|
|
}
|
|
}
|
|
|
|
|
|
/*! \brief TWI stop condition interrupt handler.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
*/
|
|
void TWI_SlaveStopHandler(TWI_Slave_t *twi)
|
|
{
|
|
/* Disable stop interrupt. */
|
|
uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA;
|
|
twi->interface->SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm;
|
|
|
|
/* Clear APIF, according to flowchart don't ACK or NACK */
|
|
uint8_t currentStatus = twi->interface->SLAVE.STATUS;
|
|
twi->interface->SLAVE.STATUS = currentStatus | TWI_SLAVE_APIF_bm;
|
|
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
/*! \brief TWI data interrupt handler.
|
|
*
|
|
* Calls the appropriate slave read or write handler.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
*/
|
|
void TWI_SlaveDataHandler(TWI_Slave_t *twi)
|
|
{
|
|
if( twi->interface->SLAVE.STATUS & TWI_SLAVE_DIR_bm ) {
|
|
TWI_SlaveWriteHandler(twi);
|
|
} else {
|
|
TWI_SlaveReadHandler(twi);
|
|
}
|
|
}
|
|
|
|
|
|
/*! \brief TWI slave read interrupt handler.
|
|
*
|
|
* Handles TWI slave read transactions and responses.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
*/
|
|
void TWI_SlaveReadHandler(TWI_Slave_t *twi)
|
|
{
|
|
uint8_t const bytesMaxRecv = twi->bytesMaxRecv;
|
|
|
|
/* Enable stop interrupt. */
|
|
uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA;
|
|
twi->interface->SLAVE.CTRLA = currentCtrlA | TWI_SLAVE_PIEN_bm;
|
|
|
|
/* If free space in buffer. */
|
|
if( twi->bytesReceived < bytesMaxRecv ) {
|
|
/* Fetch data */
|
|
uint8_t data = twi->interface->SLAVE.DATA;
|
|
twi->recvData[twi->bytesReceived] = data;
|
|
|
|
/* Process data. */
|
|
twi->Process_Data(twi);
|
|
|
|
twi->bytesReceived++;
|
|
|
|
/* If application signalling need to abort (error occured),
|
|
* complete transaction and wait for next START. Otherwise
|
|
* send ACK and wait for data interrupt.
|
|
*/
|
|
if( twi->abort ) {
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc;
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_ABORTED);
|
|
twi->abort = false;
|
|
}
|
|
else {
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc;
|
|
}
|
|
}
|
|
/* If buffer overflow, send NACK and wait for next START. Set
|
|
* result buffer overflow.
|
|
*/
|
|
else {
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_ACKACT_bm |
|
|
TWI_SLAVE_CMD_COMPTRANS_gc;
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_BUFFER_OVERFLOW);
|
|
}
|
|
}
|
|
|
|
|
|
/*! \brief TWI slave write interrupt handler.
|
|
*
|
|
* Handles TWI slave write transactions and responses.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
*/
|
|
void TWI_SlaveWriteHandler(TWI_Slave_t *twi)
|
|
{
|
|
uint8_t const bytesToSend = twi->bytesToSend;
|
|
/* If NACK, slave write transaction finished. */
|
|
if ((twi->bytesSent > 0) && (twi->interface->SLAVE.STATUS &
|
|
TWI_SLAVE_RXACK_bm)) {
|
|
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc;
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_OK);
|
|
}
|
|
/* If ACK, master expects more data. */
|
|
else {
|
|
if( twi->bytesSent < bytesToSend ) {
|
|
uint8_t data = twi->sendData[twi->bytesSent];
|
|
twi->interface->SLAVE.DATA = data;
|
|
twi->bytesSent++;
|
|
|
|
/* Send data, wait for data interrupt. */
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc;
|
|
}
|
|
/* If buffer overflow. */
|
|
else {
|
|
twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc;
|
|
TWI_SlaveTransactionFinished(twi, TWIS_RESULT_BUFFER_OVERFLOW);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*! \brief TWI transaction finished function.
|
|
*
|
|
* Prepares module for new transaction.
|
|
*
|
|
* \param twi The TWI_Slave_t struct instance.
|
|
* \param result The result of the transaction.
|
|
*/
|
|
void TWI_SlaveTransactionFinished(TWI_Slave_t *twi, uint8_t result)
|
|
{
|
|
twi->result = result;
|
|
twi->status = TWIS_STATUS_READY;
|
|
}
|