Project

General

Profile

Revision 626

Added by Kevin Woo almost 15 years ago

Created the i2cplugnplay project and copied important files over. Will
flesh out the API and figure out everything later.

View differences:

branches/charge_station_isp/code/projects/i2c_plugnplay/i2c.h
1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

  
26

  
27
/** @file i2c.h
28
 *  @brief Header file for I2C
29
 *
30
 *  Contains functions for I2C.
31
 *
32
 *  @author Kevin Woo and Suresh Nidhiry, Colony Project, CMU Robotics Club
33
 **/
34

  
35

  
36
#ifndef _I2C_H_
37
#define _I2C_H_
38

  
39
#include <stddef.h>
40

  
41
/** @brief Address of slave receive handler function **/
42
typedef void (*fun_srecv_t)(char);
43

  
44
/** @brief Address of master receive handler function**/
45
typedef int (*fun_mrecv_t)(char);
46

  
47
/** @brief Address of slave send handler function**/
48
typedef char (*fun_send_t)(void);
49

  
50
int i2c_init(char addr, fun_mrecv_t master_recv, fun_srecv_t slave_recv, fun_send_t slave_send);
51
int i2c_send(char dest, char* data, size_t bytes);
52
int i2c_request(char dest);
53

  
54
void i2c_packet_rec (char i2c_byte);
55
void i2c_packet_sniff(char data);
56
#endif
57

  
branches/charge_station_isp/code/projects/i2c_plugnplay/main.c
1
#include <dragonfly_lib.h>
2

  
3
int main(void) {
4
	dragonfly_init(ALL_ON);
5
	return 0;
6
}
branches/charge_station_isp/code/projects/i2c_plugnplay/Makefile
1
# Hey Emacs, this is a -*- makefile -*-
2
#----------------------------------------------------------------------------
3
# WinAVR Makefile Template written by Eric B. Weddington, J?rg Wunsch, et al.
4
#
5
# Released to the Public Domain
6
#
7
# Additional material for this makefile was written by:
8
# Peter Fleury
9
# Tim Henigan
10
# Colin O'Flynn
11
# Reiner Patommel
12
# Markus Pfaff
13
# Sander Pool
14
# Frederik Rouleau
15
#
16
#----------------------------------------------------------------------------
17
# On command line:
18
#
19
# make all = Make software.
20
#
21
# make clean = Clean out built project files.
22
#
23
# make coff = Convert ELF to AVR COFF.
24
#
25
# make extcoff = Convert ELF to AVR Extended COFF.
26
#
27
# make program = Download the hex file to the device, using avrdude.
28
#                Please customize the avrdude settings below first!
29
#
30
# make debug = Start either simulavr or avarice as specified for debugging, 
31
#              with avr-gdb or avr-insight as the front end for debugging.
32
#
33
# make filename.s = Just compile filename.c into the assembler code only.
34
#
35
# make filename.i = Create a preprocessed source file for use in submitting
36
#                   bug reports to the GCC project.
37
#
38
# To rebuild project do "make clean" then "make all".
39
#----------------------------------------------------------------------------
40

  
41

  
42
# MCU name
43
MCU = atmega164p
44

  
45

  
46
# Processor frequency.
47
#     This will define a symbol, F_CPU, in all source code files equal to the 
48
#     processor frequency. You can then use this symbol in your source code to 
49
#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done
50
#     automatically to create a 32-bit value in your source code.
51
F_CPU = 5000000
52

  
53

  
54
# Output format. (can be srec, ihex, binary)
55
FORMAT = ihex
56

  
57

  
58
# Target file name (without extension).
59
TARGET = timerBlink
60

  
61

  
62
# List C source files here. (C dependencies are automatically generated.)
63
SRC = $(TARGET).c
64

  
65

  
66
# List Assembler source files here.
67
#     Make them always end in a capital .S.  Files ending in a lowercase .s
68
#     will not be considered source files but generated files (assembler
69
#     output from the compiler), and will be deleted upon "make clean"!
70
#     Even though the DOS/Win* filesystem matches both .s and .S the same,
71
#     it will preserve the spelling of the filenames, and gcc itself does
72
#     care about how the name is spelled on its command-line.
73
ASRC = 
74

  
75

  
76
# Optimization level, can be [0, 1, 2, 3, s]. 
77
#     0 = turn off optimization. s = optimize for size.
78
#     (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
79
OPT = s
80

  
81

  
82
# Debugging format.
83
#     Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
84
#     AVR Studio 4.10 requires dwarf-2.
85
#     AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
86
DEBUG = dwarf-2
87

  
88

  
89
# List any extra directories to look for include files here.
90
#     Each directory must be seperated by a space.
91
#     Use forward slashes for directory separators.
92
#     For a directory that has spaces, enclose it in quotes.
93
#EXTRAINCDIRS = C:\WinAVR\include\fwr
94

  
95

  
96
# Compiler flag to set the C Standard level.
97
#     c89   = "ANSI" C
98
#     gnu89 = c89 plus GCC extensions
99
#     c99   = ISO C99 standard (not yet fully implemented)
100
#     gnu99 = c99 plus GCC extensions
101
CSTANDARD = -std=gnu99
102

  
103

  
104
# Place -D or -U options here
105
CDEFS = -DF_CPU=$(F_CPU)UL
106

  
107

  
108
# Place -I options here
109
CINCS =
110

  
111

  
112

  
113
#---------------- Compiler Options ----------------
114
#  -g*:          generate debugging information
115
#  -O*:          optimization level
116
#  -f...:        tuning, see GCC manual and avr-libc documentation
117
#  -Wall...:     warning level
118
#  -Wa,...:      tell GCC to pass this to the assembler.
119
#    -adhlns...: create assembler listing
120
CFLAGS = -g$(DEBUG)
121
CFLAGS += $(CDEFS) $(CINCS)
122
CFLAGS += -O$(OPT)
123
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
124
CFLAGS += -Wall -Wstrict-prototypes
125
CFLAGS += -Wa,-adhlns=$(<:.c=.lst)
126
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
127
CFLAGS += $(CSTANDARD)
128

  
129

  
130
#---------------- Assembler Options ----------------
131
#  -Wa,...:   tell GCC to pass this to the assembler.
132
#  -ahlms:    create listing
133
#  -gstabs:   have the assembler create line number information; note that
134
#             for use in COFF files, additional information about filenames
135
#             and function names needs to be present in the assembler source
136
#             files -- see avr-libc docs [FIXME: not yet described there]
137
ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs 
138

  
139

  
140
#---------------- Library Options ----------------
141
# Minimalistic printf version
142
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
143

  
144
# Floating point printf version (requires MATH_LIB = -lm below)
145
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
146

  
147
# If this is left blank, then it will use the Standard printf version.
148
PRINTF_LIB = 
149
#PRINTF_LIB = $(PRINTF_LIB_MIN)
150
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
151

  
152

  
153
# Minimalistic scanf version
154
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
155

  
156
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
157
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
158

  
159
# If this is left blank, then it will use the Standard scanf version.
160
SCANF_LIB = 
161
#SCANF_LIB = $(SCANF_LIB_MIN)
162
#SCANF_LIB = $(SCANF_LIB_FLOAT)
163

  
164

  
165
MATH_LIB = -lm
166

  
167

  
168

  
169
#---------------- External Memory Options ----------------
170

  
171
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
172
# used for variables (.data/.bss) and heap (malloc()).
173
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
174

  
175
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
176
# only used for heap (malloc()).
177
#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
178

  
179
EXTMEMOPTS =
180

  
181

  
182

  
183
#---------------- Linker Options ----------------
184
#  -Wl,...:     tell GCC to pass this to linker.
185
#    -Map:      create map file
186
#    --cref:    add cross reference to  map file
187
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
188
LDFLAGS += $(EXTMEMOPTS)
189
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
190

  
191

  
192

  
193
#---------------- Programming Options (avrdude) ----------------
194

  
195
# Programming hardware: alf avr910 avrisp bascom bsd 
196
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
197
#
198
# Type: avrdude -c ?
199
# to get a full listing.
200
#
201
AVRDUDE_PROGRAMMER = avrisp
202

  
203
# com1 = serial port. Use lpt1 to connect to parallel port.
204
AVRDUDE_PORT = com1
205
# programmer connected to serial device
206

  
207
AVRDUDE_WRITE_FLASH = -b 4800 -U flash:w:$(TARGET).hex
208
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
209

  
210

  
211
# Uncomment the following if you want avrdude's erase cycle counter.
212
# Note that this counter needs to be initialized first using -Yn,
213
# see avrdude manual.
214
#AVRDUDE_ERASE_COUNTER = -y
215

  
216
# Uncomment the following if you do /not/ wish a verification to be
217
# performed after programming the device.
218
#AVRDUDE_NO_VERIFY = -V
219

  
220
# Increase verbosity level.  Please use this when submitting bug
221
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> 
222
# to submit bug reports.
223
#AVRDUDE_VERBOSE = -v -v
224

  
225
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
226
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
227
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
228
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
229

  
230

  
231

  
232
#---------------- Debugging Options ----------------
233

  
234
# For simulavr only - target MCU frequency.
235
DEBUG_MFREQ = $(F_CPU)
236

  
237
# Set the DEBUG_UI to either gdb or insight.
238
# DEBUG_UI = gdb
239
DEBUG_UI = insight
240

  
241
# Set the debugging back-end to either avarice, simulavr.
242
DEBUG_BACKEND = avarice
243
#DEBUG_BACKEND = simulavr
244

  
245
# GDB Init Filename.
246
GDBINIT_FILE = __avr_gdbinit
247

  
248
# When using avarice settings for the JTAG
249
JTAG_DEV = /dev/com1
250

  
251
# Debugging port used to communicate between GDB / avarice / simulavr.
252
DEBUG_PORT = 4242
253

  
254
# Debugging host used to communicate between GDB / avarice / simulavr, normally
255
#     just set to localhost unless doing some sort of crazy debugging when 
256
#     avarice is running on a different computer.
257
DEBUG_HOST = localhost
258

  
259

  
260

  
261
#============================================================================
262

  
263

  
264
# Define programs and commands.
265
SHELL = sh
266
CC = avr-gcc
267
OBJCOPY = avr-objcopy
268
OBJDUMP = avr-objdump
269
SIZE = avr-size
270
NM = avr-nm
271
AVRDUDE = avrdude
272
REMOVE = rm -f
273
COPY = cp
274
WINSHELL = cmd
275

  
276

  
277
# Define Messages
278
# English
279
MSG_ERRORS_NONE = Errors: none
280
MSG_BEGIN = -------- begin --------
281
MSG_END = --------  end  --------
282
MSG_SIZE_BEFORE = Size before: 
283
MSG_SIZE_AFTER = Size after:
284
MSG_COFF = Converting to AVR COFF:
285
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
286
MSG_FLASH = Creating load file for Flash:
287
MSG_EEPROM = Creating load file for EEPROM:
288
MSG_EXTENDED_LISTING = Creating Extended Listing:
289
MSG_SYMBOL_TABLE = Creating Symbol Table:
290
MSG_LINKING = Linking:
291
MSG_COMPILING = Compiling:
292
MSG_ASSEMBLING = Assembling:
293
MSG_CLEANING = Cleaning project:
294

  
295

  
296

  
297

  
298
# Define all object files.
299
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) 
300

  
301
# Define all listing files.
302
LST = $(SRC:.c=.lst) $(ASRC:.S=.lst) 
303

  
304

  
305
# Compiler flags to generate dependency files.
306
GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d
307

  
308

  
309
# Combine all necessary flags and optional flags.
310
# Add target processor to flags.
311
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
312
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
313

  
314

  
315

  
316

  
317

  
318
# Default target.
319
all: begin gccversion sizebefore build sizeafter end
320

  
321
build: elf hex eep lss sym
322

  
323
elf: $(TARGET).elf
324
hex: $(TARGET).hex
325
eep: $(TARGET).eep
326
lss: $(TARGET).lss 
327
sym: $(TARGET).sym
328

  
329

  
330

  
331
# Eye candy.
332
# AVR Studio 3.x does not check make's exit code but relies on
333
# the following magic strings to be generated by the compile job.
334
begin:
335
	@echo
