You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					288 lines
				
				7.6 KiB
			
		
		
			
		
	
	
					288 lines
				
				7.6 KiB
			| 
								 
											8 years ago
										 
									 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * TWIlib.c
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *  Created: 6/01/2014 10:41:33 PM
							 | 
						||
| 
								 | 
							
								 *  Author: Chris Herring
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <avr/io.h>
							 | 
						||
| 
								 | 
							
								#include <avr/interrupt.h>
							 | 
						||
| 
								 | 
							
								#include "TWIlib.h"
							 | 
						||
| 
								 | 
							
								#include "util/delay.h"
							 | 
						||
| 
								 | 
							
								#include "print.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void TWIInit()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									TWIInfo.mode = Ready;
							 | 
						||
| 
								 | 
							
									TWIInfo.errorCode = 0xFF;
							 | 
						||
| 
								 | 
							
									TWIInfo.repStart = 0;
							 | 
						||
| 
								 | 
							
									// Set pre-scalers (no pre-scaling)
							 | 
						||
| 
								 | 
							
									TWSR = 0;
							 | 
						||
| 
								 | 
							
									// Set bit rate
							 | 
						||
| 
								 | 
							
									TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
							 | 
						||
| 
								 | 
							
									// Enable TWI and interrupt
							 | 
						||
| 
								 | 
							
									TWCR = (1 << TWIE) | (1 << TWEN);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint8_t isTWIReady()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if ( (TWIInfo.mode == Ready) | (TWIInfo.mode == RepeatedStartSent) )
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//        xprintf("i2c ready\n");
							 | 
						||
