1 ###############################################################################
\r
3 # IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:39 #
\r
4 # Copyright 1996-2007 IAR Systems. All rights reserved. #
\r
6 # Source file = C:\home\kevin\pub\src\bc100_cal\IAR\USI.c #
\r
7 # Command line = C:\home\kevin\pub\src\bc100_cal\IAR\USI.c --cpu=tiny861 #
\r
8 # -ms -o C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Obj\ #
\r
9 # -lC C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\ -lB #
\r
10 # C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\ #
\r
11 # --initializers_in_flash -z2 --no_cse --no_inline #
\r
12 # --no_code_motion --no_cross_call --no_clustering #
\r
13 # --no_tbaa --debug -DENABLE_BIT_DEFINITIONS -e #
\r
14 # --require_prototypes -I "C:\Program Files\IAR #
\r
15 # Systems\Embedded Workbench 4.0\avr\INC\" -I "C:\Program #
\r
16 # Files\IAR Systems\Embedded Workbench 4.0\avr\INC\CLIB\" #
\r
17 # --eeprom_size 512 #
\r
18 # List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\USI.lst #
\r
19 # Object file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Obj\USI.r90 #
\r
22 ###############################################################################
\r
24 C:\home\kevin\pub\src\bc100_cal\IAR\USI.c
\r
25 1 /* This file has been prepared for Doxygen automatic documentation generation.*/
\r
26 2 /*! \file *********************************************************************
\r
29 5 * Functions for use of the Universal Serial Interface
\r
31 7 * Contains high level functions for initializing the USI as an SPI slave,
\r
32 8 * interrupt handling, sending and receiving single bytes.
\r
34 10 * \par Application note:
\r
35 11 * AVR458: Charging Li-Ion Batteries with BC100 \n
\r
36 12 * AVR463: Charging NiMH Batteries with BC100
\r
38 14 * \par Documentation:
\r
39 15 * For comprehensive code documentation, supported compilers, compiler
\r
40 16 * settings and supported devices see readme.html
\r
43 19 * Atmel Corporation: http://www.atmel.com \n
\r
44 20 * Support email: avr@atmel.com \n
\r
45 21 * Original author: \n
\r
48 24 * $Revision: 2299 $
\r
50 26 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/USI.c $
\r
51 27 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n
\r
52 28 ******************************************************************************/
\r
54 30 #include <ioavr.h>
\r
56 \ In segment ABSOLUTE, at 0x38
\r
57 \ <unnamed> volatile __io _A_PORTB
\r
61 \ In segment ABSOLUTE, at 0x37
\r
62 \ <unnamed> volatile __io _A_DDRB
\r
66 \ In segment ABSOLUTE, at 0x2f
\r
67 \ <unnamed> volatile __io _A_USIDR
\r
71 \ In segment ABSOLUTE, at 0x2e
\r
72 \ <unnamed> volatile __io _A_USISR
\r
76 \ In segment ABSOLUTE, at 0x2d
\r
77 \ <unnamed> volatile __io _A_USICR
\r
80 31 #include <inavr.h>
\r
82 33 #include "enums.h"
\r
83 34 #include "structs.h"
\r
85 36 #include "main.h"
\r
87 38 #include "battery.h"
\r
88 39 #include "time.h"
\r
92 43 //******************************************************************************
\r
94 45 //******************************************************************************
\r
95 46 //! SPI status struct
\r
97 \ In segment NEAR_Z, align 1, keep-with-next
\r
98 \ 00000000 REQUIRE `?<Segment init: NEAR_Z>`
\r
99 47 SPI_Status_t SPI;
\r
104 50 //******************************************************************************
\r
106 52 //*****************************************************************************
\r
107 53 /*! \brief USI Counter Overflow Interrupt Service Routine
\r
109 55 * When the USI counter overflows, a byte has been transferred.\n
\r
110 56 * The USIDR contents are stored and flags are updated.
\r
112 58 * The protocol is quite simple and has three sequential states: command,
\r
113 59 * address and data.
\r
114 60 * (Keep in mind that the Master is in charge of data clocking, which means
\r
115 61 * there is a one byte "delay" from when the Slave puts something to SPI till
\r
116 62 * the Master can read it.)
\r
118 64 * 1. If a non-zero byte is received in the command state, the ISR will
\r
119 65 * store the commands to the SPI struct (read/write, EEPROM/SRAM, number of
\r
120 66 * bytes). To signal that the command was received, 0xCC is put to the SPI bus.
\r
121 67 * If a zero byte (0x00) is received in the command state, it is simply ignored
\r
122 68 * because it is an invalid command.
\r
124 70 * 2. When a byte is received in the address state, it is stored to the SPI
\r
125 71 * struct. To signal that the address was received, 0xBB is put to SPI bus.
\r
127 73 * 3. In the data state, variables are read/written "from back to front" until
\r
128 74 * the byte counter reaches zero. Since the Master is in charge of the data
\r
129 75 * clocking, the Slave will go to command state before the last byte is
\r
130 76 * transferred during reading. This means that the Master should send an
\r
131 77 * invalid command when getting each byte, ie 0x00.
\r
133 79 * If the time between two transfers is 1 second or more, the Slave
\r
134 80 * automatically reverts to command state.
\r
136 82 * \note Battery charging is not automatically halted during SPI communication.
\r
137 83 * This means that the current charge state (current and voltage) will
\r
138 84 * remain constant during heavy and prolonged serial traffic.
\r
140 86 * \todo Variable writing not implemented yet.
\r
141 87 * \todo EEPROM/SRAM flag doesn't really do anything with this implementation.
\r
143 89 #pragma vector=USI_OVF_vect
\r
145 \ In segment CODE, align 2, keep-with-next
\r
146 90 __interrupt void USI_OVF_ISR(void)
\r
149 \ 00000000 93AA ST -Y, R26
\r
150 \ 00000002 939A ST -Y, R25
\r
151 \ 00000004 938A ST -Y, R24
\r
152 \ 00000006 93FA ST -Y, R31
\r
153 \ 00000008 93EA ST -Y, R30
\r
154 \ 0000000A 923A ST -Y, R3
\r
155 \ 0000000C 922A ST -Y, R2
\r
156 \ 0000000E 921A ST -Y, R1
\r
157 \ 00000010 920A ST -Y, R0
\r
158 \ 00000012 937A ST -Y, R23
\r
159 \ 00000014 936A ST -Y, R22
\r
160 \ 00000016 935A ST -Y, R21
\r
161 \ 00000018 934A ST -Y, R20
\r
162 \ 0000001A 933A ST -Y, R19
\r
163 \ 0000001C 932A ST -Y, R18
\r
164 \ 0000001E 931A ST -Y, R17
\r
165 \ 00000020 930A ST -Y, R16
\r
166 \ 00000022 B7AF IN R26, 0x3F
\r
167 92 // If the communication timed out, set ST_CMD as current state.
\r
168 93 if (!Time_Left(TIMER_USI)) {
\r
169 \ 00000024 E000 LDI R16, 0
\r
170 \ 00000026 .... RCALL Time_Left
\r
171 \ 00000028 2300 TST R16
\r
172 \ 0000002A F431 BRNE ??USI_OVF_ISR_0
\r
173 94 SPI.State = ST_CMD;
\r
174 \ 0000002C 9100.... LDS R16, (SPI + 2)
\r
175 \ 00000030 730F ANDI R16, 0x3F
\r
176 \ 00000032 6400 ORI R16, 0x40
\r
177 \ 00000034 9300.... STS (SPI + 2), R16
\r
180 97 // Start communication timer. If further communication doesn't happen
\r
181 98 // within 1 second, the SPI communication state is reset to CMD.
\r
182 99 Time_Set(TIMER_USI, 0, 1, 0);
\r
184 \ 00000038 E040 LDI R20, 0
\r
185 \ 0000003A E011 LDI R17, 1
\r
186 \ 0000003C E020 LDI R18, 0
\r
187 \ 0000003E E030 LDI R19, 0
\r
188 \ 00000040 E000 LDI R16, 0
\r
189 \ 00000042 .... RCALL Time_Set
\r
191 101 // Clear USI counter and flag completed transfer.
\r
192 102 USISR = (1<<USIOIF);
\r
193 \ 00000044 E400 LDI R16, 64
\r
194 \ 00000046 B90E OUT 0x0E, R16
\r
195 103 SPI.XferComplete = TRUE;
\r
196 \ 00000048 .... LDI R30, LOW(SPI)
\r
197 \ 0000004A .... LDI R31, (SPI) >> 8
\r
198 \ 0000004C 8103 LDD R16, Z+3
\r
199 \ 0000004E 6004 ORI R16, 0x04
\r
200 \ 00000050 8303 STD Z+3, R16
\r
202 105 // Process incoming data.
\r
203 106 switch(SPI.State) {
\r
204 \ 00000052 9100.... LDS R16, (SPI + 2)
\r
205 \ 00000056 0F00 LSL R16
\r
206 \ 00000058 1F00 ROL R16
\r
207 \ 0000005A 1F00 ROL R16
\r
208 \ 0000005C 7003 ANDI R16, 0x03
\r
209 \ 0000005E 5001 SUBI R16, 1
\r
210 \ 00000060 F039 BREQ ??USI_OVF_ISR_1
\r
211 \ 00000062 950A DEC R16
\r
212 \ 00000064 F409 BRNE $+2+2
\r
213 \ 00000066 C040 RJMP ??USI_OVF_ISR_2
\r
214 \ 00000068 950A DEC R16
\r
215 \ 0000006A F409 BRNE $+2+2
\r
216 \ 0000006C C050 RJMP ??USI_OVF_ISR_3
\r
217 \ 0000006E C0C0 RJMP ??USI_OVF_ISR_4
\r
218 107 // A valid SPI transfer starts with a Command Byte sent by the Master.
\r
220 109 SPI.Data = USIDR; // Store the transferred byte.
\r
222 \ 00000070 B10F IN R16, 0x0F
\r
223 \ 00000072 9110.... LDS R17, SPI
\r
224 \ 00000076 9300.... STS SPI, R16
\r
226 111 // If the master sent 0, it is trying to get data. Ignore in this state.
\r
227 112 if (SPI.Data != 0) {
\r
228 \ 0000007A 9100.... LDS R16, SPI
\r
229 \ 0000007E 2300 TST R16
\r
230 \ 00000080 F409 BRNE $+2+2
\r
231 \ 00000082 C0B6 RJMP ??USI_OVF_ISR_4
\r
232 113 // Does the master want to read or write?
\r
233 114 if (SPI.Data & 0x40) {
\r
234 \ 00000084 .... LDI R30, LOW(SPI)
\r
235 \ 00000086 .... LDI R31, (SPI) >> 8
\r
236 \ 00000088 8100 LD R16, Z
\r
237 \ 0000008A FF06 SBRS R16, 6
\r
238 \ 0000008C C006 RJMP ??USI_OVF_ISR_5
\r
239 115 SPI.Read = FALSE;
\r
240 \ 0000008E .... LDI R30, LOW(SPI)
\r
241 \ 00000090 .... LDI R31, (SPI) >> 8
\r
242 \ 00000092 8103 LDD R16, Z+3
\r
243 \ 00000094 7F0E ANDI R16, 0xFE
\r
244 \ 00000096 8303 STD Z+3, R16
\r
245 \ 00000098 C005 RJMP ??USI_OVF_ISR_6
\r
247 117 SPI.Read = TRUE;
\r
249 \ 0000009A .... LDI R30, LOW(SPI)
\r
250 \ 0000009C .... LDI R31, (SPI) >> 8
\r
251 \ 0000009E 8103 LDD R16, Z+3
\r
252 \ 000000A0 6001 ORI R16, 0x01
\r
253 \ 000000A2 8303 STD Z+3, R16
\r
256 120 // From/to EEPROM or SRAM?
\r
257 121 if (SPI.Data &0x80) {
\r
259 \ 000000A4 .... LDI R30, LOW(SPI)
\r
260 \ 000000A6 .... LDI R31, (SPI) >> 8
\r
261 \ 000000A8 8100 LD R16, Z
\r
262 \ 000000AA FF07 SBRS R16, 7
\r
263 \ 000000AC C006 RJMP ??USI_OVF_ISR_7
\r
264 122 SPI.EEPROM = TRUE;
\r
265 \ 000000AE .... LDI R30, LOW(SPI)
\r
266 \ 000000B0 .... LDI R31, (SPI) >> 8
\r
267 \ 000000B2 8103 LDD R16, Z+3
\r
268 \ 000000B4 6002 ORI R16, 0x02
\r
269 \ 000000B6 8303 STD Z+3, R16
\r
270 \ 000000B8 C005 RJMP ??USI_OVF_ISR_8
\r
272 124 SPI.EEPROM = FALSE;
\r
274 \ 000000BA .... LDI R30, LOW(SPI)
\r
275 \ 000000BC .... LDI R31, (SPI) >> 8
\r
276 \ 000000BE 8103 LDD R16, Z+3
\r
277 \ 000000C0 7F0D ANDI R16, 0xFD
\r
278 \ 000000C2 8303 STD Z+3, R16
\r
281 127 SPI.Count = (SPI.Data & 0x3F); // Get number of bytes to receive/send.
\r
283 \ 000000C4 9110.... LDS R17, (SPI + 2)
\r
284 \ 000000C8 7C10 ANDI R17, 0xC0
\r
285 \ 000000CA 9100.... LDS R16, SPI
\r
286 \ 000000CE 730F ANDI R16, 0x3F
\r
287 \ 000000D0 2B01 OR R16, R17
\r
288 \ 000000D2 9300.... STS (SPI + 2), R16
\r
289 128 SPI.State = ST_ADDR; // The Master will send the address byte next.
\r
290 \ 000000D6 9100.... LDS R16, (SPI + 2)
\r
291 \ 000000DA 730F ANDI R16, 0x3F
\r
292 \ 000000DC 6800 ORI R16, 0x80
\r
293 \ 000000DE 9300.... STS (SPI + 2), R16
\r
295 130 SPI_Put(0xCC); // Signal that command was received.
\r
296 \ 000000E2 EC0C LDI R16, 204
\r
297 \ 000000E4 .... RCALL SPI_Put
\r
298 \ 000000E6 C084 RJMP ??USI_OVF_ISR_4
\r
304 136 SPI.Data = USIDR; // Store the address.
\r
306 \ 000000E8 B10F IN R16, 0x0F
\r
307 \ 000000EA 9180.... LDS R24, SPI
\r
308 \ 000000EE 9300.... STS SPI, R16
\r
309 137 SPI.Address = SPI.Data;
\r
310 \ 000000F2 9190.... LDS R25, (SPI + 1)
\r
311 \ 000000F6 9100.... LDS R16, SPI
\r
312 \ 000000FA 9300.... STS (SPI + 1), R16
\r
313 138 SPI.State = ST_DATA; // The master will send/wait for data next.
\r
314 \ 000000FE .... LDI R30, LOW(SPI)
\r
315 \ 00000100 .... LDI R31, (SPI) >> 8
\r
316 \ 00000102 8102 LDD R16, Z+2
\r
317 \ 00000104 6C00 ORI R16, 0xC0
\r
318 \ 00000106 8302 STD Z+2, R16
\r
320 140 SPI_Put(0xBB); // Signal that address was received.
\r
321 \ 00000108 EB0B LDI R16, 187
\r
322 \ 0000010A .... RCALL SPI_Put
\r
323 \ 0000010C C071 RJMP ??USI_OVF_ISR_4
\r
327 144 // Note well: this will process at least one byte, regardless of Count.
\r
329 146 if (SPI.Count-- > 0) {
\r
331 \ 0000010E 9100.... LDS R16, (SPI + 2)
\r
332 \ 00000112 2F20 MOV R18, R16
\r
333 \ 00000114 7C20 ANDI R18, 0xC0
\r
334 \ 00000116 2F10 MOV R17, R16
\r
335 \ 00000118 951A DEC R17
\r
336 \ 0000011A 731F ANDI R17, 0x3F
\r
337 \ 0000011C 2B12 OR R17, R18
\r
338 \ 0000011E 9310.... STS (SPI + 2), R17
\r
339 \ 00000122 730F ANDI R16, 0x3F
\r
340 \ 00000124 3001 CPI R16, 1
\r
341 \ 00000126 F408 BRCC $+2+2
\r
342 \ 00000128 C05D RJMP ??USI_OVF_ISR_9
\r
343 147 // Write specified variable to SPI, "back to front".
\r
344 148 if (SPI.Read) {
\r
345 \ 0000012A .... LDI R30, LOW(SPI)
\r
346 \ 0000012C .... LDI R31, (SPI) >> 8
\r
347 \ 0000012E 8103 LDD R16, Z+3
\r
348 \ 00000130 FF00 SBRS R16, 0
\r
349 \ 00000132 C043 RJMP ??USI_OVF_ISR_10
\r
350 149 switch (SPI.Address) {
\r
351 \ 00000134 9100.... LDS R16, (SPI + 1)
\r
352 \ 00000138 5001 SUBI R16, 1
\r
353 \ 0000013A F049 BREQ ??USI_OVF_ISR_11
\r
354 \ 0000013C 950A DEC R16
\r
355 \ 0000013E F089 BREQ ??USI_OVF_ISR_12
\r
356 \ 00000140 950A DEC R16
\r
357 \ 00000142 F0C9 BREQ ??USI_OVF_ISR_13
\r
358 \ 00000144 950A DEC R16
\r
359 \ 00000146 F109 BREQ ??USI_OVF_ISR_14
\r
360 \ 00000148 950A DEC R16
\r
361 \ 0000014A F151 BREQ ??USI_OVF_ISR_15
\r
362 \ 0000014C C033 RJMP ??USI_OVF_ISR_16
\r
364 151 SPI_Put(*(((unsigned char*)&ADCS) + (SPI.Count)));
\r
365 \ ??USI_OVF_ISR_11:
\r
366 \ 0000014E 9100.... LDS R16, (SPI + 2)
\r
367 \ 00000152 730F ANDI R16, 0x3F
\r
368 \ 00000154 E010 LDI R17, 0
\r
369 \ 00000156 01F8 MOVW R31:R30, R17:R16
\r
370 \ 00000158 .... SUBI R30, LOW((-(ADCS) & 0xFFFF))
\r
371 \ 0000015A .... SBCI R31, (-(ADCS) & 0xFFFF) >> 8
\r
372 \ 0000015C 8100 LD R16, Z
\r
373 \ 0000015E .... RCALL SPI_Put
\r
374 \ 00000160 C047 RJMP ??USI_OVF_ISR_4
\r
378 155 case ADR_BATTACTIVE:
\r
379 156 SPI_Put(*((unsigned char*)&BattActive + (SPI.Count)));
\r
380 \ ??USI_OVF_ISR_12:
\r
381 \ 00000162 9100.... LDS R16, (SPI + 2)
\r
382 \ 00000166 730F ANDI R16, 0x3F
\r
383 \ 00000168 E010 LDI R17, 0
\r
384 \ 0000016A 01F8 MOVW R31:R30, R17:R16
\r
385 \ 0000016C .... SUBI R30, LOW((-(BattActive) & 0xFFFF))
\r
386 \ 0000016E .... SBCI R31, (-(BattActive) & 0xFFFF) >> 8
\r
387 \ 00000170 8100 LD R16, Z
\r
388 \ 00000172 .... RCALL SPI_Put
\r
389 \ 00000174 C03D RJMP ??USI_OVF_ISR_4
\r
393 160 case ADR_BATTDATA:
\r
394 161 SPI_Put(*((unsigned char*)&BattData + (SPI.Count)));
\r
395 \ ??USI_OVF_ISR_13:
\r
396 \ 00000176 9100.... LDS R16, (SPI + 2)
\r
397 \ 0000017A 730F ANDI R16, 0x3F
\r
398 \ 0000017C E010 LDI R17, 0
\r
399 \ 0000017E 01F8 MOVW R31:R30, R17:R16
\r
400 \ 00000180 .... SUBI R30, LOW((-(BattData) & 0xFFFF))
\r
401 \ 00000182 .... SBCI R31, (-(BattData) & 0xFFFF) >> 8
\r
402 \ 00000184 8100 LD R16, Z
\r
403 \ 00000186 .... RCALL SPI_Put
\r
404 \ 00000188 C033 RJMP ??USI_OVF_ISR_4
\r
408 165 case ADR_BATTCTRL:
\r
409 166 SPI_Put(*((__eeprom unsigned char*)&BattControl + (SPI.Count)));
\r
410 \ ??USI_OVF_ISR_14:
\r
411 \ 0000018A 9100.... LDS R16, (SPI + 2)
\r
412 \ 0000018E 730F ANDI R16, 0x3F
\r
413 \ 00000190 E010 LDI R17, 0
\r
414 \ 00000192 .... LDI R20, LOW(BattControl)
\r
415 \ 00000194 .... LDI R21, (BattControl) >> 8
\r
416 \ 00000196 0F40 ADD R20, R16
\r
417 \ 00000198 1F51 ADC R21, R17
\r
418 \ 0000019A .... RCALL __eeget8_16
\r
419 \ 0000019C .... RCALL SPI_Put
\r
420 \ 0000019E C028 RJMP ??USI_OVF_ISR_4
\r
423 169 case ADR_TIMERS:
\r
424 170 SPI_Put(*((unsigned char*)&timeval + (SPI.Count)));
\r
425 \ ??USI_OVF_ISR_15:
\r
426 \ 000001A0 9100.... LDS R16, (SPI + 2)
\r
427 \ 000001A4 730F ANDI R16, 0x3F
\r
428 \ 000001A6 E010 LDI R17, 0
\r
429 \ 000001A8 01F8 MOVW R31:R30, R17:R16
\r
430 \ 000001AA .... SUBI R30, LOW((-(timeval) & 0xFFFF))
\r
431 \ 000001AC .... SBCI R31, (-(timeval) & 0xFFFF) >> 8
\r
432 \ 000001AE 8100 LD R16, Z
\r
433 \ 000001B0 .... RCALL SPI_Put
\r
434 \ 000001B2 C01E RJMP ??USI_OVF_ISR_4
\r
440 \ ??USI_OVF_ISR_16:
\r
441 \ 000001B4 E000 LDI R16, 0
\r
442 \ 000001B6 .... RCALL SPI_Put
\r
443 \ 000001B8 C01B RJMP ??USI_OVF_ISR_4
\r
447 179 // Read byte from SPI
\r
448 180 SPI.Data = USIDR;
\r
449 \ ??USI_OVF_ISR_10:
\r
450 \ 000001BA B10F IN R16, 0x0F
\r
451 \ 000001BC 9110.... LDS R17, SPI
\r
452 \ 000001C0 9300.... STS SPI, R16
\r
454 182 // ********************************************
\r
455 183 // THIS FUNCTION HAS NOT BEEN FULLY IMPLEMENTED
\r
456 184 // ********************************************
\r
458 186 // Save byte to specified variable.
\r
459 187 switch (SPI.Address) {
\r
460 \ 000001C4 9100.... LDS R16, (SPI + 1)
\r
461 \ 000001C8 5004 SUBI R16, 4
\r
462 \ 000001CA F491 BRNE ??USI_OVF_ISR_4
\r
463 188 case ADR_BATTCTRL:
\r
464 189 *((__eeprom unsigned char*)&BattControl + SPI.Count) = SPI.Data;
\r
465 \ 000001CC 9100.... LDS R16, SPI
\r
466 \ 000001D0 9120.... LDS R18, (SPI + 2)
\r
467 \ 000001D4 732F ANDI R18, 0x3F
\r
468 \ 000001D6 E030 LDI R19, 0
\r
469 \ 000001D8 .... LDI R20, LOW(BattControl)
\r
470 \ 000001DA .... LDI R21, (BattControl) >> 8
\r
471 \ 000001DC 0F42 ADD R20, R18
\r
472 \ 000001DE 1F53 ADC R21, R19
\r
473 \ 000001E0 .... RCALL __eeput8_16
\r
474 \ 000001E2 C006 RJMP ??USI_OVF_ISR_4
\r
485 200 SPI.State = ST_CMD;
\r
487 \ 000001E4 9100.... LDS R16, (SPI + 2)
\r
488 \ 000001E8 730F ANDI R16, 0x3F
\r
489 \ 000001EA 6400 ORI R16, 0x40
\r
490 \ 000001EC 9300.... STS (SPI + 2), R16
\r
494 204 default: // Shouldn't end up here. (Unknown SPI-state)
\r
499 \ 000001F0 BFAF OUT 0x3F, R26
\r
500 \ 000001F2 9109 LD R16, Y+
\r
501 \ 000001F4 9119 LD R17, Y+
\r
502 \ 000001F6 9129 LD R18, Y+
\r
503 \ 000001F8 9139 LD R19, Y+
\r
504 \ 000001FA 9149 LD R20, Y+
\r
505 \ 000001FC 9159 LD R21, Y+
\r
506 \ 000001FE 9169 LD R22, Y+
\r
507 \ 00000200 9179 LD R23, Y+
\r
508 \ 00000202 9009 LD R0, Y+
\r
509 \ 00000204 9019 LD R1, Y+
\r
510 \ 00000206 9029 LD R2, Y+
\r
511 \ 00000208 9039 LD R3, Y+
\r
512 \ 0000020A 91E9 LD R30, Y+
\r
513 \ 0000020C 91F9 LD R31, Y+
\r
514 \ 0000020E 9189 LD R24, Y+
\r
515 \ 00000210 9199 LD R25, Y+
\r
516 \ 00000212 91A9 LD R26, Y+
\r
517 \ 00000214 9518 RETI
\r
518 \ 00000216 REQUIRE _A_USIDR
\r
519 \ 00000216 REQUIRE _A_USISR
\r
522 210 /*! \brief Initializes USI as an SPI slave
\r
524 212 * Initializes USI as a 3-wire SPI slave using the pins specified in USI.h for
\r
525 213 * I/O and clock, and USI counter overflow interrupts enabled.\n
\r
526 214 * Also initializes the SPI status struct.
\r
528 216 * \param spi_mode Specifies if USI should trigger on positive (0) or negative
\r
529 217 * (1) edge of clock signal
\r
531 219 * \note Clears the stored data
\r
533 221 * \todo Timer should reset SPI protocol on timeout
\r
536 \ In segment CODE, align 2, keep-with-next
\r
537 223 void SPI_Init(unsigned char spi_mode)
\r
540 225 __disable_interrupt();
\r
541 \ 00000000 94F8 CLI
\r
543 227 // Configure outputs and inputs, enable pull-ups for DATAIN and CLOCK pins.
\r
544 228 USI_DIR_REG |= (1<<USI_DATAOUT_PIN);
\r
545 \ 00000002 9AB9 SBI 0x17, 0x01
\r
546 229 USI_DIR_REG &= ~((1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN));
\r
547 \ 00000004 B317 IN R17, 0x17
\r
548 \ 00000006 7F1A ANDI R17, 0xFA
\r
549 \ 00000008 BB17 OUT 0x17, R17
\r
550 230 USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN);
\r
551 \ 0000000A B318 IN R17, 0x18
\r
552 \ 0000000C 6015 ORI R17, 0x05
\r
553 \ 0000000E BB18 OUT 0x18, R17
\r
555 232 // Configure USI to 3-wire slave mode with overflow interrupt
\r
556 233 USICR = ( (1<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (spi_mode<<USICS0) );
\r
557 \ 00000010 2F10 MOV R17, R16
\r
558 \ 00000012 0F11 LSL R17
\r
559 \ 00000014 0F11 LSL R17
\r
560 \ 00000016 6518 ORI R17, 0x58
\r
561 \ 00000018 B91D OUT 0x0D, R17
\r
563 235 // Initialize the SPI struct
\r
564 236 SPI.Data = 0; // Clear data.
\r
565 \ 0000001A E010 LDI R17, 0
\r
566 \ 0000001C 9310.... STS SPI, R17
\r
567 237 SPI.State = ST_CMD; // Initial SPI state: wait for command.
\r
568 \ 00000020 9110.... LDS R17, (SPI + 2)
\r
569 \ 00000024 731F ANDI R17, 0x3F
\r
570 \ 00000026 6410 ORI R17, 0x40
\r
571 \ 00000028 9310.... STS (SPI + 2), R17
\r
572 238 SPI.Read = FALSE; // Doesn't matter right now.
\r
573 \ 0000002C .... LDI R30, LOW(SPI)
\r
574 \ 0000002E .... LDI R31, (SPI) >> 8
\r
575 \ 00000030 8113 LDD R17, Z+3
\r
576 \ 00000032 7F1E ANDI R17, 0xFE
\r
577 \ 00000034 8313 STD Z+3, R17
\r
578 239 SPI.EEPROM = FALSE; // Doesn't matter right now.
\r
579 \ 00000036 .... LDI R30, LOW(SPI)
\r
580 \ 00000038 .... LDI R31, (SPI) >> 8
\r
581 \ 0000003A 8113 LDD R17, Z+3
\r
582 \ 0000003C 7F1D ANDI R17, 0xFD
\r
583 \ 0000003E 8313 STD Z+3, R17
\r
584 240 SPI.Count = 0; // Doesn't matter right now.
\r
585 \ 00000040 .... LDI R30, LOW(SPI)
\r
586 \ 00000042 .... LDI R31, (SPI) >> 8
\r
587 \ 00000044 8112 LDD R17, Z+2
\r
588 \ 00000046 7C10 ANDI R17, 0xC0
\r
589 \ 00000048 8312 STD Z+2, R17
\r
590 241 SPI.Address = 0; // Doesn't matter right now.
\r
591 \ 0000004A E010 LDI R17, 0
\r
592 \ 0000004C 9310.... STS (SPI + 1), R17
\r
593 242 SPI.XferComplete = FALSE; // We haven't even started a transfer yet.
\r
594 \ 00000050 .... LDI R30, LOW(SPI)
\r
595 \ 00000052 .... LDI R31, (SPI) >> 8
\r
596 \ 00000054 8113 LDD R17, Z+3
\r
597 \ 00000056 7F1B ANDI R17, 0xFB
\r
598 \ 00000058 8313 STD Z+3, R17
\r
599 243 SPI.WriteCollision = FALSE; // ..And therefore a collision hasn't happened.
\r
600 \ 0000005A .... LDI R30, LOW(SPI)
\r
601 \ 0000005C .... LDI R31, (SPI) >> 8
\r
602 \ 0000005E 8113 LDD R17, Z+3
\r
603 \ 00000060 7F17 ANDI R17, 0xF7
\r
604 \ 00000062 8313 STD Z+3, R17
\r
606 245 __enable_interrupt();
\r
607 \ 00000064 9478 SEI
\r
609 \ 00000066 9508 RET
\r
610 \ 00000068 REQUIRE _A_PORTB
\r
611 \ 00000068 REQUIRE _A_DDRB
\r
612 \ 00000068 REQUIRE _A_USICR
\r
615 249 // Put one byte on bus. Use this function like you would write to the SPDR
\r
616 250 // register in the native SPI module. Calling this function will prepare a
\r
617 251 // byte for the next transfer initiated by the master device. If a transfer
\r
618 252 // is in progress, this function will set the write collision flag and return
\r
619 253 // without altering the data registers.
\r
621 255 // Returns 0 if a write collision occurred, 1 otherwise.
\r
622 256 /*! \brief Write a byte to SPI bus
\r
624 258 * This function first checks if a transmission is in progress, and if so, flags
\r
625 259 * a write collision, and returns FALSE.\n
\r
626 260 * If a transmission is not in progress, the flags for write collision and
\r
627 261 * transfer complete are cleared, and the input byte is written to SPDR.\n
\r
629 263 * \param val The byte to send.
\r
631 265 * \retval FALSE A write collision happened.
\r
632 266 * \retval TRUE Byte written to SPDR.
\r
635 \ In segment CODE, align 2, keep-with-next
\r
636 268 unsigned char SPI_Put(unsigned char val)
\r
639 \ 00000000 2F10 MOV R17, R16
\r
640 270 // Check if transmission in progress, i.e. if USI counter doesn't equal zero.
\r
641 271 // If this fails, flag a write collision and return.
\r
642 272 if((USISR & 0x0F) != 0) {
\r
643 \ 00000002 B10E IN R16, 0x0E
\r
644 \ 00000004 700F ANDI R16, 0x0F
\r
645 \ 00000006 2300 TST R16
\r
646 \ 00000008 F039 BREQ ??SPI_Put_0
\r
647 273 SPI.WriteCollision = TRUE;
\r
648 \ 0000000A .... LDI R30, LOW(SPI)
\r
649 \ 0000000C .... LDI R31, (SPI) >> 8
\r
650 \ 0000000E 8103 LDD R16, Z+3
\r
651 \ 00000010 6008 ORI R16, 0x08
\r
652 \ 00000012 8303 STD Z+3, R16
\r
654 \ 00000014 E000 LDI R16, 0
\r
655 \ 00000016 9508 RET
\r
658 277 // Reinitialize flags.
\r
659 278 SPI.XferComplete = FALSE;
\r
661 \ 00000018 .... LDI R30, LOW(SPI)
\r
662 \ 0000001A .... LDI R31, (SPI) >> 8
\r
663 \ 0000001C 8103 LDD R16, Z+3
\r
664 \ 0000001E 7F0B ANDI R16, 0xFB
\r
665 \ 00000020 8303 STD Z+3, R16
\r
666 279 SPI.WriteCollision = FALSE;
\r
667 \ 00000022 .... LDI R30, LOW(SPI)
\r
668 \ 00000024 .... LDI R31, (SPI) >> 8
\r
669 \ 00000026 8103 LDD R16, Z+3
\r
670 \ 00000028 7F07 ANDI R16, 0xF7
\r
671 \ 0000002A 8303 STD Z+3, R16
\r
673 281 USIDR = val; // Put data in USI data register.
\r
674 \ 0000002C B91F OUT 0x0F, R17
\r
677 \ 0000002E E001 LDI R16, 1
\r
678 \ 00000030 9508 RET
\r
679 \ 00000032 REQUIRE _A_USIDR
\r
680 \ 00000032 REQUIRE _A_USISR
\r
684 287 // Get one byte from bus. This function only returns the previous stored
\r
685 288 // USIDR value. The transfer complete flag is not checked. Use this function
\r
686 289 // like you would read from the SPDR register in the native SPI module.
\r
687 290 /*! \brief Get the last byte received from SPI bus
\r
689 292 * This function simply returns the last byte stored to the SPI status struct,
\r
690 293 * without checking if a completed transfer is flagged.
\r
692 295 * \retval SPI.Data The last byte read from SPI.
\r
695 \ In segment CODE, align 2, keep-with-next
\r
696 297 unsigned char SPI_Get(void)
\r
699 299 return SPI.Data;
\r
700 \ 00000000 9100.... LDS R16, SPI
\r
701 \ 00000004 9508 RET
\r
705 303 /*! \brief Wait for SPI transfer to complete
\r
707 305 * This function waits for a transfer complete to be flagged.
\r
710 \ In segment CODE, align 2, keep-with-next
\r
711 307 void SPI_Wait(void)
\r
715 309 do { // Wait for transfer complete.
\r
716 310 } while (SPI.XferComplete == FALSE);
\r
717 \ 00000000 .... LDI R30, LOW(SPI)
\r
718 \ 00000002 .... LDI R31, (SPI) >> 8
\r
719 \ 00000004 8103 LDD R16, Z+3
\r
720 \ 00000006 FF02 SBRS R16, 2
\r
721 \ 00000008 CFFB RJMP ??SPI_Wait_0
\r
723 \ 0000000A 9508 RET
\r
725 \ In segment INTVEC, offset 0x10, root
\r
726 \ `??USI_OVF_ISR??INTVEC 16`:
\r
727 \ 00000010 .... RJMP USI_OVF_ISR
\r
729 Maximum stack usage in bytes:
\r
731 Function CSTACK RSTACK
\r
732 -------- ------ ------
\r
750 Segment part sizes:
\r
752 Function/Label Bytes
\r
753 -------------- -----
\r
765 ??USI_OVF_ISR??INTVEC 16 2
\r
769 5 bytes in segment ABSOLUTE
\r
770 706 bytes in segment CODE
\r
771 6 bytes in segment INITTAB
\r
772 2 bytes in segment INTVEC
\r
773 4 bytes in segment NEAR_Z
\r
775 706 bytes of CODE memory (+ 8 bytes shared)
\r
776 4 bytes of DATA memory (+ 5 bytes shared)
\r