336
	@echo $(MSG_BEGIN)
337

  
338
end:
339
	@echo $(MSG_END)
340
	@echo
341

  
342

  
343
# Display size of file.
344
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
345
ELFSIZE = $(SIZE) -A $(TARGET).elf
346
AVRMEM = avr-mem.sh $(TARGET).elf $(MCU)
347

  
348
sizebefore:
349
	@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
350
	$(AVRMEM) 2>/dev/null; echo; fi
351

  
352
sizeafter:
353
	@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
354
	$(AVRMEM) 2>/dev/null; echo; fi
355

  
356

  
357

  
358
# Display compiler version information.
359
gccversion : 
360
	@$(CC) --version
361

  
362

  
363

  
364
# Program the device.  
365
program: $(TARGET).hex $(TARGET).eep
366
	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
367

  
368

  
369
# Generate avr-gdb config/init file which does the following:
370
#     define the reset signal, load the target file, connect to target, and set 
371
#     a breakpoint at main().
372
gdb-config: 
373
	@$(REMOVE) $(GDBINIT_FILE)
374
	@echo define reset >> $(GDBINIT_FILE)
375
	@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
376
	@echo end >> $(GDBINIT_FILE)
377
	@echo file $(TARGET).elf >> $(GDBINIT_FILE)
