00001 // This file has been prepared for Doxygen automatic documentation generation. 00025 #include <avr/io.h> 00026 #include <avr/interrupt.h> 00027 00028 00029 /* USI port and pin definitions. 00030 */ 00031 #define USI_OUT_REG PORTB //!< USI port output register. 00032 #define USI_IN_REG PINE //!< USI port input register. 00033 #define USI_DIR_REG DDRB //!< USI port direction register. 00034 #define USI_CLOCK_PIN PB2 //!< USI clock I/O pin. 00035 #define USI_DATAIN_PIN PB1 //!< USI data input pin. 00036 #define USI_DATAOUT_PIN PB0 //!< USI data output pin. 00037 00038 00039 00040 00041 /* Speed configuration: 00042 * Bits per second = CPUSPEED / PRESCALER / (COMPAREVALUE+1) / 2. 00043 * Maximum = CPUSPEED / 64. 00044 */ 00045 #define TC0_PRESCALER_VALUE 256 //!< Must be 1, 8, 64, 256 or 1024. 00046 #define TC0_COMPARE_VALUE 1 //!< Must be 0 to 255. Minimum 31 with prescaler CLK/1. 00047 00048 00049 00050 00051 /* Prescaler value converted to bit settings. 00052 */ 00053 #if TC0_PRESCALER_VALUE == 1 00054 #define TC0_PS_SETTING (1<<CS00) 00055 #elif TC0_PRESCALER_VALUE == 8 00056 #define TC0_PS_SETTING (1<<CS01) 00057 #elif TC0_PRESCALER_VALUE == 64 00058 #define TC0_PS_SETTING (1<<CS01)|(1<<CS00) 00059 #elif TC0_PRESCALER_VALUE == 256 00060 #define TC0_PS_SETTING (1<<CS02) 00061 #elif TC0_PRESCALER_VALUE == 1024 00062 #define TC0_PS_SETTING (1<<CS02)|(1<<CS00) 00063 #else 00064 #error Invalid T/C0 prescaler setting. 00065 #endif 00066 00067 00068 00076 unsigned char storedUSIDR; 00077 00078 00079 00087 struct usidriverStatus_t { 00088 unsigned char masterMode : 1; 00089 unsigned char transferComplete : 1; 00090 unsigned char writeCollision : 1; 00091 }; 00092 00093 volatile struct usidriverStatus_t spiX_status; 00094 00095 00096 00103 #if 0 00104 ISR(SIG_OUTPUT_COMPARE1A) 00105 { 00106 USICR |= (1<<USITC); // Toggle clock output pin. 00107 } 00108 #endif //#if 0 00109 00110 00118 ISR(SIG_USI_OVERFLOW) 00119 { 00120 // Master must now disable the compare match interrupt 00121 // to prevent more USI counter clocks. 00122 if( spiX_status.masterMode == 1 ) { 00123 TIMSK &= ~(1<<OCIE0A); 00124 } 00125 00126 // Update flags and clear USI counter 00127 USISR = (1<<USIOIF); 00128 spiX_status.transferComplete = 1; 00129 00130 // Copy USIDR to buffer to prevent overwrite on next transfer. 00131 storedUSIDR = USIDR; 00132 } 00133 00134 00135 00144 void spiX_initmaster( char spi_mode ) 00145 { 00146 // Configure port directions. 00147 USI_DIR_REG |= (1<<USI_DATAOUT_PIN) | (1<<USI_CLOCK_PIN); // Outputs. 00148 USI_DIR_REG &= ~(1<<USI_DATAIN_PIN); // Inputs. 00149 USI_OUT_REG |= (1<<USI_DATAIN_PIN); // Pull-ups. 00150 00151 // Configure USI to 3-wire master mode with overflow interrupt. 00152 USICR = (1<<USIOIE) | (1<<USIWM0) | 00153 (1<<USICS1) | (spi_mode<<USICS0) | 00154 (1<<USICLK); 00155 00156 // Enable 'Clear Timer on Compare match' and init prescaler. 00157 TCCR0A = TC0_PS_SETTING; 00158 00159 //TCCR0A = (1<<WGM01); 00160 00161 // Init Output Compare Register. 00162 OCR0A = TC0_COMPARE_VALUE; 00163 00164 // Init driver status register. 00165 spiX_status.masterMode = 1; 00166 spiX_status.transferComplete = 0; 00167 spiX_status.writeCollision = 0; 00168 00169 storedUSIDR = 0; 00170 } 00171 00172 00173 00182 void spiX_initslave( char spi_mode ) 00183 { 00184 // Configure port directions. 00185 USI_DIR_REG |= (1<<USI_DATAOUT_PIN); // Outputs. 00186 USI_DIR_REG &= ~(1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN); // Inputs. 00187 USI_OUT_REG |= (1<<USI_DATAIN_PIN) | (1<<USI_CLOCK_PIN); // Pull-ups. 00188 00189 // Configure USI to 3-wire slave mode with overflow interrupt. 00190 USICR = (1<<USIOIE) | (1<<USIWM0) | 00191 (1<<USICS1) | (spi_mode<<USICS0); 00192 00193 // Init driver status register. 00194 spiX_status.masterMode = 0; 00195 spiX_status.transferComplete = 0; 00196 spiX_status.writeCollision = 0; 00197 00198 storedUSIDR = 0; 00199 } 00200 00201 00202 00213 char spiX_put( unsigned char val ) 00214 { 00215 // Check if transmission in progress, 00216 // i.e. USI counter unequal to zero. 00217 if( (USISR & 0x0F) != 0 ) { 00218 // Indicate write collision and return. 00219 spiX_status.writeCollision = 1; 00220 return 1; 00221 } 00222 00223 // Reinit flags. 00224 spiX_status.transferComplete = 0; 00225 spiX_status.writeCollision = 0; 00226 00227 // Put data in USI data register. 00228 USIDR = val; 00229 00230 // Master should now enable compare match interrupts. 00231 if( spiX_status.masterMode == 1 ) { 00232 TIFR |= (1<<OCF0A); // Clear compare match flag. 00233 TIMSK |= (1<<OCIE0A); // Enable compare match interrupt. 00234 } 00235 00236 if( spiX_status.writeCollision == 0 ) return 1; 00237 return 0; 00238 } 00239 00240 00241 00248 unsigned char spiX_get(void) 00249 { 00250 return storedUSIDR; 00251 } 00252 00253 00254 00260 void spiX_wait(void) 00261 { 00262 do {} while( spiX_status.transferComplete == 0 ); 00263 } 00264 00265 00266 00267 // end of file