Initial import
[avr_bc100.git] / BaseTinyFirmware / IAR / Release / List / USI.s90
1 ///////////////////////////////////////////////////////////////////////////////\r
2 //                                                                            /\r
3 // IAR Atmel AVR C/C++ Compiler V4.30F/W32              13/Mar/2008  04:52:02 /\r
4 // Copyright 1996-2007 IAR Systems. All rights reserved.                      /\r
5 //                                                                            /\r
6 //    Source file           =  C:\home\kevin\pub\src\bc100\IAR\USI.c          /\r
7 //    Command line          =  C:\home\kevin\pub\src\bc100\IAR\USI.c          /\r
8 //                             --cpu=tiny861 -ms -o C:\home\kevin\pub\src\bc1 /\r
9 //                             00\IAR\Release\Obj\ -D NDEBUG -lCN             /\r
10 //                             C:\home\kevin\pub\src\bc100\IAR\Release\List\  /\r
11 //                             -lB C:\home\kevin\pub\src\bc100\IAR\Release\Li /\r
12 //                             st\ --initializers_in_flash -s9                /\r
13 //                             --no_cross_call --no_tbaa                      /\r
14 //                             -DENABLE_BIT_DEFINITIONS -e -I "C:\Program     /\r
15 //                             Files\IAR Systems\Embedded Workbench           /\r
16 //                             4.0\avr\INC\" -I "C:\Program Files\IAR         /\r
17 //                             Systems\Embedded Workbench 4.0\avr\INC\CLIB\"  /\r
18 //                             --eeprom_size 512 --misrac=5-9,11-12,14,16-17, /\r
19 //                             19-21,24-26,29-32,34-35,38-39,42-43,46,50,     /\r
20 //                             52-54,56-59,61-62,64-65,68-80,83-84,87-91,     /\r
21 //                             94-95,98-100,103-110,112-126                   /\r
22 //    Enabled MISRA C rules =  5-9,11-12,14,16-17,19-21,24-26,29-32,34-35,    /\r
23 //                             38-39,42-43,46,50,52-54,56-59,61-62,64-65,     /\r
24 //                             68-80,83-84,87-91,94-95,98-100,103-110,112-126 /\r
25 //      Checked             =  5,7-9,11-12,14,17,19-21,24,29-32,34-35,38-39,  /\r
26 //                             42,46,50,52-54,56-59,61-62,64,68-69,71-80,     /\r
27 //                             83-84,87-89,91,94-95,98,100,104-105,108-109,   /\r
28 //                             112-115,118-126                                /\r
29 //      Not checked         =  6,16,25-26,43,65,70,90,99,103,106-107,110,     /\r
30 //                             116-117                                        /\r
31 //    List file             =  C:\home\kevin\pub\src\bc100\IAR\Release\List\U /\r
32 //                             SI.s90                                         /\r
33 //                                                                            /\r
34 //                                                                            /\r
35 ///////////////////////////////////////////////////////////////////////////////\r
36 \r
37         NAME USI\r
38 \r
39         RSEG CSTACK:DATA:NOROOT(0)\r
40         RSEG RSTACK:DATA:NOROOT(0)\r
41 \r
42         EXTERN ?need_segment_init\r
43         EXTERN __eeget8_16\r
44         EXTERN __eeput8_16\r
45 \r
46         PUBWEAK `?<Segment init: NEAR_Z>`\r
47         PUBWEAK `??USI_OVF_ISR??INTVEC 16`\r
48         PUBLIC SPI\r
49         PUBLIC SPI_Get\r
50         PUBLIC SPI_Init\r
51         PUBLIC SPI_Put\r
52         PUBLIC SPI_Wait\r
53         PUBLIC USI_OVF_ISR\r
54         PUBWEAK _A_DDRB\r
55         PUBWEAK _A_PORTB\r
56         PUBWEAK _A_USICR\r
57         PUBWEAK _A_USIDR\r
58         PUBWEAK _A_USISR\r
59         PUBWEAK __?EEARH\r
60         PUBWEAK __?EEARL\r
61         PUBWEAK __?EECR\r
62         PUBWEAK __?EEDR\r
63 \r
64 USI_OVF_ISR         SYMBOL "USI_OVF_ISR"\r
65 `??USI_OVF_ISR??INTVEC 16` SYMBOL "??INTVEC 16", USI_OVF_ISR\r
66 \r
67         EXTERN Time_Left\r
68         EXTERN Time_Set\r
69         EXTERN ADCS\r
70         EXTERN BattActive\r
71         EXTERN BattControl\r
72         EXTERN BattData\r
73         EXTERN timeval\r
74 \r
75 // C:\home\kevin\pub\src\bc100\IAR\USI.c\r
76 //    1 /* This file has been prepared for Doxygen automatic documentation generation.*/\r
77 //    2 /*! \file *********************************************************************\r
78 //    3  *\r
79 //    4  * \brief\r
80 //    5  *      Functions for use of the Universal Serial Interface\r
81 //    6  *\r
82 //    7  *      Contains high level functions for initializing the USI as an SPI slave,\r
83 //    8  *      interrupt handling, sending and receiving single bytes.\r
84 //    9  *\r
85 //   10  * \par Application note:\r
86 //   11  *      AVR458: Charging Li-Ion Batteries with BC100 \n\r
87 //   12  *      AVR463: Charging NiMH Batteries with BC100\r
88 //   13  *\r
89 //   14  * \par Documentation:\r
90 //   15  *      For comprehensive code documentation, supported compilers, compiler\r
91 //   16  *      settings and supported devices see readme.html\r
92 //   17  *\r
93 //   18  * \author\r
94 //   19  *      Atmel Corporation: http://www.atmel.com \n\r
95 //   20  *      Support email: avr@atmel.com \n\r
96 //   21  *      Original author: \n\r
97 //   22  *\r
98 //   23  * $Name$\r
99 //   24  * $Revision: 2299 $\r
100 //   25  * $RCSfile$\r
101 //   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
102 //   27  * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n\r
103 //   28  ******************************************************************************/\r
104 //   29 \r
105 //   30 #include <ioavr.h>\r
106 \r
107         ASEGN ABSOLUTE:DATA:NOROOT,038H\r
108 // <unnamed> volatile __io _A_PORTB\r
109 _A_PORTB:\r
110         DS 1\r
111 \r
112         ASEGN ABSOLUTE:DATA:NOROOT,037H\r
113 // <unnamed> volatile __io _A_DDRB\r
114 _A_DDRB:\r
115         DS 1\r
116 \r
117         ASEGN ABSOLUTE:DATA:NOROOT,02fH\r
118 // <unnamed> volatile __io _A_USIDR\r
119 _A_USIDR:\r
120         DS 1\r
121 \r
122         ASEGN ABSOLUTE:DATA:NOROOT,02eH\r
123 // <unnamed> volatile __io _A_USISR\r
124 _A_USISR:\r
125         DS 1\r
126 \r
127         ASEGN ABSOLUTE:DATA:NOROOT,02dH\r
128 // <unnamed> volatile __io _A_USICR\r
129 _A_USICR:\r
130         DS 1\r
131 //   31 #include <inavr.h>\r
132 //   32 \r
133 //   33 #include "enums.h"\r
134 //   34 #include "structs.h"\r
135 //   35 \r
136 //   36 #include "main.h"\r
137 //   37 #include "ADC.h"\r
138 //   38 #include "battery.h"\r
139 //   39 #include "time.h"\r
140 //   40 #include "USI.h"\r
141 //   41 \r
142 //   42 \r
143 //   43 //******************************************************************************\r
144 //   44 // Variables\r
145 //   45 //******************************************************************************\r
146 //   46 //! SPI status struct\r
147 \r
148         RSEG NEAR_Z:DATA:NOROOT(0)\r
149         REQUIRE `?<Segment init: NEAR_Z>`\r
150 //   47 SPI_Status_t SPI;\r
151 SPI:\r
152         DS 4\r
153 //   48 \r
154 //   49 \r
155 //   50 //******************************************************************************\r
156 //   51 //Functions\r
157 //   52 //*****************************************************************************\r
158 //   53 /*! \brief USI Counter Overflow Interrupt Service Routine\r
159 //   54  *\r
160 //   55  * When the USI counter overflows, a byte has been transferred.\n\r
161 //   56  * The USIDR contents are stored and flags are updated.\r
162 //   57  *\r
163 //   58  * The protocol is quite simple and has three sequential states: command,\r
164 //   59  * address and data.\r
165 //   60  * (Keep in mind that the Master is in charge of data clocking, which means\r
166 //   61  * there is a one byte "delay" from when the Slave puts something to SPI till\r
167 //   62  * the Master can read it.)\r
168 //   63  *\r
169 //   64  * 1. If a non-zero byte is received in the command state, the ISR will\r
170 //   65  * store the commands to the SPI struct (read/write, EEPROM/SRAM, number of\r
171 //   66  * bytes). To signal that the command was received, 0xCC is put to the SPI bus.\r
172 //   67  * If a zero byte (0x00) is received in the command state, it is simply ignored\r
173 //   68  * because it is an invalid command.\r
174 //   69  *\r
175 //   70  * 2. When a byte is received in the address state, it is stored to the SPI\r
176 //   71  * struct. To signal that the address was received, 0xBB is put to SPI bus.\r
177 //   72  * \r
178 //   73  * 3. In the data state, variables are read/written "from back to front" until\r
179 //   74  * the byte counter reaches zero. Since the Master is in charge of the data\r
180 //   75  * clocking, the Slave will go to command state before the last byte is\r
181 //   76  * transferred during reading. This means that the Master should send an \r
182 //   77  * invalid command when getting each byte, ie 0x00.\r
183 //   78  *\r
184 //   79  * If the time between two transfers is 1 second or more, the Slave\r
185 //   80  * automatically reverts to command state.\r
186 //   81  *\r
187 //   82  * \note Battery charging is not automatically halted during SPI communication.\r
188 //   83  * This means that the current charge state (current and voltage) will\r
189 //   84  * remain constant during heavy and prolonged serial traffic.\r
190 //   85  *\r
191 //   86  * \todo Variable writing not implemented yet.\r
192 //   87  * \todo EEPROM/SRAM flag doesn't really do anything with this implementation.\r
193 //   88  */\r
194 //   89 #pragma vector=USI_OVF_vect\r
195 \r
196         RSEG CODE:CODE:NOROOT(1)\r
197 //   90 __interrupt void USI_OVF_ISR(void)\r
198 USI_OVF_ISR:\r
199 //   91 {\r
200         ST      -Y, R24\r
201         ST      -Y, R31\r
202         ST      -Y, R30\r
203         ST      -Y, R3\r
204         ST      -Y, R2\r
205         ST      -Y, R1\r
206         ST      -Y, R0\r
207         ST      -Y, R23\r
208         ST      -Y, R22\r
209         ST      -Y, R21\r
210         ST      -Y, R20\r
211         ST      -Y, R19\r
212         ST      -Y, R18\r
213         ST      -Y, R17\r
214         ST      -Y, R16\r
215         IN      R24, 0x3F\r
216 //   92         // If the communication timed out, set ST_CMD as current state.\r
217 //   93         if (!Time_Left(TIMER_USI)) {\r
218         LDI     R16, 0\r
219         RCALL   Time_Left\r
220         TST     R16\r
221         BRNE    ??USI_OVF_ISR_0\r
222 //   94                 SPI.State = ST_CMD;\r
223         LDI     R30, LOW(SPI)\r
224         LDI     R31, (SPI) >> 8\r
225         LDD     R16, Z+2\r
226         ANDI    R16, 0x3F\r
227         ORI     R16, 0x40\r
228         STD     Z+2, R16\r
229 //   95         }\r
230 //   96 \r
231 //   97         // Start communication timer. If further communication doesn't happen\r
232 //   98         // within 1 second, the SPI communication state is reset to CMD.\r
233 //   99         Time_Set(TIMER_USI, 0, 1, 0);\r
234 ??USI_OVF_ISR_0:\r
235         LDI     R20, 0\r
236         LDI     R17, 1\r
237         LDI     R18, 0\r
238         LDI     R19, 0\r
239         LDI     R16, 0\r
240         RCALL   Time_Set\r
241 //  100         \r
242 //  101         // Clear USI counter and flag completed transfer.\r
243 //  102         USISR = (1<<USIOIF);\r
244         LDI     R16, 64\r
245         OUT     0x0E, R16\r
246 //  103         SPI.XferComplete = TRUE;\r
247         LDI     R30, LOW(SPI)\r
248         LDI     R31, (SPI) >> 8\r
249         LDD     R16, Z+3\r
250         ORI     R16, 0x04\r
251         STD     Z+3, R16\r
252 //  104         \r
253 //  105         // Process incoming data.\r
254 //  106         switch(SPI.State)       {\r
255         LDD     R17, Z+2\r
256         MOV     R16, R17\r
257         LSL     R16\r
258         ROL     R16\r
259         ROL     R16\r
260         ANDI    R16, 0x03\r
261         SUBI    R16, 1\r
262         BREQ    ??USI_OVF_ISR_1\r
263         DEC     R16\r
264         BREQ    ??USI_OVF_ISR_2\r
265         DEC     R16\r
266         BREQ    ??USI_OVF_ISR_3\r
267         RJMP    ??USI_OVF_ISR_4\r
268 //  107         // A valid SPI transfer starts with a Command Byte sent by the Master.\r
269 //  108         case ST_CMD:   \r
270 //  109                 SPI.Data = USIDR;  // Store the transferred byte.\r
271 ??USI_OVF_ISR_1:\r
272         IN      R16, 0x0F\r
273         ST      Z, R16\r
274 //  110                 \r
275 //  111                 // If the master sent 0, it is trying to get data. Ignore in this state.\r
276 //  112                 if (SPI.Data != 0) {\r
277         TST     R16\r
278         BRNE    $+2+2\r
279         RJMP    ??USI_OVF_ISR_4\r
280 //  113                         // Does the master want to read or write?\r
281 //  114                         if (SPI.Data & 0x40) {\r
282         SBRS    R16, 6\r
283         RJMP    ??USI_OVF_ISR_5\r
284 //  115                                 SPI.Read = FALSE;\r
285         LDD     R16, Z+3\r
286         ANDI    R16, 0xFE\r
287         RJMP    ??USI_OVF_ISR_6\r
288 //  116                         } else {\r
289 //  117                                 SPI.Read = TRUE;\r
290 ??USI_OVF_ISR_5:\r
291         LDD     R16, Z+3\r
292         ORI     R16, 0x01\r
293 ??USI_OVF_ISR_6:\r
294         STD     Z+3, R16\r
295 //  118                         }\r
296 //  119 \r
297 //  120                                 // From/to EEPROM or SRAM?\r
298 //  121                         if (SPI.Data &0x80) {\r
299         LD      R16, Z\r
300         SBRS    R16, 7\r
301         RJMP    ??USI_OVF_ISR_7\r
302 //  122                                 SPI.EEPROM = TRUE;\r
303         LDD     R16, Z+3\r
304         ORI     R16, 0x02\r
305         RJMP    ??USI_OVF_ISR_8\r
306 //  123                         } else {\r
307 //  124                                 SPI.EEPROM = FALSE;\r
308 ??USI_OVF_ISR_7:\r
309         LDD     R16, Z+3\r
310         ANDI    R16, 0xFD\r
311 ??USI_OVF_ISR_8:\r
312         STD     Z+3, R16\r
313 //  125                         }\r
314 //  126 \r
315 //  127                         SPI.Count = (SPI.Data & 0x3F);  // Get number of bytes to receive/send.\r
316 //  128                         SPI.State = ST_ADDR;  // The Master will send the address byte next.\r
317         LD      R16, Z\r
318         ANDI    R16, 0x3F\r
319         ORI     R16, 0x80\r
320         STD     Z+2, R16\r
321 //  129 \r
322 //  130                         SPI_Put(0xCC);  // Signal that command was received.\r
323         LDI     R16, 204\r
324 ??USI_OVF_ISR_9:\r
325         RCALL   SPI_Put\r
326         RJMP    ??USI_OVF_ISR_4\r
327 //  131                 }\r
328 //  132         break;\r
329 //  133 \r
330 //  134                         \r
331 //  135         case ST_ADDR:  \r
332 //  136                 SPI.Data = USIDR;  // Store the address.\r
333 ??USI_OVF_ISR_2:\r
334         IN      R16, 0x0F\r
335         ST      Z, R16\r
336 //  137                 SPI.Address = SPI.Data;\r
337         STD     Z+1, R16\r
338 //  138                 SPI.State = ST_DATA;  // The master will send/wait for data next.\r
339         MOV     R16, R17\r
340         ORI     R16, 0xC0\r
341         STD     Z+2, R16\r
342 //  139 \r
343 //  140                 SPI_Put(0xBB);  // Signal that address was received.\r
344         LDI     R16, 187\r
345         RJMP    ??USI_OVF_ISR_9\r
346 //  141         break;\r
347 //  142 \r
348 //  143 \r
349 //  144         // Note well: this will process at least one byte, regardless of Count.\r
350 //  145         case ST_DATA:\r
351 //  146                 if (SPI.Count-- > 0) {\r
352 ??USI_OVF_ISR_3:\r
353         MOV     R18, R17\r
354         ANDI    R17, 0xC0\r
355         MOV     R16, R18\r
356         DEC     R16\r
357         ANDI    R16, 0x3F\r
358         OR      R16, R17\r
359         STD     Z+2, R16\r
360         ANDI    R18, 0x3F\r
361         BRNE    $+2+2\r
362         RJMP    ??USI_OVF_ISR_10\r
363 //  147                         // Write specified variable to SPI, "back to front".\r
364 //  148                         if (SPI.Read) {\r
365         LDD     R18, Z+1\r
366         LDD     R17, Z+3\r
367         SBRS    R17, 0\r
368         RJMP    ??USI_OVF_ISR_11\r
369 //  149                                 switch (SPI.Address) {\r
370         DEC     R18\r
371         BREQ    ??USI_OVF_ISR_12\r
372         DEC     R18\r
373         BREQ    ??USI_OVF_ISR_13\r
374         DEC     R18\r
375         BREQ    ??USI_OVF_ISR_14\r
376         DEC     R18\r
377         BREQ    ??USI_OVF_ISR_15\r
378         DEC     R18\r
379         BREQ    ??USI_OVF_ISR_16\r
380         RJMP    ??USI_OVF_ISR_17\r
381 //  150                                 case ADR_ADCS:\r
382 //  151                                         SPI_Put(*(((unsigned char*)&ADCS) + (SPI.Count)));\r
383 ??USI_OVF_ISR_12:\r
384         ANDI    R16, 0x3F\r
385         LDI     R17, 0\r
386         MOVW    R31:R30, R17:R16\r
387         SUBI    R30, LOW((-(ADCS) & 0xFFFF))\r
388         SBCI    R31, (-(ADCS) & 0xFFFF) >> 8\r
389 ??USI_OVF_ISR_18:\r
390         LD      R16, Z\r
391         RJMP    ??USI_OVF_ISR_9\r
392 //  152                                 break;\r
393 //  153                                 \r
394 //  154                                 \r
395 //  155                                 case ADR_BATTACTIVE:\r
396 //  156                                         SPI_Put(*((unsigned char*)&BattActive + (SPI.Count)));\r
397 ??USI_OVF_ISR_13:\r
398         ANDI    R16, 0x3F\r
399         LDI     R17, 0\r
400         MOVW    R31:R30, R17:R16\r
401         SUBI    R30, LOW((-(BattActive) & 0xFFFF))\r
402         SBCI    R31, (-(BattActive) & 0xFFFF) >> 8\r
403         RJMP    ??USI_OVF_ISR_18\r
404 //  157                                 break;\r
405 //  158                                 \r
406 //  159                                 \r
407 //  160                                 case ADR_BATTDATA:\r
408 //  161                                         SPI_Put(*((unsigned char*)&BattData + (SPI.Count)));\r
409 ??USI_OVF_ISR_14:\r
410         ANDI    R16, 0x3F\r
411         LDI     R17, 0\r
412         MOVW    R31:R30, R17:R16\r
413         SUBI    R30, LOW((-(BattData) & 0xFFFF))\r
414         SBCI    R31, (-(BattData) & 0xFFFF) >> 8\r
415         RJMP    ??USI_OVF_ISR_18\r
416 //  162                                 break;\r
417 //  163                                 \r
418 //  164                                 \r
419 //  165                                 case ADR_BATTCTRL:\r
420 //  166                                         SPI_Put(*((__eeprom unsigned char*)&BattControl + (SPI.Count)));\r
421 ??USI_OVF_ISR_15:\r
422         ANDI    R16, 0x3F\r
423         LDI     R17, 0\r
424         LDI     R20, LOW(BattControl)\r
425         LDI     R21, (BattControl) >> 8\r
426         ADD     R20, R16\r
427         ADC     R21, R17\r
428         RCALL   __eeget8_16\r
429         RJMP    ??USI_OVF_ISR_9\r
430 //  167                                 break;\r
431 //  168                                 \r
432 //  169                                 case ADR_TIMERS:\r
433 //  170                                         SPI_Put(*((unsigned char*)&timeval + (SPI.Count)));\r
434 ??USI_OVF_ISR_16:\r
435         ANDI    R16, 0x3F\r
436         LDI     R17, 0\r
437         MOVW    R31:R30, R17:R16\r
438         SUBI    R30, LOW((-(timeval) & 0xFFFF))\r
439         SBCI    R31, (-(timeval) & 0xFFFF) >> 8\r
440         RJMP    ??USI_OVF_ISR_18\r
441 //  171                                 break;\r
442 //  172 \r
443 //  173                                 \r
444 //  174                                 default:\r
445 //  175                                         SPI_Put(0);\r
446 ??USI_OVF_ISR_17:\r
447         LDI     R16, 0\r
448         RJMP    ??USI_OVF_ISR_9\r
449 //  176                                 break;\r
450 //  177                                 }\r
451 //  178                         } else {\r
452 //  179                                 // Read byte from SPI\r
453 //  180                                 SPI.Data = USIDR;\r
454 ??USI_OVF_ISR_11:\r
455         IN      R17, 0x0F\r
456         ST      Z, R17\r
457 //  181 \r
458 //  182                                 // ********************************************\r
459 //  183                                 // THIS FUNCTION HAS NOT BEEN FULLY IMPLEMENTED\r
460 //  184                                 // ********************************************\r
461 //  185                                                                 \r
462 //  186                                 // Save byte to specified variable.\r
463 //  187                                 switch (SPI.Address) {\r
464         SUBI    R18, 4\r
465         BRNE    ??USI_OVF_ISR_4\r
466 //  188                                 case ADR_BATTCTRL:\r
467 //  189                                         *((__eeprom unsigned char*)&BattControl + SPI.Count) = SPI.Data;\r
468         MOV     R18, R17\r
469         ANDI    R16, 0x3F\r
470         LDI     R17, 0\r
471         LDI     R20, LOW(BattControl)\r
472         LDI     R21, (BattControl) >> 8\r
473         ADD     R20, R16\r
474         ADC     R21, R17\r
475         MOV     R16, R18\r
476         RCALL   __eeput8_16\r
477         RJMP    ??USI_OVF_ISR_4\r
478 //  190                                 break;\r
479 //  191 \r
480 //  192                                 \r
481 //  193                                 default:\r
482 //  194                                 break;\r
483 //  195                                 }\r
484 //  196                         }\r
485 //  197                         \r
486 //  198 \r
487 //  199                 } else {\r
488 //  200                         SPI.State = ST_CMD;\r
489 ??USI_OVF_ISR_10:\r
490         ANDI    R16, 0x3F\r
491         ORI     R16, 0x40\r
492         STD     Z+2, R16\r
493 //  201                 }\r
494 //  202         break;\r
495 //  203 \r
496 //  204         default:  // Shouldn't end up here. (Unknown SPI-state)\r
497 //  205         break;\r
498 //  206         }\r
499 //  207 }\r
500 ??USI_OVF_ISR_4:\r
501         OUT     0x3F, R24\r
502         LD      R16, Y+\r
503         LD      R17, Y+\r
504         LD      R18, Y+\r
505         LD      R19, Y+\r
506         LD      R20, Y+\r
507         LD      R21, Y+\r
508         LD      R22, Y+\r
509         LD      R23, Y+\r
510         LD      R0, Y+\r
511         LD      R1, Y+\r
512         LD      R2, Y+\r
513         LD      R3, Y+\r
514         LD      R30, Y+\r
515         LD      R31, Y+\r
516         LD      R24, Y+\r
517         RETI\r
518         REQUIRE _A_USIDR\r
519         REQUIRE _A_USISR\r
520 //  208 \r
521 //  209 \r
522 //  210 /*! \brief Initializes USI as an SPI slave\r
523 //  211  *\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
527 //  215  * \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
530 //  218  *\r
531 //  219  * \note Clears the stored data\r
532 //  220  *\r
533 //  221  * \todo Timer should reset SPI protocol on timeout\r
534 //  222  */\r
535 \r
536         RSEG CODE:CODE:NOROOT(1)\r
537 //  223 void SPI_Init(unsigned char spi_mode)\r
538 SPI_Init:\r
539 //  224 {\r
540 //  225         __disable_interrupt();\r
541         CLI\r
542 //  226         \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         SBI     0x17, 0x01\r
546 //  229         USI_DIR_REG &= ~((1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN));\r
547         IN      R17, 0x17\r
548         ANDI    R17, 0xFA\r
549         OUT     0x17, R17\r
550 //  230         USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN);\r
551         IN      R17, 0x18\r
552         ORI     R17, 0x05\r
553         OUT     0x18, R17\r
554 //  231         \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         LSL     R16\r
558         LSL     R16\r
559         ORI     R16, 0x58\r
560         OUT     0x0D, R16\r
561 //  234 \r
562 //  235         // Initialize the SPI struct\r
563 //  236         SPI.Data = 0;                 // Clear data.\r
564         LDI     R30, LOW(SPI)\r
565         LDI     R31, (SPI) >> 8\r
566         LDI     R16, 0\r
567         ST      Z, R16\r
568 //  237         SPI.State = ST_CMD;           // Initial SPI state: wait for command.\r
569 //  238         SPI.Read = FALSE;             // Doesn't matter right now.\r
570 //  239         SPI.EEPROM = FALSE;           // Doesn't matter right now.\r
571         LDD     R16, Z+3\r
572         ANDI    R16, 0xFC\r
573         STD     Z+3, R16\r
574 //  240         SPI.Count = 0;                // Doesn't matter right now.\r
575         LDI     R16, 64\r
576         STD     Z+2, R16\r
577 //  241         SPI.Address = 0;              // Doesn't matter right now.\r
578         LDI     R16, 0\r
579         STD     Z+1, R16\r
580 //  242         SPI.XferComplete = FALSE;     // We haven't even started a transfer yet.\r
581 //  243         SPI.WriteCollision = FALSE;   // ..And therefore a collision hasn't happened.\r
582         LDD     R16, Z+3\r
583         ANDI    R16, 0xF3\r
584         STD     Z+3, R16\r
585 //  244 \r
586 //  245         __enable_interrupt();\r
587         SEI\r
588 //  246 }\r
589         RET\r
590         REQUIRE _A_PORTB\r
591         REQUIRE _A_DDRB\r
592         REQUIRE _A_USICR\r
593 //  247 \r
594 //  248 \r
595 //  249 // Put one byte on bus. Use this function like you would write to the SPDR\r
596 //  250 // register in the native SPI module. Calling this function will prepare a\r
597 //  251 // byte for the next transfer initiated by the master device. If a transfer\r
598 //  252 // is in progress, this function will set the write collision flag and return\r
599 //  253 // without altering the data registers.\r
600 //  254 //\r
601 //  255 // Returns 0 if a write collision occurred, 1 otherwise.\r
602 //  256 /*! \brief Write a byte to SPI bus\r
603 //  257  *\r
604 //  258  * This function first checks if a transmission is in progress, and if so, flags\r
605 //  259  * a write collision, and returns FALSE.\n\r
606 //  260  * If a transmission is not in progress, the flags for write collision and\r
607 //  261  * transfer complete are cleared, and the input byte is written to SPDR.\n\r
608 //  262  *\r
609 //  263  * \param val The byte to send.\r
610 //  264  *\r
611 //  265  * \retval FALSE A write collision happened.\r
612 //  266  * \retval TRUE Byte written to SPDR.\r
613 //  267  */\r
614 \r
615         RSEG CODE:CODE:NOROOT(1)\r
616 //  268 unsigned char SPI_Put(unsigned char val)\r
617 SPI_Put:\r
618 //  269 {\r
619 //  270         // Check if transmission in progress, i.e. if USI counter doesn't equal zero.\r
620 //  271         // If this fails, flag a write collision and return.\r
621 //  272         if((USISR & 0x0F) != 0) {\r
622         IN      R17, 0x0E\r
623         ANDI    R17, 0x0F\r
624         LDI     R30, LOW(SPI)\r
625         LDI     R31, (SPI) >> 8\r
626         BREQ    ??SPI_Put_0\r
627 //  273                 SPI.WriteCollision = TRUE;\r
628         LDD     R16, Z+3\r
629         ORI     R16, 0x08\r
630         STD     Z+3, R16\r
631 //  274                 return(FALSE);\r
632         LDI     R16, 0\r
633         RET\r
634 //  275         }\r
635 //  276 \r
636 //  277         // Reinitialize flags.\r
637 //  278         SPI.XferComplete = FALSE;\r
638 //  279         SPI.WriteCollision = FALSE;\r
639 ??SPI_Put_0:\r
640         LDD     R17, Z+3\r
641         ANDI    R17, 0xF3\r
642         STD     Z+3, R17\r
643 //  280 \r
644 //  281         USIDR = val;  // Put data in USI data register.\r
645         OUT     0x0F, R16\r
646 //  282 \r
647 //  283         return (TRUE);\r
648         LDI     R16, 1\r
649         RET\r
650         REQUIRE _A_USIDR\r
651         REQUIRE _A_USISR\r
652 //  284 }\r
653 //  285 \r
654 //  286 \r
655 //  287 // Get one byte from bus. This function only returns the previous stored\r
656 //  288 // USIDR value. The transfer complete flag is not checked. Use this function\r
657 //  289 // like you would read from the SPDR register in the native SPI module.\r
658 //  290 /*! \brief Get the last byte received from SPI bus\r
659 //  291  *\r
660 //  292  * This function simply returns the last byte stored to the SPI status struct,\r
661 //  293  * without checking if a completed transfer is flagged.\r
662 //  294  *\r
663 //  295  * \retval SPI.Data The last byte read from SPI.\r
664 //  296  */\r
665 \r
666         RSEG CODE:CODE:NOROOT(1)\r
667 //  297 unsigned char SPI_Get(void)\r
668 SPI_Get:\r
669 //  298 {\r
670 //  299         return SPI.Data;\r
671         LDS     R16, SPI\r
672         RET\r
673 //  300 }\r
674 //  301 \r
675 //  302 \r
676 //  303 /*! \brief Wait for SPI transfer to complete\r
677 //  304  *\r
678 //  305  * This function waits for a transfer complete to be flagged.\r
679 //  306  */\r
680 \r
681         RSEG CODE:CODE:NOROOT(1)\r
682 //  307 void SPI_Wait(void)\r
683 SPI_Wait:\r
684 //  308 {\r
685         LDS     R16, (SPI + 3)\r
686         SBRS    R16, 2\r
687 //  309         do {  // Wait for transfer complete.\r
688 //  310         } while (SPI.XferComplete == FALSE);\r
689 ??SPI_Wait_0:\r
690         RJMP    ??SPI_Wait_0\r
691 //  311 }\r
692 ??SPI_Wait_1:\r
693         RET\r
694 \r
695         ASEGN ABSOLUTE:DATA:NOROOT,01cH\r
696 __?EECR:\r
697 \r
698         ASEGN ABSOLUTE:DATA:NOROOT,01dH\r
699 __?EEDR:\r
700 \r
701         ASEGN ABSOLUTE:DATA:NOROOT,01eH\r
702 __?EEARL:\r
703 \r
704         ASEGN ABSOLUTE:DATA:NOROOT,01fH\r
705 __?EEARH:\r
706 \r
707         COMMON INTVEC:CODE:ROOT(1)\r
708         ORG 16\r
709 `??USI_OVF_ISR??INTVEC 16`:\r
710         RJMP    USI_OVF_ISR\r
711 \r
712         RSEG INITTAB:CODE:NOROOT(0)\r
713 `?<Segment init: NEAR_Z>`:\r
714         DW      SFE(NEAR_Z) - SFB(NEAR_Z)\r
715         DW      SFB(NEAR_Z)\r
716         DW      0\r
717         REQUIRE ?need_segment_init\r
718 \r
719         END\r
720 // \r
721 //   5 bytes in segment ABSOLUTE\r
722 // 470 bytes in segment CODE\r
723 //   6 bytes in segment INITTAB\r
724 //   2 bytes in segment INTVEC\r
725 //   4 bytes in segment NEAR_Z\r
726 // \r
727 // 470 bytes of CODE memory (+ 8 bytes shared)\r
728 //   4 bytes of DATA memory (+ 5 bytes shared)\r
729 //\r
730 //Errors: none\r
731 //Warnings: none\r