USI.c

Go to the documentation of this file.
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 }

Generated on Tue Sep 4 19:17:55 2007 for AVR463 Charging NiMH Batteries with ATAVRBC100 by  doxygen 1.5.2