aboutsummaryrefslogtreecommitdiffstats
path: root/keyboards/meira/TWIlib.c
blob: 4091429b4efedb12d7c41ccdfaf1e9c9afdd5fb0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/*
 * 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"

// Global transmit buffer
volatile uint8_t *TWITransmitBuffer;
// Global receive buffer
volatile uint8_t TWIReceiveBuffer[RXMAXBUFLEN];
// Buffer indexes
volatile int TXBuffIndex; // Index of the transmit buffer. Is volatile, can change at any time.
int RXBuffIndex; // Current index in the receive buffer
// Buffer lengths
int TXBuffLen; // The total length of the transmit buffer
int RXBuffLen; // The total number of bytes to read (should be less than RXMAXBUFFLEN)

TWIInfoStruct TWIInfo;

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;
	}

}