00001 /* This file has been prepared for Doxygen automatic documentation generation.*/ 00030 #include <ioavr.h> 00031 #include <inavr.h> 00032 00033 #include "enums.h" 00034 #include "structs.h" 00035 00036 #include "main.h" 00037 #include "ADC.h" 00038 #include "battery.h" 00039 #include "time.h" 00040 #include "USI.h" 00041 00042 00043 //****************************************************************************** 00044 // Variables 00045 //****************************************************************************** 00047 SPI_Status_t SPI; 00048 00049 00050 //****************************************************************************** 00051 //Functions 00052 //***************************************************************************** 00089 #pragma vector=USI_OVF_vect 00090 __interrupt void USI_OVF_ISR(void) 00091 { 00092 // If the communication timed out, set ST_CMD as current state. 00093 if (!Time_Left(TIMER_USI)) { 00094 SPI.State = ST_CMD; 00095 } 00096 00097 // Start communication timer. If further communication doesn't happen 00098 // within 1 second, the SPI communication state is reset to CMD. 00099 Time_Set(TIMER_USI, 0, 1, 0); 00100 00101 // Clear USI counter and flag completed transfer. 00102 USISR = (1<<USIOIF); 00103 SPI.XferComplete = TRUE; 00104 00105 // Process incoming data. 00106 switch(SPI.State) { 00107 // A valid SPI transfer starts with a Command Byte sent by the Master. 00108 case ST_CMD: 00109 SPI.Data = USIDR; // Store the transferred byte. 00110 00111 // If the master sent 0, it is trying to get data. Ignore in this state. 00112 if (SPI.Data != 0) { 00113 // Does the master want to read or write? 00114 if (SPI.Data & 0x40) { 00115 SPI.Read = FALSE; 00116 } else { 00117 SPI.Read = TRUE; 00118 } 00119 00120 // From/to EEPROM or SRAM? 00121 if (SPI.Data &0x80) { 00122 SPI.EEPROM = TRUE; 00123 } else { 00124 SPI.EEPROM = FALSE; 00125 } 00126 00127 SPI.Count = (SPI.Data & 0x3F); // Get number of bytes to receive/send. 00128 SPI.State = ST_ADDR; // The Master will send the address byte next. 00129 00130 SPI_Put(0xCC); // Signal that command was received. 00131 } 00132 break; 00133 00134 00135 case ST_ADDR: 00136 SPI.Data = USIDR; // Store the address. 00137 SPI.Address = SPI.Data; 00138 SPI.State = ST_DATA; // The master will send/wait for data next. 00139 00140 SPI_Put(0xBB); // Signal that address was received. 00141 break; 00142 00143 00144 // Note well: this will process at least one byte, regardless of Count. 00145 case ST_DATA: 00146 if (SPI.Count-- > 0) { 00147 // Write specified variable to SPI, "back to front". 00148 if (SPI.Read) { 00149 switch (SPI.Address) { 00150 case ADR_ADCS: 00151 SPI_Put(*(((unsigned char*)&ADCS) + (SPI.Count))); 00152 break; 00153 00154 00155 case ADR_BATTACTIVE: 00156 SPI_Put(*((unsigned char*)&BattActive + (SPI.Count))); 00157 break; 00158 00159 00160 case ADR_BATTDATA: 00161 SPI_Put(*((unsigned char*)&BattData + (SPI.Count))); 00162 break; 00163 00164 00165 case ADR_BATTCTRL: 00166 SPI_Put(*((__eeprom unsigned char*)&BattControl + (SPI.Count))); 00167 break; 00168 00169 case ADR_TIMERS: 00170 SPI_Put(*((unsigned char*)&timeval + (SPI.Count))); 00171 break; 00172 00173 00174 default: 00175 SPI_Put(0); 00176 break; 00177 } 00178 } else { 00179 // Read byte from SPI 00180 SPI.Data = USIDR; 00181 00182 // ******************************************** 00183 // THIS FUNCTION HAS NOT BEEN FULLY IMPLEMENTED 00184 // ******************************************** 00185 00186 // Save byte to specified variable. 00187 switch (SPI.Address) { 00188 case ADR_BATTCTRL: 00189 *((__eeprom unsigned char*)&BattControl + SPI.Count) = SPI.Data; 00190 break; 00191 00192 00193 default: 00194 break; 00195 } 00196 } 00197 00198 00199 } else { 00200 SPI.State = ST_CMD; 00201 } 00202 break; 00203 00204 default: // Shouldn't end up here. (Unknown SPI-state) 00205 break; 00206 } 00207 } 00208 00209 00223 void SPI_Init(unsigned char spi_mode) 00224 { 00225 __disable_interrupt(); 00226 00227 // Configure outputs and inputs, enable pull-ups for DATAIN and CLOCK pins. 00228 USI_DIR_REG |= (1<<USI_DATAOUT_PIN); 00229 USI_DIR_REG &= ~((1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN)); 00230 USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN); 00231 00232 // Configure USI to 3-wire slave mode with overflow interrupt 00233 USICR = ( (1<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (spi_mode<<USICS0) ); 00234 00235 // Initialize the SPI struct 00236 SPI.Data = 0; // Clear data. 00237 SPI.State = ST_CMD; // Initial SPI state: wait for command. 00238 SPI.Read = FALSE; // Doesn't matter right now. 00239 SPI.EEPROM = FALSE; // Doesn't matter right now. 00240 SPI.Count = 0; // Doesn't matter right now. 00241 SPI.Address = 0; // Doesn't matter right now. 00242 SPI.XferComplete = FALSE; // We haven't even started a transfer yet. 00243 SPI.WriteCollision = FALSE; // ..And therefore a collision hasn't happened. 00244 00245 __enable_interrupt(); 00246 } 00247 00248 00249 // Put one byte on bus. Use this function like you would write to the SPDR 00250 // register in the native SPI module. Calling this function will prepare a 00251 // byte for the next transfer initiated by the master device. If a transfer 00252 // is in progress, this function will set the write collision flag and return 00253 // without altering the data registers. 00254 // 00255 // Returns 0 if a write collision occurred, 1 otherwise. 00268 unsigned char SPI_Put(unsigned char val) 00269 { 00270 // Check if transmission in progress, i.e. if USI counter doesn't equal zero. 00271 // If this fails, flag a write collision and return. 00272 if((USISR & 0x0F) != 0) { 00273 SPI.WriteCollision = TRUE; 00274 return(FALSE); 00275 } 00276 00277 // Reinitialize flags. 00278 SPI.XferComplete = FALSE; 00279 SPI.WriteCollision = FALSE; 00280 00281 USIDR = val; // Put data in USI data register. 00282 00283 return (TRUE); 00284 } 00285 00286 00287 // Get one byte from bus. This function only returns the previous stored 00288 // USIDR value. The transfer complete flag is not checked. Use this function 00289 // like you would read from the SPDR register in the native SPI module. 00297 unsigned char SPI_Get(void) 00298 { 00299 return SPI.Data; 00300 } 00301 00302 00307 void SPI_Wait(void) 00308 { 00309 do { // Wait for transfer complete. 00310 } while (SPI.XferComplete == FALSE); 00311 }