############################################################################### # # # IAR Atmel AVR C/C++ Compiler V4.30F/W32 12/Mar/2008 23:01:39 # # Copyright 1996-2007 IAR Systems. All rights reserved. # # # # Source file = C:\home\kevin\pub\src\bc100_cal\IAR\USI.c # # Command line = C:\home\kevin\pub\src\bc100_cal\IAR\USI.c --cpu=tiny861 # # -ms -o C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Obj\ # # -lC C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\ -lB # # C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\ # # --initializers_in_flash -z2 --no_cse --no_inline # # --no_code_motion --no_cross_call --no_clustering # # --no_tbaa --debug -DENABLE_BIT_DEFINITIONS -e # # --require_prototypes -I "C:\Program Files\IAR # # Systems\Embedded Workbench 4.0\avr\INC\" -I "C:\Program # # Files\IAR Systems\Embedded Workbench 4.0\avr\INC\CLIB\" # # --eeprom_size 512 # # List file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\List\USI.lst # # Object file = C:\home\kevin\pub\src\bc100_cal\IAR\Debug\Obj\USI.r90 # # # # # ############################################################################### C:\home\kevin\pub\src\bc100_cal\IAR\USI.c 1 /* This file has been prepared for Doxygen automatic documentation generation.*/ 2 /*! \file ********************************************************************* 3 * 4 * \brief 5 * Functions for use of the Universal Serial Interface 6 * 7 * Contains high level functions for initializing the USI as an SPI slave, 8 * interrupt handling, sending and receiving single bytes. 9 * 10 * \par Application note: 11 * AVR458: Charging Li-Ion Batteries with BC100 \n 12 * AVR463: Charging NiMH Batteries with BC100 13 * 14 * \par Documentation: 15 * For comprehensive code documentation, supported compilers, compiler 16 * settings and supported devices see readme.html 17 * 18 * \author 19 * Atmel Corporation: http://www.atmel.com \n 20 * Support email: avr@atmel.com \n 21 * Original author: \n 22 * 23 * $Name$ 24 * $Revision: 2299 $ 25 * $RCSfile$ 26 * $URL: http://svn.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/tag/20070904_release_1.0/code/IAR/USI.c $ 27 * $Date: 2007-08-23 12:55:51 +0200 (to, 23 aug 2007) $\n 28 ******************************************************************************/ 29 30 #include \ In segment ABSOLUTE, at 0x38 \ volatile __io _A_PORTB \ _A_PORTB: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x37 \ volatile __io _A_DDRB \ _A_DDRB: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x2f \ volatile __io _A_USIDR \ _A_USIDR: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x2e \ volatile __io _A_USISR \ _A_USISR: \ 00000000 DS 1 \ In segment ABSOLUTE, at 0x2d \ volatile __io _A_USICR \ _A_USICR: \ 00000000 DS 1 31 #include 32 33 #include "enums.h" 34 #include "structs.h" 35 36 #include "main.h" 37 #include "ADC.h" 38 #include "battery.h" 39 #include "time.h" 40 #include "USI.h" 41 42 43 //****************************************************************************** 44 // Variables 45 //****************************************************************************** 46 //! SPI status struct \ In segment NEAR_Z, align 1, keep-with-next \ 00000000 REQUIRE `?` 47 SPI_Status_t SPI; \ SPI: \ 00000000 DS 4 48 49 50 //****************************************************************************** 51 //Functions 52 //***************************************************************************** 53 /*! \brief USI Counter Overflow Interrupt Service Routine 54 * 55 * When the USI counter overflows, a byte has been transferred.\n 56 * The USIDR contents are stored and flags are updated. 57 * 58 * The protocol is quite simple and has three sequential states: command, 59 * address and data. 60 * (Keep in mind that the Master is in charge of data clocking, which means 61 * there is a one byte "delay" from when the Slave puts something to SPI till 62 * the Master can read it.) 63 * 64 * 1. If a non-zero byte is received in the command state, the ISR will 65 * store the commands to the SPI struct (read/write, EEPROM/SRAM, number of 66 * bytes). To signal that the command was received, 0xCC is put to the SPI bus. 67 * If a zero byte (0x00) is received in the command state, it is simply ignored 68 * because it is an invalid command. 69 * 70 * 2. When a byte is received in the address state, it is stored to the SPI 71 * struct. To signal that the address was received, 0xBB is put to SPI bus. 72 * 73 * 3. In the data state, variables are read/written "from back to front" until 74 * the byte counter reaches zero. Since the Master is in charge of the data 75 * clocking, the Slave will go to command state before the last byte is 76 * transferred during reading. This means that the Master should send an 77 * invalid command when getting each byte, ie 0x00. 78 * 79 * If the time between two transfers is 1 second or more, the Slave 80 * automatically reverts to command state. 81 * 82 * \note Battery charging is not automatically halted during SPI communication. 83 * This means that the current charge state (current and voltage) will 84 * remain constant during heavy and prolonged serial traffic. 85 * 86 * \todo Variable writing not implemented yet. 87 * \todo EEPROM/SRAM flag doesn't really do anything with this implementation. 88 */ 89 #pragma vector=USI_OVF_vect \ In segment CODE, align 2, keep-with-next 90 __interrupt void USI_OVF_ISR(void) \ USI_OVF_ISR: 91 { \ 00000000 93AA ST -Y, R26 \ 00000002 939A ST -Y, R25 \ 00000004 938A ST -Y, R24 \ 00000006 93FA ST -Y, R31 \ 00000008 93EA ST -Y, R30 \ 0000000A 923A ST -Y, R3 \ 0000000C 922A ST -Y, R2 \ 0000000E 921A ST -Y, R1 \ 00000010 920A ST -Y, R0 \ 00000012 937A ST -Y, R23 \ 00000014 936A ST -Y, R22 \ 00000016 935A ST -Y, R21 \ 00000018 934A ST -Y, R20 \ 0000001A 933A ST -Y, R19 \ 0000001C 932A ST -Y, R18 \ 0000001E 931A ST -Y, R17 \ 00000020 930A ST -Y, R16 \ 00000022 B7AF IN R26, 0x3F 92 // If the communication timed out, set ST_CMD as current state. 93 if (!Time_Left(TIMER_USI)) { \ 00000024 E000 LDI R16, 0 \ 00000026 .... RCALL Time_Left \ 00000028 2300 TST R16 \ 0000002A F431 BRNE ??USI_OVF_ISR_0 94 SPI.State = ST_CMD; \ 0000002C 9100.... LDS R16, (SPI + 2) \ 00000030 730F ANDI R16, 0x3F \ 00000032 6400 ORI R16, 0x40 \ 00000034 9300.... STS (SPI + 2), R16 95 } 96 97 // Start communication timer. If further communication doesn't happen 98 // within 1 second, the SPI communication state is reset to CMD. 99 Time_Set(TIMER_USI, 0, 1, 0); \ ??USI_OVF_ISR_0: \ 00000038 E040 LDI R20, 0 \ 0000003A E011 LDI R17, 1 \ 0000003C E020 LDI R18, 0 \ 0000003E E030 LDI R19, 0 \ 00000040 E000 LDI R16, 0 \ 00000042 .... RCALL Time_Set 100 101 // Clear USI counter and flag completed transfer. 102 USISR = (1<> 8 \ 0000004C 8103 LDD R16, Z+3 \ 0000004E 6004 ORI R16, 0x04 \ 00000050 8303 STD Z+3, R16 104 105 // Process incoming data. 106 switch(SPI.State) { \ 00000052 9100.... LDS R16, (SPI + 2) \ 00000056 0F00 LSL R16 \ 00000058 1F00 ROL R16 \ 0000005A 1F00 ROL R16 \ 0000005C 7003 ANDI R16, 0x03 \ 0000005E 5001 SUBI R16, 1 \ 00000060 F039 BREQ ??USI_OVF_ISR_1 \ 00000062 950A DEC R16 \ 00000064 F409 BRNE $+2+2 \ 00000066 C040 RJMP ??USI_OVF_ISR_2 \ 00000068 950A DEC R16 \ 0000006A F409 BRNE $+2+2 \ 0000006C C050 RJMP ??USI_OVF_ISR_3 \ 0000006E C0C0 RJMP ??USI_OVF_ISR_4 107 // A valid SPI transfer starts with a Command Byte sent by the Master. 108 case ST_CMD: 109 SPI.Data = USIDR; // Store the transferred byte. \ ??USI_OVF_ISR_1: \ 00000070 B10F IN R16, 0x0F \ 00000072 9110.... LDS R17, SPI \ 00000076 9300.... STS SPI, R16 110 111 // If the master sent 0, it is trying to get data. Ignore in this state. 112 if (SPI.Data != 0) { \ 0000007A 9100.... LDS R16, SPI \ 0000007E 2300 TST R16 \ 00000080 F409 BRNE $+2+2 \ 00000082 C0B6 RJMP ??USI_OVF_ISR_4 113 // Does the master want to read or write? 114 if (SPI.Data & 0x40) { \ 00000084 .... LDI R30, LOW(SPI) \ 00000086 .... LDI R31, (SPI) >> 8 \ 00000088 8100 LD R16, Z \ 0000008A FF06 SBRS R16, 6 \ 0000008C C006 RJMP ??USI_OVF_ISR_5 115 SPI.Read = FALSE; \ 0000008E .... LDI R30, LOW(SPI) \ 00000090 .... LDI R31, (SPI) >> 8 \ 00000092 8103 LDD R16, Z+3 \ 00000094 7F0E ANDI R16, 0xFE \ 00000096 8303 STD Z+3, R16 \ 00000098 C005 RJMP ??USI_OVF_ISR_6 116 } else { 117 SPI.Read = TRUE; \ ??USI_OVF_ISR_5: \ 0000009A .... LDI R30, LOW(SPI) \ 0000009C .... LDI R31, (SPI) >> 8 \ 0000009E 8103 LDD R16, Z+3 \ 000000A0 6001 ORI R16, 0x01 \ 000000A2 8303 STD Z+3, R16 118 } 119 120 // From/to EEPROM or SRAM? 121 if (SPI.Data &0x80) { \ ??USI_OVF_ISR_6: \ 000000A4 .... LDI R30, LOW(SPI) \ 000000A6 .... LDI R31, (SPI) >> 8 \ 000000A8 8100 LD R16, Z \ 000000AA FF07 SBRS R16, 7 \ 000000AC C006 RJMP ??USI_OVF_ISR_7 122 SPI.EEPROM = TRUE; \ 000000AE .... LDI R30, LOW(SPI) \ 000000B0 .... LDI R31, (SPI) >> 8 \ 000000B2 8103 LDD R16, Z+3 \ 000000B4 6002 ORI R16, 0x02 \ 000000B6 8303 STD Z+3, R16 \ 000000B8 C005 RJMP ??USI_OVF_ISR_8 123 } else { 124 SPI.EEPROM = FALSE; \ ??USI_OVF_ISR_7: \ 000000BA .... LDI R30, LOW(SPI) \ 000000BC .... LDI R31, (SPI) >> 8 \ 000000BE 8103 LDD R16, Z+3 \ 000000C0 7F0D ANDI R16, 0xFD \ 000000C2 8303 STD Z+3, R16 125 } 126 127 SPI.Count = (SPI.Data & 0x3F); // Get number of bytes to receive/send. \ ??USI_OVF_ISR_8: \ 000000C4 9110.... LDS R17, (SPI + 2) \ 000000C8 7C10 ANDI R17, 0xC0 \ 000000CA 9100.... LDS R16, SPI \ 000000CE 730F ANDI R16, 0x3F \ 000000D0 2B01 OR R16, R17 \ 000000D2 9300.... STS (SPI + 2), R16 128 SPI.State = ST_ADDR; // The Master will send the address byte next. \ 000000D6 9100.... LDS R16, (SPI + 2) \ 000000DA 730F ANDI R16, 0x3F \ 000000DC 6800 ORI R16, 0x80 \ 000000DE 9300.... STS (SPI + 2), R16 129 130 SPI_Put(0xCC); // Signal that command was received. \ 000000E2 EC0C LDI R16, 204 \ 000000E4 .... RCALL SPI_Put \ 000000E6 C084 RJMP ??USI_OVF_ISR_4 131 } 132 break; 133 134 135 case ST_ADDR: 136 SPI.Data = USIDR; // Store the address. \ ??USI_OVF_ISR_2: \ 000000E8 B10F IN R16, 0x0F \ 000000EA 9180.... LDS R24, SPI \ 000000EE 9300.... STS SPI, R16 137 SPI.Address = SPI.Data; \ 000000F2 9190.... LDS R25, (SPI + 1) \ 000000F6 9100.... LDS R16, SPI \ 000000FA 9300.... STS (SPI + 1), R16 138 SPI.State = ST_DATA; // The master will send/wait for data next. \ 000000FE .... LDI R30, LOW(SPI) \ 00000100 .... LDI R31, (SPI) >> 8 \ 00000102 8102 LDD R16, Z+2 \ 00000104 6C00 ORI R16, 0xC0 \ 00000106 8302 STD Z+2, R16 139 140 SPI_Put(0xBB); // Signal that address was received. \ 00000108 EB0B LDI R16, 187 \ 0000010A .... RCALL SPI_Put \ 0000010C C071 RJMP ??USI_OVF_ISR_4 141 break; 142 143 144 // Note well: this will process at least one byte, regardless of Count. 145 case ST_DATA: 146 if (SPI.Count-- > 0) { \ ??USI_OVF_ISR_3: \ 0000010E 9100.... LDS R16, (SPI + 2) \ 00000112 2F20 MOV R18, R16 \ 00000114 7C20 ANDI R18, 0xC0 \ 00000116 2F10 MOV R17, R16 \ 00000118 951A DEC R17 \ 0000011A 731F ANDI R17, 0x3F \ 0000011C 2B12 OR R17, R18 \ 0000011E 9310.... STS (SPI + 2), R17 \ 00000122 730F ANDI R16, 0x3F \ 00000124 3001 CPI R16, 1 \ 00000126 F408 BRCC $+2+2 \ 00000128 C05D RJMP ??USI_OVF_ISR_9 147 // Write specified variable to SPI, "back to front". 148 if (SPI.Read) { \ 0000012A .... LDI R30, LOW(SPI) \ 0000012C .... LDI R31, (SPI) >> 8 \ 0000012E 8103 LDD R16, Z+3 \ 00000130 FF00 SBRS R16, 0 \ 00000132 C043 RJMP ??USI_OVF_ISR_10 149 switch (SPI.Address) { \ 00000134 9100.... LDS R16, (SPI + 1) \ 00000138 5001 SUBI R16, 1 \ 0000013A F049 BREQ ??USI_OVF_ISR_11 \ 0000013C 950A DEC R16 \ 0000013E F089 BREQ ??USI_OVF_ISR_12 \ 00000140 950A DEC R16 \ 00000142 F0C9 BREQ ??USI_OVF_ISR_13 \ 00000144 950A DEC R16 \ 00000146 F109 BREQ ??USI_OVF_ISR_14 \ 00000148 950A DEC R16 \ 0000014A F151 BREQ ??USI_OVF_ISR_15 \ 0000014C C033 RJMP ??USI_OVF_ISR_16 150 case ADR_ADCS: 151 SPI_Put(*(((unsigned char*)&ADCS) + (SPI.Count))); \ ??USI_OVF_ISR_11: \ 0000014E 9100.... LDS R16, (SPI + 2) \ 00000152 730F ANDI R16, 0x3F \ 00000154 E010 LDI R17, 0 \ 00000156 01F8 MOVW R31:R30, R17:R16 \ 00000158 .... SUBI R30, LOW((-(ADCS) & 0xFFFF)) \ 0000015A .... SBCI R31, (-(ADCS) & 0xFFFF) >> 8 \ 0000015C 8100 LD R16, Z \ 0000015E .... RCALL SPI_Put \ 00000160 C047 RJMP ??USI_OVF_ISR_4 152 break; 153 154 155 case ADR_BATTACTIVE: 156 SPI_Put(*((unsigned char*)&BattActive + (SPI.Count))); \ ??USI_OVF_ISR_12: \ 00000162 9100.... LDS R16, (SPI + 2) \ 00000166 730F ANDI R16, 0x3F \ 00000168 E010 LDI R17, 0 \ 0000016A 01F8 MOVW R31:R30, R17:R16 \ 0000016C .... SUBI R30, LOW((-(BattActive) & 0xFFFF)) \ 0000016E .... SBCI R31, (-(BattActive) & 0xFFFF) >> 8 \ 00000170 8100 LD R16, Z \ 00000172 .... RCALL SPI_Put \ 00000174 C03D RJMP ??USI_OVF_ISR_4 157 break; 158 159 160 case ADR_BATTDATA: 161 SPI_Put(*((unsigned char*)&BattData + (SPI.Count))); \ ??USI_OVF_ISR_13: \ 00000176 9100.... LDS R16, (SPI + 2) \ 0000017A 730F ANDI R16, 0x3F \ 0000017C E010 LDI R17, 0 \ 0000017E 01F8 MOVW R31:R30, R17:R16 \ 00000180 .... SUBI R30, LOW((-(BattData) & 0xFFFF)) \ 00000182 .... SBCI R31, (-(BattData) & 0xFFFF) >> 8 \ 00000184 8100 LD R16, Z \ 00000186 .... RCALL SPI_Put \ 00000188 C033 RJMP ??USI_OVF_ISR_4 162 break; 163 164 165 case ADR_BATTCTRL: 166 SPI_Put(*((__eeprom unsigned char*)&BattControl + (SPI.Count))); \ ??USI_OVF_ISR_14: \ 0000018A 9100.... LDS R16, (SPI + 2) \ 0000018E 730F ANDI R16, 0x3F \ 00000190 E010 LDI R17, 0 \ 00000192 .... LDI R20, LOW(BattControl) \ 00000194 .... LDI R21, (BattControl) >> 8 \ 00000196 0F40 ADD R20, R16 \ 00000198 1F51 ADC R21, R17 \ 0000019A .... RCALL __eeget8_16 \ 0000019C .... RCALL SPI_Put \ 0000019E C028 RJMP ??USI_OVF_ISR_4 167 break; 168 169 case ADR_TIMERS: 170 SPI_Put(*((unsigned char*)&timeval + (SPI.Count))); \ ??USI_OVF_ISR_15: \ 000001A0 9100.... LDS R16, (SPI + 2) \ 000001A4 730F ANDI R16, 0x3F \ 000001A6 E010 LDI R17, 0 \ 000001A8 01F8 MOVW R31:R30, R17:R16 \ 000001AA .... SUBI R30, LOW((-(timeval) & 0xFFFF)) \ 000001AC .... SBCI R31, (-(timeval) & 0xFFFF) >> 8 \ 000001AE 8100 LD R16, Z \ 000001B0 .... RCALL SPI_Put \ 000001B2 C01E RJMP ??USI_OVF_ISR_4 171 break; 172 173 174 default: 175 SPI_Put(0); \ ??USI_OVF_ISR_16: \ 000001B4 E000 LDI R16, 0 \ 000001B6 .... RCALL SPI_Put \ 000001B8 C01B RJMP ??USI_OVF_ISR_4 176 break; 177 } 178 } else { 179 // Read byte from SPI 180 SPI.Data = USIDR; \ ??USI_OVF_ISR_10: \ 000001BA B10F IN R16, 0x0F \ 000001BC 9110.... LDS R17, SPI \ 000001C0 9300.... STS SPI, R16 181 182 // ******************************************** 183 // THIS FUNCTION HAS NOT BEEN FULLY IMPLEMENTED 184 // ******************************************** 185 186 // Save byte to specified variable. 187 switch (SPI.Address) { \ 000001C4 9100.... LDS R16, (SPI + 1) \ 000001C8 5004 SUBI R16, 4 \ 000001CA F491 BRNE ??USI_OVF_ISR_4 188 case ADR_BATTCTRL: 189 *((__eeprom unsigned char*)&BattControl + SPI.Count) = SPI.Data; \ 000001CC 9100.... LDS R16, SPI \ 000001D0 9120.... LDS R18, (SPI + 2) \ 000001D4 732F ANDI R18, 0x3F \ 000001D6 E030 LDI R19, 0 \ 000001D8 .... LDI R20, LOW(BattControl) \ 000001DA .... LDI R21, (BattControl) >> 8 \ 000001DC 0F42 ADD R20, R18 \ 000001DE 1F53 ADC R21, R19 \ 000001E0 .... RCALL __eeput8_16 \ 000001E2 C006 RJMP ??USI_OVF_ISR_4 190 break; 191 192 193 default: 194 break; 195 } 196 } 197 198 199 } else { 200 SPI.State = ST_CMD; \ ??USI_OVF_ISR_9: \ 000001E4 9100.... LDS R16, (SPI + 2) \ 000001E8 730F ANDI R16, 0x3F \ 000001EA 6400 ORI R16, 0x40 \ 000001EC 9300.... STS (SPI + 2), R16 201 } 202 break; 203 204 default: // Shouldn't end up here. (Unknown SPI-state) 205 break; 206 } 207 } \ ??USI_OVF_ISR_4: \ 000001F0 BFAF OUT 0x3F, R26 \ 000001F2 9109 LD R16, Y+ \ 000001F4 9119 LD R17, Y+ \ 000001F6 9129 LD R18, Y+ \ 000001F8 9139 LD R19, Y+ \ 000001FA 9149 LD R20, Y+ \ 000001FC 9159 LD R21, Y+ \ 000001FE 9169 LD R22, Y+ \ 00000200 9179 LD R23, Y+ \ 00000202 9009 LD R0, Y+ \ 00000204 9019 LD R1, Y+ \ 00000206 9029 LD R2, Y+ \ 00000208 9039 LD R3, Y+ \ 0000020A 91E9 LD R30, Y+ \ 0000020C 91F9 LD R31, Y+ \ 0000020E 9189 LD R24, Y+ \ 00000210 9199 LD R25, Y+ \ 00000212 91A9 LD R26, Y+ \ 00000214 9518 RETI \ 00000216 REQUIRE _A_USIDR \ 00000216 REQUIRE _A_USISR 208 209 210 /*! \brief Initializes USI as an SPI slave 211 * 212 * Initializes USI as a 3-wire SPI slave using the pins specified in USI.h for 213 * I/O and clock, and USI counter overflow interrupts enabled.\n 214 * Also initializes the SPI status struct. 215 * 216 * \param spi_mode Specifies if USI should trigger on positive (0) or negative 217 * (1) edge of clock signal 218 * 219 * \note Clears the stored data 220 * 221 * \todo Timer should reset SPI protocol on timeout 222 */ \ In segment CODE, align 2, keep-with-next 223 void SPI_Init(unsigned char spi_mode) \ SPI_Init: 224 { 225 __disable_interrupt(); \ 00000000 94F8 CLI 226 227 // Configure outputs and inputs, enable pull-ups for DATAIN and CLOCK pins. 228 USI_DIR_REG |= (1<> 8 \ 00000030 8113 LDD R17, Z+3 \ 00000032 7F1E ANDI R17, 0xFE \ 00000034 8313 STD Z+3, R17 239 SPI.EEPROM = FALSE; // Doesn't matter right now. \ 00000036 .... LDI R30, LOW(SPI) \ 00000038 .... LDI R31, (SPI) >> 8 \ 0000003A 8113 LDD R17, Z+3 \ 0000003C 7F1D ANDI R17, 0xFD \ 0000003E 8313 STD Z+3, R17 240 SPI.Count = 0; // Doesn't matter right now. \ 00000040 .... LDI R30, LOW(SPI) \ 00000042 .... LDI R31, (SPI) >> 8 \ 00000044 8112 LDD R17, Z+2 \ 00000046 7C10 ANDI R17, 0xC0 \ 00000048 8312 STD Z+2, R17 241 SPI.Address = 0; // Doesn't matter right now. \ 0000004A E010 LDI R17, 0 \ 0000004C 9310.... STS (SPI + 1), R17 242 SPI.XferComplete = FALSE; // We haven't even started a transfer yet. \ 00000050 .... LDI R30, LOW(SPI) \ 00000052 .... LDI R31, (SPI) >> 8 \ 00000054 8113 LDD R17, Z+3 \ 00000056 7F1B ANDI R17, 0xFB \ 00000058 8313 STD Z+3, R17 243 SPI.WriteCollision = FALSE; // ..And therefore a collision hasn't happened. \ 0000005A .... LDI R30, LOW(SPI) \ 0000005C .... LDI R31, (SPI) >> 8 \ 0000005E 8113 LDD R17, Z+3 \ 00000060 7F17 ANDI R17, 0xF7 \ 00000062 8313 STD Z+3, R17 244 245 __enable_interrupt(); \ 00000064 9478 SEI 246 } \ 00000066 9508 RET \ 00000068 REQUIRE _A_PORTB \ 00000068 REQUIRE _A_DDRB \ 00000068 REQUIRE _A_USICR 247 248 249 // Put one byte on bus. Use this function like you would write to the SPDR 250 // register in the native SPI module. Calling this function will prepare a 251 // byte for the next transfer initiated by the master device. If a transfer 252 // is in progress, this function will set the write collision flag and return 253 // without altering the data registers. 254 // 255 // Returns 0 if a write collision occurred, 1 otherwise. 256 /*! \brief Write a byte to SPI bus 257 * 258 * This function first checks if a transmission is in progress, and if so, flags 259 * a write collision, and returns FALSE.\n 260 * If a transmission is not in progress, the flags for write collision and 261 * transfer complete are cleared, and the input byte is written to SPDR.\n 262 * 263 * \param val The byte to send. 264 * 265 * \retval FALSE A write collision happened. 266 * \retval TRUE Byte written to SPDR. 267 */ \ In segment CODE, align 2, keep-with-next 268 unsigned char SPI_Put(unsigned char val) \ SPI_Put: 269 { \ 00000000 2F10 MOV R17, R16 270 // Check if transmission in progress, i.e. if USI counter doesn't equal zero. 271 // If this fails, flag a write collision and return. 272 if((USISR & 0x0F) != 0) { \ 00000002 B10E IN R16, 0x0E \ 00000004 700F ANDI R16, 0x0F \ 00000006 2300 TST R16 \ 00000008 F039 BREQ ??SPI_Put_0 273 SPI.WriteCollision = TRUE; \ 0000000A .... LDI R30, LOW(SPI) \ 0000000C .... LDI R31, (SPI) >> 8 \ 0000000E 8103 LDD R16, Z+3 \ 00000010 6008 ORI R16, 0x08 \ 00000012 8303 STD Z+3, R16 274 return(FALSE); \ 00000014 E000 LDI R16, 0 \ 00000016 9508 RET 275 } 276 277 // Reinitialize flags. 278 SPI.XferComplete = FALSE; \ ??SPI_Put_0: \ 00000018 .... LDI R30, LOW(SPI) \ 0000001A .... LDI R31, (SPI) >> 8 \ 0000001C 8103 LDD R16, Z+3 \ 0000001E 7F0B ANDI R16, 0xFB \ 00000020 8303 STD Z+3, R16 279 SPI.WriteCollision = FALSE; \ 00000022 .... LDI R30, LOW(SPI) \ 00000024 .... LDI R31, (SPI) >> 8 \ 00000026 8103 LDD R16, Z+3 \ 00000028 7F07 ANDI R16, 0xF7 \ 0000002A 8303 STD Z+3, R16 280 281 USIDR = val; // Put data in USI data register. \ 0000002C B91F OUT 0x0F, R17 282 283 return (TRUE); \ 0000002E E001 LDI R16, 1 \ 00000030 9508 RET \ 00000032 REQUIRE _A_USIDR \ 00000032 REQUIRE _A_USISR 284 } 285 286 287 // Get one byte from bus. This function only returns the previous stored 288 // USIDR value. The transfer complete flag is not checked. Use this function 289 // like you would read from the SPDR register in the native SPI module. 290 /*! \brief Get the last byte received from SPI bus 291 * 292 * This function simply returns the last byte stored to the SPI status struct, 293 * without checking if a completed transfer is flagged. 294 * 295 * \retval SPI.Data The last byte read from SPI. 296 */ \ In segment CODE, align 2, keep-with-next 297 unsigned char SPI_Get(void) \ SPI_Get: 298 { 299 return SPI.Data; \ 00000000 9100.... LDS R16, SPI \ 00000004 9508 RET 300 } 301 302 303 /*! \brief Wait for SPI transfer to complete 304 * 305 * This function waits for a transfer complete to be flagged. 306 */ \ In segment CODE, align 2, keep-with-next 307 void SPI_Wait(void) \ SPI_Wait: \ ??SPI_Wait_0: 308 { 309 do { // Wait for transfer complete. 310 } while (SPI.XferComplete == FALSE); \ 00000000 .... LDI R30, LOW(SPI) \ 00000002 .... LDI R31, (SPI) >> 8 \ 00000004 8103 LDD R16, Z+3 \ 00000006 FF02 SBRS R16, 2 \ 00000008 CFFB RJMP ??SPI_Wait_0 311 } \ 0000000A 9508 RET \ In segment INTVEC, offset 0x10, root \ `??USI_OVF_ISR??INTVEC 16`: \ 00000010 .... RJMP USI_OVF_ISR Maximum stack usage in bytes: Function CSTACK RSTACK -------- ------ ------ SPI_Get 0 2 SPI_Init 0 2 SPI_Put 0 2 SPI_Wait 0 2 USI_OVF_ISR 17 4 -> Time_Left 17 2 -> Time_Set 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 -> SPI_Put 17 2 Segment part sizes: Function/Label Bytes -------------- ----- _A_PORTB 1 _A_DDRB 1 _A_USIDR 1 _A_USISR 1 _A_USICR 1 SPI 4 USI_OVF_ISR 534 SPI_Init 104 SPI_Put 50 SPI_Get 6 ??SPI_Wait_0 12 ??USI_OVF_ISR??INTVEC 16 2 Others 6 5 bytes in segment ABSOLUTE 706 bytes in segment CODE 6 bytes in segment INITTAB 2 bytes in segment INTVEC 4 bytes in segment NEAR_Z 706 bytes of CODE memory (+ 8 bytes shared) 4 bytes of DATA memory (+ 5 bytes shared) Errors: none Warnings: none