378
	@echo target remote $(DEBUG_HOST):$(DEBUG_PORT)  >> $(GDBINIT_FILE)
379
ifeq ($(DEBUG_BACKEND),simulavr)
380
	@echo load  >> $(GDBINIT_FILE)
381
endif	
382
	@echo break main >> $(GDBINIT_FILE)
383
	
384
debug: gdb-config $(TARGET).elf
385
ifeq ($(DEBUG_BACKEND), avarice)
386
	@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
387
	@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
388
	$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
389
	@$(WINSHELL) /c pause
390
	
391
else
392
	@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
393
	$(DEBUG_MFREQ) --port $(DEBUG_PORT)
394
endif
395
	@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
396
	
397

  
398

  
399

  
400
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
401
COFFCONVERT=$(OBJCOPY) --debugging \
402
--change-section-address .data-0x800000 \
403
--change-section-address .bss-0x800000 \
404
--change-section-address .noinit-0x800000 \
405
--change-section-address .eeprom-0x810000 
406

  
407

  
408
coff: $(TARGET).elf
409
	@echo
410
	@echo $(MSG_COFF) $(TARGET).cof
411
	$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
412

  
413

  
414
extcoff: $(TARGET).elf
415
	@echo
416
	@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
417
	$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
418

  
419

  
420

  
421
# Create final output files (.hex, .eep) from ELF output file.
422
%.hex: %.elf
423
	@echo
