USI.h File Reference


Detailed Description

Headerfile for USI.c.

Contains definitions of which I/O-register and pins to use, communication states, and a declaration of the SPI status struct.

Application note:
AVR458: Charging Li-Ion Batteries with BC100
AVR463: Charging NiMH Batteries with BC100
Documentation:
For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html
Author:
Atmel Corporation: http://www.atmel.com
Support email: avr@atmel.com
$Name$
Revision
2335
$RCSfile$
URL
http://revisor.norway.atmel.com/AppsAVR8/avr458_Charging_Li-Ion_Batteries_with_BC100/trunk/code/IAR/USI.h
Date
2007-09-07 10:11:19 +0200 (fr, 07 sep 2007)

Definition in file USI.h.

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SPI_Status_struct
 Holds SPI status and data. More...

Defines

#define USI_CLOCK_PIN   PB2
 USI clock I/O pin.
#define USI_DATAIN_PIN   PB0
 USI data input pin.
#define USI_DATAOUT_PIN   PB1
 USI data output pin.
#define USI_DIR_REG   DDRB
 USI port direction register.
#define USI_IN_REG   PINB
 USI port input register.
#define USI_OUT_REG   PORTB
 USI port output register.

Typedefs

typedef struct SPI_Status_struct SPI_Status_t
 For convenience.

Enumerations

enum  { ST_CMD = 1, ST_ADDR, ST_DATA }

Functions

unsigned char SPI_Get (void)
 Get the last byte received from SPI bus.
void SPI_Init (unsigned char spi_mode)
 Initializes USI as an SPI slave.
unsigned char SPI_Put (unsigned char val)
 Write a byte to SPI bus.
void SPI_Wait (void)
 Wait for SPI transfer to complete.
__interrupt void USI_OVF_ISR (void)
 USI Counter Overflow Interrupt Service Routine.


Define Documentation

#define USI_CLOCK_PIN   PB2

USI clock I/O pin.

Definition at line 38 of file USI.h.

Referenced by SPI_Init().

#define USI_DATAIN_PIN   PB0

USI data input pin.

Definition at line 39 of file USI.h.

Referenced by SPI_Init().

#define USI_DATAOUT_PIN   PB1

USI data output pin.

Definition at line 40 of file USI.h.

Referenced by SPI_Init().

#define USI_DIR_REG   DDRB

USI port direction register.

Definition at line 37 of file USI.h.

Referenced by SPI_Init().

#define USI_IN_REG   PINB

USI port input register.

Definition at line 36 of file USI.h.

#define USI_OUT_REG   PORTB

USI port output register.

Definition at line 35 of file USI.h.

Referenced by SPI_Init().


Typedef Documentation

For convenience.

Definition at line 78 of file USI.h.


Enumeration Type Documentation

anonymous enum

Enumerator:
ST_CMD  USI/SPI command state.
ST_ADDR  USI/SPI address state.
ST_DATA  USI/SPI data state.

Definition at line 46 of file USI.h.

00046      {
00047         ST_CMD = 1,  
00048         ST_ADDR,     
00049         ST_DATA      
00050 };


Function Documentation

unsigned char SPI_Get ( void   ) 

Get the last byte received from SPI bus.

This function simply returns the last byte stored to the SPI status struct, without checking if a completed transfer is flagged.

Return values:
SPI.Data The last byte read from SPI.

Definition at line 297 of file USI.c.

References SPI_Status_struct::Data.

00298 {
00299         return SPI.Data;
00300 }

void SPI_Init ( unsigned char  spi_mode  ) 

Initializes USI as an SPI slave.

Initializes USI as a 3-wire SPI slave using the pins specified in USI.h for I/O and clock, and USI counter overflow interrupts enabled.
Also initializes the SPI status struct.

Parameters:
spi_mode Specifies if USI should trigger on positive (0) or negative (1) edge of clock signal
Note:
Clears the stored data
Todo:
Timer should reset SPI protocol on timeout

Definition at line 223 of file USI.c.

References SPI_Status_struct::Address, SPI_Status_struct::Count, SPI_Status_struct::Data, SPI_Status_struct::EEPROM, FALSE, SPI_Status_struct::Read, ST_CMD, SPI_Status_struct::State, USI_CLOCK_PIN, USI_DATAIN_PIN, USI_DATAOUT_PIN, USI_DIR_REG, USI_OUT_REG, SPI_Status_struct::WriteCollision, and SPI_Status_struct::XferComplete.

Referenced by Initialize().

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 }

unsigned char SPI_Put ( unsigned char  val  ) 

Write a byte to SPI bus.

This function first checks if a transmission is in progress, and if so, flags a write collision, and returns FALSE.
If a transmission is not in progress, the flags for write collision and transfer complete are cleared, and the input byte is written to SPDR.

Parameters:
val The byte to send.
Return values:
FALSE A write collision happened.
TRUE Byte written to SPDR.

Definition at line 268 of file USI.c.

References FALSE, TRUE, SPI_Status_struct::WriteCollision, and SPI_Status_struct::XferComplete.

Referenced by USI_OVF_ISR().

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 }

void SPI_Wait ( void   ) 

Wait for SPI transfer to complete.

This function waits for a transfer complete to be flagged.

Definition at line 307 of file USI.c.

References FALSE, and SPI_Status_struct::XferComplete.

00308 {
00309         do {  // Wait for transfer complete.
00310         } while (SPI.XferComplete == FALSE);
00311 }

__interrupt void USI_OVF_ISR ( void   ) 

USI Counter Overflow Interrupt Service Routine.

When the USI counter overflows, a byte has been transferred.
The USIDR contents are stored and flags are updated.

The protocol is quite simple and has three sequential states: command, address and data. (Keep in mind that the Master is in charge of data clocking, which means there is a one byte "delay" from when the Slave puts something to SPI till the Master can read it.)

1. If a non-zero byte is received in the command state, the ISR will store the commands to the SPI struct (read/write, EEPROM/SRAM, number of bytes). To signal that the command was received, 0xCC is put to the SPI bus. If a zero byte (0x00) is received in the command state, it is simply ignored because it is an invalid command.

2. When a byte is received in the address state, it is stored to the SPI struct. To signal that the address was received, 0xBB is put to SPI bus.

3. In the data state, variables are read/written "from back to front" until the byte counter reaches zero. Since the Master is in charge of the data clocking, the Slave will go to command state before the last byte is transferred during reading. This means that the Master should send an invalid command when getting each byte, ie 0x00.

If the time between two transfers is 1 second or more, the Slave automatically reverts to command state.

Note:
Battery charging is not automatically halted during SPI communication. This means that the current charge state (current and voltage) will remain constant during heavy and prolonged serial traffic.
Todo:
Variable writing not implemented yet.
Todo:
EEPROM/SRAM flag doesn't really do anything with this implementation.

Definition at line 90 of file USI.c.

References ADCS, SPI_Status_struct::Address, ADR_ADCS, ADR_BATTACTIVE, ADR_BATTCTRL, ADR_BATTDATA, ADR_TIMERS, BattActive, BattControl, BattData, SPI_Status_struct::Count, SPI_Status_struct::Data, SPI_Status_struct::EEPROM, FALSE, SPI_Status_struct::Read, SPI_Put(), ST_ADDR, ST_CMD, ST_DATA, SPI_Status_struct::State, Time_Left(), Time_Set(), TIMER_USI, timeval, TRUE, and SPI_Status_struct::XferComplete.

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 }

Here is the call graph for this function:


Generated on Fri Jul 25 12:42:36 2008 for AVR458 Charging Li-Ion Batteries with ATAVRBC100 by  doxygen 1.5.6