- Main Page
- Related Pages
- Data Structures
- Files

# 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 }