424
	@echo $(MSG_FLASH) $@
425
	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
426

  
427
%.eep: %.elf
428
	@echo
429
	@echo $(MSG_EEPROM) $@
430
	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
431
	--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
432

  
433
# Create extended listing file from ELF output file.
434
%.lss: %.elf
435
	@echo
436
	@echo $(MSG_EXTENDED_LISTING) $@
437
	$(OBJDUMP) -h -S $< > $@
438

  
439
# Create a symbol table from ELF output file.
440
%.sym: %.elf
441
	@echo
442
	@echo $(MSG_SYMBOL_TABLE) $@
443
	$(NM) -n $< > $@
444

  
445

  
446

  
447
# Link: create ELF output file from object files.
448
.SECONDARY : $(TARGET).elf
449
.PRECIOUS : $(OBJ)
450
%.elf: $(OBJ)
451
	@echo
452
	@echo $(MSG_LINKING) $@
453
	$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
454

  
455

  
456
# Compile: create object files from C source files.
457
%.o : %.c
458
	@echo
459
	@echo $(MSG_COMPILING) $<
460
	$(CC) -c $(ALL_CFLAGS) $< -o $@ 
461

  
462

  
463
# Compile: create assembler files from C source files.
464
%.s : %.c
465
	$(CC) -S $(ALL_CFLAGS) $< -o $@
466

  
467

  
468
# Assemble: create object files from assembler source files.
469
%.o : %.S
470
	@echo
471
	@echo $(MSG_ASSEMBLING) $<
472
	$(CC) -c $(ALL_ASFLAGS) $< -o $@
473

  
474
# Create preprocessed source for use in sending a bug report.
475
%.i : %.c
476
	$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ 
477

  
478

  
479
# Target: clean project.
480
clean: begin clean_list end
481

  
482
clean_list :
483
	@echo
484
	@echo $(MSG_CLEANING)
485
	$(REMOVE) $(TARGET).hex