| 
								 | 
							
										return 1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if(TWIInfo.mode == Initializing){
							 | 
						||
| 
								 | 
							
											switch(TWIInfo.errorCode){
							 | 
						||
| 
								 | 
							
										        case TWI_SUCCESS:
							 | 
						||
| 
								 | 
							
										            break;
							 | 
						||
| 
								 | 
							
										        case TWI_NO_RELEVANT_INFO:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										        	break;
							 | 
						||
| 
								 | 
							
												case TWI_LOST_ARBIT:
							 | 
						||
| 
								 | 
							
												case TWI_MT_DATA_NACK:
							 | 
						||
| 
								 | 
							
													// Some kind of I2C error, reset and re-init
							 | 
						||
| 
								 | 
							
										        	xprintf("I2C init error: %d\n", TWIInfo.errorCode);
							 | 
						||
| 
								 | 
							
											        TWCR = (1 << TWINT)|(1 << TWSTO);
							 | 
						||
| 
								 | 
							
										        	TWIInit();
							 | 
						||
| 
								 | 
							
										        	break;
							 | 
						||
| 
								 | 
							
										        default:
							 | 
						||
| 
								 | 
							
										        	xprintf("Other i2c init error: %d\n", TWIInfo.errorCode);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart, uint8_t blocking)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									// Wait until ready
							 | 
						||
| 
								 | 
							
									while (!isTWIReady()) {_delay_us(1);}
							 | 
						||
| 
								 | 
							
									// Reset the I2C stuff
							 | 
						||
| 
								 | 
							
									TWCR = (1 << TWINT)|(1 << TWSTO);
							 | 
						||
| 
								 | 
							
									TWIInit();
							 | 
						||
| 
								 | 
							
									// Set repeated start mode
							 | 
						||
| 
								 | 
							
									TWIInfo.repStart = repStart;
							 | 
						||
| 
								 | 
							
									// Copy transmit info to global variables
							 | 
						||
| 
								 | 
							
									TWITransmitBuffer = (uint8_t *)TXdata;
							 | 
						||
| 
								 | 
							
									TXBuffLen = dataLen;
							 | 
						||
| 
								 | 
							
									TXBuffIndex = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// If a repeated start has been sent, then devices are already listening for an address
							 | 
						||
| 
								 | 
							
									// and another start does not need to be sent.
							 | 
						||
| 
								 | 
							
									if (TWIInfo.mode == RepeatedStartSent)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										TWIInfo.mode = Initializing;
							 | 
						||
| 
								 | 
							
										TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
							 | 
						||
| 
								 | 
							
										TWISendTransmit(); // Send the data
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else // Otherwise, just send the normal start signal to begin transmission.
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										TWIInfo.mode = Initializing;
							 | 
						||
| 
								 | 
							
										TWISendStart();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if(blocking){
							 | 
						||
| 
								 | 
							
										// Wait until ready
							 | 
						||
| 
								 | 
							
										while (!isTWIReady()){_delay_us(1);}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart)
							 | 
						||
| 
								 | 
							
								// {
							 | 
						||
| 
								 | 
							
								// 	if (dataLen <= TXMAXBUFLEN)
							 | 
						||
| 
								 | 
							
								// 	{
							 | 
						||
| 
								 | 
							
								// 		// Wait until ready
							 | 
						||
| 
								 | 
							
								// 		while (!isTWIReady()) {_delay_us(1);}
							 | 
						||
| 
								 | 
							
								// 		// Set repeated start mode
							 | 
						||
| 
								 | 
							
								// 		TWIInfo.repStart = repStart;
							 | 
						||
| 
								 | 
							
								// 		// Copy data into the transmit buffer
							 | 
						||
| 
								 | 
							
								// 		uint8_t *data = (uint8_t *)TXdata;
							 | 
						||
| 
								 | 
							
								// 		for (int i = 0; i < dataLen; i++)
							 | 
						||
| 
								 | 
							
								// 		{
							 | 
						||
| 
								 | 
							
								// 			TWITransmitBuffer[i] = data[i];
							 | 
						||
| 
								 | 
							
								// 		}
							 | 
						||
| 
								 | 
							
								// 		// Copy transmit info to global variables
							 | 
						||
| 
								 | 
							
								// 		TXBuffLen = dataLen;
							 | 
						||
| 
								 | 
							
								// 		TXBuffIndex = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 		// If a repeated start has been sent, then devices are already listening for an address
							 | 
						||
| 
								 | 
							
								// 		// and another start does not need to be sent.
							 | 
						||
| 
								 | 
							
								// 		if (TWIInfo.mode == RepeatedStartSent)
							 | 
						||
| 
								 | 
							
								// 		{
							 | 
						||
| 
								 | 
							
								// 			TWIInfo.mode = Initializing;
							 | 
						||
| 
								 | 
							
								// 			TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
							 | 
						||
| 
								 | 
							
								// 			TWISendTransmit(); // Send the data
							 | 
						||
| 
								 | 
							
								// 		}
							 | 
						||
| 
								 | 
							
								// 		else // Otherwise, just send the normal start signal to begin transmission.
							 | 
						||
| 
								 | 
							
								// 		{
							 | 
						||
| 
								 | 
							
								// 			TWIInfo.mode = Initializing;
							 | 
						||
| 
								 | 
							
								// 			TWISendStart();
							 | 
						||
| 
								 | 
							
								// 		}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 	}
							 | 
						||
| 
								 | 
							
								// 	else
							 | 
						||
| 
								 | 
							
								// 	{
							 | 
						||
| 
								 | 
							
								// 		return 1; // return an error if data length is longer than buffer
							 | 
						||
| 
								 | 
							
								// 	}
							 | 
						||
| 
								 | 
							
								// 	return 0;
							 | 
						||
| 
								 | 
							
								// }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									// Check if number of bytes to read can fit in the RXbuffer
							 | 
						||
| 
								 | 
							
									if (bytesToRead < RXMAXBUFLEN)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										// Reset buffer index and set RXBuffLen to the number of bytes to read
							 | 
						||
| 
								 | 
							
										RXBuffIndex = 0;
							 | 
						||
| 
								 | 
							
										RXBuffLen = bytesToRead;
							 | 
						||
| 
								 | 
							
										// Create the one value array for the address to be transmitted
							 | 
						||
| 
								 | 
							
										uint8_t TXdata[1];
							 | 
						||
| 
								 | 
							
										// Shift the address and AND a 1 into the read write bit (set to write mode)
							 | 
						||
| 
								 | 
							
										TXdata[0] = (TWIaddr << 1) | 0x01;
							 | 
						||
| 
								 | 
							
										// Use the TWITransmitData function to initialize the transfer and address the slave
							 | 
						||
| 
								 | 
							
										TWITransmitData(TXdata, 1, repStart, 0);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ISR (TWI_vect)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									switch (TWI_STATUS)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										// ----\/ ---- MASTER TRANSMITTER OR WRITING ADDRESS ----\/ ----  //
							 | 
						||
| 
								 | 
							
										case TWI_MT_SLAW_ACK: // SLA+W transmitted and ACK received
							 | 
						||
| 
								 | 
							
										// Set mode to Master Transmitter
							 | 
						||
| 
								 | 
							
										TWIInfo.mode = MasterTransmitter;
							 | 
						||
| 
								 | 
							
										case TWI_START_SENT: // Start condition has been transmitted
							 | 
						||
| 
								 | 
							
										case TWI_MT_DATA_ACK: // Data byte has been transmitted, ACK received
							 | 
						||
| 
								 | 
							
											if (TXBuffIndex < TXBuffLen) // If there is more data to send
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
							 | 
						||
| 
								 | 
							
												TWISendTransmit(); // Send the data
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// This transmission is complete however do not release bus yet
							 | 
						||
| 
								 | 
							
											else if (TWIInfo.repStart)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = 0xFF;
							 | 
						||
| 
								 | 
							
												TWISendStart();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// All transmissions are complete, exit
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.mode = Ready;
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = 0xFF;
							 | 
						||
| 
								 | 
							
												TWISendStop();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ----\/ ---- MASTER RECEIVER ----\/ ----  //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case TWI_MR_SLAR_ACK: // SLA+R has been transmitted, ACK has been received
							 | 
						||
| 
								 | 
							
											// Switch to Master Receiver mode
							 | 
						||
| 
								 | 
							
											TWIInfo.mode = MasterReceiver;
							 | 
						||
| 
								 | 
							
											// If there is more than one byte to be read, receive data byte and return an ACK
							 | 
						||
| 
								 | 
							
											if (RXBuffIndex < RXBuffLen-1)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
							 | 
						||
| 
								 | 
							
												TWISendACK();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// Otherwise when a data byte (the only data byte) is received, return NACK
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
							 | 
						||
| 
								 | 
							
												TWISendNACK();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case TWI_MR_DATA_ACK: // Data has been received, ACK has been transmitted.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											/// -- HANDLE DATA BYTE --- ///
							 | 
						||
| 
								 | 
							
											TWIReceiveBuffer[RXBuffIndex++] = TWDR;
							 | 
						||
| 
								 | 
							
											// If there is more than one byte to be read, receive data byte and return an ACK
							 | 
						||
| 
								 | 
							
											if (RXBuffIndex < RXBuffLen-1)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
							 | 
						||
| 
								 | 
							
												TWISendACK();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// Otherwise when a data byte (the only data byte) is received, return NACK
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
							 | 
						||
| 
								 | 
							
												TWISendNACK();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case TWI_MR_DATA_NACK: // Data byte has been received, NACK has been transmitted. End of transmission.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											/// -- HANDLE DATA BYTE --- ///
							 | 
						||
| 
								 | 
							
											TWIReceiveBuffer[RXBuffIndex++] = TWDR;
							 | 
						||
| 
								 | 
							
											// This transmission is complete however do not release bus yet
							 | 
						||
| 
								 | 
							
											if (TWIInfo.repStart)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = 0xFF;
							 | 
						||
| 
								 | 
							
												TWISendStart();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// All transmissions are complete, exit
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.mode = Ready;
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = 0xFF;
							 | 
						||
| 
								 | 
							
												TWISendStop();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ----\/ ---- MT and MR common ----\/ ---- //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case TWI_MR_SLAR_NACK: // SLA+R transmitted, NACK received
							 | 
						||
| 
								 | 
							
										case TWI_MT_SLAW_NACK: // SLA+W transmitted, NACK received
							 | 
						||
| 
								 | 
							
										case TWI_MT_DATA_NACK: // Data byte has been transmitted, NACK received
							 | 
						||
| 
								 | 
							
										case TWI_LOST_ARBIT: // Arbitration has been lost
							 | 
						||
| 
								 | 
							
											// Return error and send stop and set mode to ready
							 | 
						||
| 
								 | 
							
											if (TWIInfo.repStart)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_STATUS;
							 | 
						||
| 
								 | 
							
												TWISendStart();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// All transmissions are complete, exit
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												TWIInfo.mode = Ready;
							 | 
						||
| 
								 | 
							
												TWIInfo.errorCode = TWI_STATUS;
							 | 
						||
| 
								 | 
							
												TWISendStop();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case TWI_REP_START_SENT: // Repeated start has been transmitted
							 | 
						||
| 
								 | 
							
											// Set the mode but DO NOT clear TWINT as the next data is not yet ready
							 | 
						||
| 
								 | 
							
											TWIInfo.mode = RepeatedStartSent;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ----\/ ---- SLAVE RECEIVER ----\/ ----  //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// TODO  IMPLEMENT SLAVE RECEIVER FUNCTIONALITY
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ----\/ ---- SLAVE TRANSMITTER ----\/ ----  //
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// TODO  IMPLEMENT SLAVE TRANSMITTER FUNCTIONALITY
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// ----\/ ---- MISCELLANEOUS STATES ----\/ ----  //
							 | 
						||
| 
								 | 
							
										case TWI_NO_RELEVANT_INFO: // It is not really possible to get into this ISR on this condition
							 | 
						||
| 
								 | 
							
																   // Rather, it is there to be manually set between operations
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case TWI_ILLEGAL_START_STOP: // Illegal START/STOP, abort and return error
							 | 
						||
| 
								 | 
							
											TWIInfo.errorCode = TWI_ILLEGAL_START_STOP;
							 | 
						||
| 
								 | 
							
											TWIInfo.mode = Ready;
							 | 
						||
| 
								 | 
							
											TWISendStop();
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 |