486
	$(REMOVE) $(TARGET).eep
487
	$(REMOVE) $(TARGET).cof
488
	$(REMOVE) $(TARGET).elf
489
	$(REMOVE) $(TARGET).map
490
	$(REMOVE) $(TARGET).sym
491
	$(REMOVE) $(TARGET).lss
492
	$(REMOVE) $(OBJ)
493
	$(REMOVE) $(LST)
494
	$(REMOVE) $(SRC:.c=.s)
495
	$(REMOVE) $(SRC:.c=.d)
496
	$(REMOVE) .dep/*
497

  
498

  
499

  
500
# Include the dependency files.
501
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
502

  
503

  
504
# Listing of phony targets.
505
.PHONY : all begin finish end sizebefore sizeafter gccversion \
506
build elf hex eep lss sym coff extcoff \
507
clean clean_list program debug gdb-config
508

  
branches/charge_station_isp/code/projects/i2c_plugnplay/i2c.c
1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

  
26

  
27
/**
28
 * @file i2c.c
29
 * @brief Implemenation of I2C communications protocol
30
 * 
31
 * In the case where you have master sends and then a master request to the same
32
 * address, you will not give up control of the line because the send and
33
 * request addresses are seen as different addresses. In between it will send a
34
 * restart but will not give up the line.
35
 *
36
 * @author CMU Robotics Club, Kevin Woo, Sursh Nidhiry
37
 * @bug Not tested.
38
 */
39

  
40
#include <avr/interrupt.h>
41
#include <util/twi.h>
42

  
43
#include "i2c.h"
44
#include "ring_buffer.h"
45

  
46
/**
47
 * @defgroup i2c I2C 
48
 *
49
 * @brief Provides Inter-Interconnected-Communications (I2C)
50
 * 
51
 * Initiates I2C functions on an ATMega128 which has a fully hardware Two Wire 
52
 * Interface (TWI) module. Any Atmel chip with this hardware should be able to
53
 * use the software.
54
 *
55
 * This code will operate in a multi-master enviornment and can be either a
56
 * slave or a master at any time (as long as they are not one or the other at
57
 * the moment. You can queue up multiple transmission modes in the buffer up to 
58
 * the buffer size. The buffer is implemented as a ring buffer.
59
 *
60
 * It is implemented using callback functions. Whenever you want to send a packet
61
 * you can call the built in send function (as a master) and it will send an array
62
 * of bytes. Master recieve and slave send/receive are all handled by the call back
63
 * functions. It is up to the end user to create functions that will handle the
64
 * receiving of packets. Their functions will be called with every byte recieved
65
 * so you must either buffer the inputs or handle each one separately.
66
 *
67
 * On errors we will simply flush the entire buffer.
68
 * 
69
 * For information on how I2C operates, read the wikipedia article
70
 * http://en.wikipedia.org/wiki/I2c
71
 * for a good explanation of how it works.
72
 * @{
73
 */
74

  
75
/** 
76
 * @brief Set bit rate 12 = 100kbit/s (max speed setting is 10 for an
77
 *  8 MHz clock). It is a divider, so the lower the number the faster the speed.
78
 */
79
#define I2C_BIT_RATE_DIVIDER 0x0C
80

  
81
static int start_flag;
82

  
83
static fun_mrecv_t master_recv_function;
84
static fun_srecv_t slave_recv_function;
85
static fun_send_t slave_send_function;
86

  
87
RING_BUFFER_NEW(i2c_buffer, 128, char, i2c_write_buff, i2c_addr_buff);
88

  
89

  
90
/**
91
 * @brief Initializes the i2c module.
92
 *
93
 * Initializes the I2C module to start listening on the i2c lines. If the callback functions
94
 * are not set to null they will be called when that transmission mode is called. The address
95
 * is your address that you will listen to when you are not the master.
96
 *
97
 * @param addr 			Your address on the I2C bus.
98
 * @param master_recv 	The address of the function to call when you receive a byte when you are a
99
 *                    	master.
100
 * @param slave_recv 	The address of the function to call when you are a slave you receive data
101
 *								from the master
102
 * @param slave_send		The address of the function to call when you are a slave and the master
103
 *								requests data from you.
104
 *
105
 * @return 0 for success, nonzero for failure
106
 **/
107
int i2c_init(char addr, fun_mrecv_t master_recv, fun_srecv_t slave_recv, fun_send_t slave_send) {
108
    master_recv_function = master_recv;
109
    slave_recv_function = slave_recv;
110
    slave_send_function = slave_send;
111

  
112
    RING_BUFFER_CLEAR(i2c_write_buff);
113
    RING_BUFFER_CLEAR(i2c_addr_buff);
114
  
115
    /* enables twi interrupt, automatic ack sending, and all twi hardware */
116
    TWCR =  (_BV(TWEA) | _BV(TWEN) | _BV(TWIE));
117

  
118
    /* sets the bit rate of data transmission */
119
    TWBR = I2C_BIT_RATE_DIVIDER;
120

  
121
    /* sets the address (it is stored in the 7 most significant bits) and allows
122
     * global messages to be accepted */
123
    TWAR = (addr << 1) | 1;
124
  
125
    return 0;
126
}
127

  
128
/**
129
 * @brief Sends a byte array over I2C as a master
130
 *
131
 * Will perform a send over I2C to the destination from data for the ammount of
132
 * bytes that bytes is.
133
 *
134
 * @param dest		Destination address of the data on the I2C bus.
135
 * @param data 	The pointer to the byte array of data
136
 * @param bytes	The amount of bytes long that the byte array is. This is how
137
 *						many bytes from the array that the function will send.
138
 *
139
 * @return zero for success, nonzero for failure
140
 **/
141
int i2c_send(char dest, char *data, size_t bytes) {
142
    int i;
143

  
144
    /* adding data to be sent to ring buffers is not atomic,
145
     * so disable interrupts */
146
    cli();
147
    for(i = 0; i < bytes; i++) {
148
        if(RING_BUFFER_FULL(i2c_write_buff)) {
149
            sei();
150
            return -1;
151
        }
152

  
153
        RING_BUFFER_ADD(i2c_write_buff, data[i]);
154
        RING_BUFFER_ADD(i2c_addr_buff, dest << 1);
155
    }
156
    
157
    /* re-enable the interrupts */
158
    sei();
159
    
160
    /* send the start bit, only if this device is not currently master */
161
    if(!start_flag) {
162
        start_flag = 1;
163
        TWCR |= _BV(TWSTA);
164
        TWCR |= _BV(TWINT);
165
    }
166
  
167
    return 0;
168
}
169
 
170
/**
171
 * @brief Send a master request to the destination
172
 *
173
 * Sends a request of data from the target address and calls
174
 * the callback function to handle data as it comes in. This function will
175
 * not work if the slave has not informationt to send or has nothing implemented
176
 * to send it.
177
 *
178
 * @param dest		The destination that we want to receive information from.
179
 *
180
 * @return 0 for success, nonzero for failure
181
 **/ 
182
int i2c_request(char dest) {
183
    if(RING_BUFFER_FULL(i2c_write_buff))
184
        return -1;
185
  
186
    RING_BUFFER_ADD(i2c_write_buff, 0);
187
    RING_BUFFER_ADD(i2c_addr_buff, (dest << 1) | 1);
188
  
189
    if(!start_flag) {
190
        start_flag = 1;
191
        TWCR |= _BV(TWSTA);
192
        TWCR |= _BV(TWINT);
193
    }
194
  
195
    return 0;
196
}
197

  
198
/** @} **/
199
 
200
/**
201
 * @brief Interrupt to handle I2C interrupts from the I2C hardware.
202
 * 
203
 * Uses the status codes from the I2C register to handle the events
204
 * needed to advance in I2C stages. For instance, you will get a bit for
205
 * receiving a start ack, then a address ack, then a data ack, etc.
206
 * The events are handled in each switch case. The status codes are defined
207
 * by avr-gcc in /util/twi.h but are the same codes as the Atmel documentation.
208
 *
209
 * Bytes are sent by popping off the ring buffer. It also will keep track
210
 * of what modes the send is in.
211
 *
212
 * Errors are handled here as well.
213
 **/ 
214
ISR(TWI_vect) {
215
	static char data_to_send;
216
	static char addr_to_send = -1;
217
	char addr, statusCode;
218
  
219
	//Get status code (only upper 5 bits)
220
	statusCode = (TWSR & 0xF8);
221

  
222
    switch (statusCode) {
223
        //Start sent successfully
224
        case TW_START:
225
        case TW_REP_START:
226
            /* Send address and write
227
             * ring_buffer will not be empty */
228
            RING_BUFFER_REMOVE(i2c_addr_buff, addr_to_send);
229
            RING_BUFFER_REMOVE(i2c_write_buff, data_to_send);
230
            
231
            /* first send the address */
232
            TWDR = addr_to_send; 
233
            
234
            //Turn off start bits
235
            TWCR &= ~_BV(TWSTA);
236
            break;
237

  
238
        //Master Transmit - Address sent succesfully
239
        case TW_MT_SLA_ACK:
240
        //Send byte
241
            TWDR = data_to_send;
242
            PORTG &= ~_BV(PG2);
243
            break;
244
	 
245
        //Master Transmit - Data sent succesfully
246
        case TW_MT_DATA_ACK:    
247
            //If there is still data to send
248
            if(!RING_BUFFER_EMPTY(i2c_write_buff)) {
249
                RING_BUFFER_PEEK(i2c_addr_buff, addr);
250
        
251
                //Still data for this address
252
                if (addr == addr_to_send) {
253
                    RING_BUFFER_REMOVE(i2c_addr_buff, addr);
254
                    RING_BUFFER_REMOVE(i2c_write_buff, TWDR);
255
                    break;
256
                //No more data for this address, data for another address -> resend start
257
                } else {
258
                    TWCR |= _BV(TWSTA);
259
                    break;
260
                }
261
            }
262
            /* there are no bytes to send */
263
            TWCR |= _BV(TWSTO);
264
            start_flag = 0;
265
            break; 
266
            
267
        //Master Transmit - Slave sends a nack, transmit is done
268
        case TW_MT_DATA_NACK:
269
            PORTG |= _BV(PG2);
270
            TWCR |= _BV(TWSTO);
271
            start_flag = 0;
272
            break;
273
    
274
        //Master Receive - Address sent succesfully
275
        case TW_MR_SLA_ACK:
276
            PORTG |= _BV(PG2);
277
            break;
278
            
279
        //Master Receive - Data received succesfully
280
        case TW_MR_DATA_ACK:
281
            if(master_recv_function) {
282
                if(!master_recv_function(TWDR)) {
283
                    TWCR &= ~_BV(TWEA);
284
                }
285
            }
286
            break;
287
            
288
        //Master Receive - Slave sends a nack, transmission is done    
289
        case TW_MR_DATA_NACK:
290
            TWCR |= _BV(TWEA);
291
      
292
            //If there is still data to send
293
            if(!RING_BUFFER_EMPTY(i2c_write_buff)) {
294
                TWCR |= _BV(TWSTA);
295
                break;
296
            }
297
      
298
            /* there are no bytes to send */
299
            TWCR |= _BV(TWSTO);
300
            start_flag = 0;  
301
            break;
302
    
303
        //Slave Transmit - Address received
304
        case TW_ST_SLA_ACK:
305
            break;
306
    
307
        //Slave Transmit - Nack received, no data requsted
308
        case TW_ST_DATA_NACK:
309
            break;
310
        
311
        //Slave Transmit - Data requested, ack received
312
        case TW_ST_DATA_ACK:
313
            if (slave_send_function) {
314
                TWDR = slave_send_function();
315
            }
316
            break;
317
    
318
        //Slave Receive - Address received  
319
        case TW_SR_SLA_ACK:
320
            break;
321
    
322
        //Slave Receive - Data received, ack returned
323
        case TW_SR_DATA_ACK:
324
            if(slave_recv_function) {
325
                slave_recv_function(TWDR);
326
            }
327
            
328
            break;
329
      
330
        //Stop sent  
331
        case TW_SR_STOP:
332
            break;
333
	
334
        //Problem on the bus, reset everything
335
        default:
336
            TWCR |= _BV(TWSTO);
337
            start_flag = 0;
338
            RING_BUFFER_CLEAR(i2c_write_buff);
339
            RING_BUFFER_CLEAR(i2c_addr_buff);  	
340
    }
341
  
342
  /* Toggle TWINT so that it resets and executes the commands */
343
  TWCR |= _BV(TWINT);
344
}
345

  

Also available in: Unified diff