NEW DATABASE - 350 MILLION DATASHEETS FROM 8500 MANUFACTURERS
AT91M63200 AT24C512 CH-1705 - Datasheet Archive
Serial EEPROM Introduction The Inter Integrated Circuit Bus (I²C Bus) is a simple bi-directional 2-wire, Serial Data (SDA)
AT91M63200 AT91M63200: I2C Drivers for AT24C512 AT24C512 Serial EEPROM Introduction The Inter Integrated Circuit Bus (I²C Bus) is a simple bi-directional 2-wire, Serial Data (SDA) and Serial Clock (SCL) Bus for inter-IC control. The AT91M63200 AT91M63200 does not have dedicated hardware to manage an I²C line, but because of its high processing speed, flexible Timer/Counters (TC) and efficient interrupt management, an effective software implementation can easily be done. This Application Note describes such an implementation compliant with ARM procedure call standard (APCS). It is intended for use with an AT24C512 AT24C512 serial EEPROM. AT91 ARM® Thumb® Microcontrollers Application Note Theory of Operation The industry-standard interface defined by I²C consists of the following signals: · GND: common reference · VCC: power supply · SCL: serial clocks .The positive edge of the SCL input is used to clock data into the EEPROM device and the negative edge clocks data out of the device. · SDA: serial data. The SDA pin is bi-directional for serial data transfer. Waveforms Figure 1. Clock and Data Transition: SDA SCL Data Stable Data Stable Data Change Rev. 1742A06/01 1 Figure 2. Start and Stop Condition SDA SCL Stop Start Figure 3. Acknowledge SCL 1 8 9 Data In SDA Data Out Start Acknowledge Figure 4. Write Operation S t a r t W r i t e Device Address SDA Line Second Word Address = n First Word Address = n Data [n] S t o p Data [n + z] 0 L R AM S / CS B WKB M S B L A S C B K A C K A C K A C K Figure 5. Read Operation S t a r t Device Address W r i t e 1st, 2nd Word Address = n S t a r t 0 SDA Line M S B Device Address R e a d S t o p Data [n] 0 L R AM S / CS BW K B LA SC BK L RA S / C B WK N 0 A C K Dummy Write 2 AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb AT91M63200 AT91M63200 Implementation This application note describes how to implement a I²C master device using an AT91M63200 AT91M63200 IC. A Timer/Counter channel and two PIO lines are used to manage the SCL and SDA lines. The bytes from the EEPROM are stored in a reception buffer. The writable bytes come from a transmission buffer. The Timer/Counter is clocked from its internal clock (MCK/2). The bit duration and sampling are generated by programing the register C (RC): The RC is set with the bit time value. In read and write mode, the counter is reset at each RC Compare event. Connection At reset, all PIO pins of the AT91M63200 AT91M63200 are programmed as inputs. Therefore, the SDA line must be connected to the supply voltage via a pull-up resistor. (Refer to the data sheet of the AT91M63200 AT91M63200 to get more details concerning the value of the pull-up resistors.) Figure 6. Hardware Connection Vcc Pull up PIOi EEPROM AT24C512 AT24C512 SDA PIOj SCL AT91M63200 AT91M63200 Source Files The following source files are provided to implement the AT91M63200 AT91M63200 I2C Driver: Table 1. Files stdio.h Standard C I/O definitions lib_m63200.h AT91M63200 AT91M63200 Library include file reg_m63200.h AT91M63200 AT91M63200 Registers include file lib_i2c.h I²C line types and constants lib_i2c.c Transmission/Reception interrupt handlers test_i2c.c I²C EEPROM drivers i2c_irq.s Peripheral Drivers Contents Assembler Interrupt handler For each peripheral used (Timer/Counter, advanced interrupt controller, etc.), a structure is defined to provide easy access to the peripheral registers. Constants are also defined to provide easy access to the register fields. These peripherals and constants are defined in lib_m63200.h 3 1742A06/01 Global Variables Global variables relative to the I²C line are grouped in a structure (I2Cdesc), type defined in lib_i2c.h, a portion of which is reproduced below. Extract From lib_i2c.h This structure groups timer characteristics, PIO characteristics, buffer pointers, working variables and interrupt handler addresses (AIC handler and C handler). typedef struct I2C { //* Buffers u_char *RxBase; u_char *RxPtr; u_char *RxEnd; u_char *TxPtr; u_char *TxEnd; //* work variables u_char deviceAddress; u_short loadAddress; u_char nb_ACK; u_int nbI2CByte; u_char mode; signed char countBit; u_char I2CByte; u_char state; //* PIO field StructPIO *pioa_base; const PioCtrlDesc *pio_ctrl_desc ; u_int SDA; u_int SCL; //* Timer Counter field StructTCBlock *TCBase; StructTC *timerBase; u_char channelId; //* IRQ field TypeAICHandler *AICHandler; void (*I2CTCHandler) (struct I2C *); } I2Cdesc ; Note: 4 The test_i2c file defines a structure instance for the I²C line: I2C_line The lib_i2c.c file uses a pointer to this structure (I2C_pt) to allow an access to these variables. AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb Interrupt Management Read and write commands are implemented by interupts. The initialization relative to these interrupts (stack,etc.) is not described in this document, but initialization must be done before using functions defined in this application note. · The Advanced Interrupt Controller (AIC) Source Vector Register (SVR) of the timer used is filled with an assembler interrupt handler. This assembler handler (defined in I2c_irq.s) executes the basic interrupt treatments (register saving and restoring, stack management, end of interrupt acknowledgment, etc.) The handler loads the variable structure corresponding to the I2C line descriptor (see Global Variables section) and call the I2C_lineHandlerInt C handler with this structure as a parameter. · I2C_lineHandlerInt performs the basic operations to be done for all handlers: Read timer status to acknowledge interrupt. Call the C handler defined by the variable I2CTCHandler field. This handler will perform specific operations according to the machine state. Begin | Acknowledge interrupt status | Call handler following the machine state |End I2C Drivers The I²C drivers have been designed to support multi-byte sequential read and write operations. A write operation requires the device address word and acknowledgment, followed by two 8bit data word addresses, followed by the data sequence. The sequence must begin with a start condition and terminate with a stop condition. Figure 7. Write Sequence States Start & Device Address High Address Low Address Data Write Stop A read operation is initiated the same way as a write operation. It requires a dummy write operation in order to set the address. Then the sequence must follow with another start condition and a device address word. The sequence must terminate with a stop condition. Figure 8. Read Seaquence States Start & Device Address High Address Low Address Start & Device Read Address Data Read Stop 5 1742A06/01 State Machine Management The file lib_i2c provides all the functions required for the management of the two following state machines. Two counters (byte and bit) and several flags have been defined to manage the change between the different states. Two functions perform the start of a read or write sequence by initializing the state machine: at91_I2CRead at91_I2Cwrite The other functions are interrupt handlers. There is one interrupt handler for each state of the state machines. All of these functions and handlers are described after the descriptions of the two state machines. Write Sequence Figure 9. Write Sequence State Machine Write Command SendStartSDA SendStartSCL CountByte = 0 SendByte SendBit TxPrepareACK TxWaitACK I2CError No ACK SetSCL PrepareStop SendStopSDA 6 No_handler AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb Read Sequence Figure 10. Read Sequence State Machine No_handler Read Command SendStop No ACK SendStartSDA DeviceRead I2CError PrepareStop CountByte = 0 SendStartSCL RxDoACK TxWaitAck CountBit = 0 CountBit = 0 SendBit RxPrepareACK SendBit ReceiveByte ReceiveBit ClearSCL SETSCL 7 1742A06/01 User Interface Layer I2C_lineOpen The I2C_lineOpen function configures the PIO lines and the Timer/Counter channel to be used. Begin | Set SDA and SCL as output | Set SDA and SCL | Open the clock of the timer | Initialize the mode of the timer | Initialize the RC Register | Enable timer clock End I2C_lineClose The I2C_lineClose function disables interrupts on the timer, allowing it to be used by another task. Begin | Disable all interrupts of the current timer End at91_I2CWrite The at91_I2CWrite function initializes the write sequence by setting up the address of the slave device, the number of bytes to write and the address of the first byte. It sets the next mode flag at high_address_write value. It also enables the timer interrupt and changes the interrupt handler to at91_I2CTxSendStartSDA. Begin | Initialize state | Set SDA and SCL as an output | Set SDA and SCL | Get device address | Get address where to write | Set next mode High_address_write | Get byte counter | Initialize bit counter | Change IT handler to at91_I2CTxSendStartSDA | Enable interrupt on RC Compare event End 8 AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb at91_12CRead The at91_12CRead function initializes the read sequence by setting up the address of the slave device, the number of bytes to read and the address of the first byte. It sets the next mode flag at high_address_read value. It also enables the timer interrupt and changes the interrupt handler to at91_I2CTxSendStartSDA. Begin | Initialize state | Set SDA and SCL as an output | Set SDA and SCL | Get device address | Get address where to read | Set next mode High_address_read | Get byte counter | Initialize bit counter | Change IT handler to at91_I2CTxSendStartSDA | Enable interrupt on RC Compare event End Interrupt Interface Layer at91_I2CDeviceRead The at91_I2CDeviceRead handler configures the read mode. It sets the next mode flag at data_read value and changes the interrupt handler to at91_I2CTxSendStartSDA. Begin | Set SDA and SCL as an output | Set SDA and SCL | Configure device address for read mode | Set next mode Data_read | Initialize bit counter | Change IT handler to at91_I2CTxSendStartSDA End 9 1742A06/01 at91_I2CTxSendByte The at91_I2CTxSendByte handler configures the SDA line as an output at high level and, depending on the current mode flag, sets up the byte to write and the next mode flag. It changes the interrupt handler to at91_I2CTxSendBit. Begin | Set SDA and SCL as an output | Set SDA and SCL | | if mode = Data | | | get byte from the buffer | | | decrement counter byte | | | if byte counter = 0 | | | | next mode = Stop | | if mode = High_address_write | | | get high address byte | | | | next mode = Low_address_write | | if mode = Low_address_write | | | get low address byte | | | | next mode = Low_address_write | | if mode = High_address_read | | | get high byte address | | | | next mode = Low_address_read | | if mode = Low_address_read | | | get high byte address | | | | next mode = Device_Read | Initialize bit counter | Change IT handler to at91_I2CTxSendBit End at91_I2CTxSendByte The at91_I2CTxSendByte handler configures the SDA line as an input, clears the SCL line and decrements the number of bytes to read. If there are no more bytes to read, it sets the next mode flag at stop value. It changes the interrupt handler to at91_I2CrxReceiveBit. Begin | Set SDA as an input | Clear SCL | Initialize bit counter | Decrement byte counter | Next mode = STOP if byte counter = 0 | Change IT handler to at91_I2CRxReceiveBit End 10 AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb at91_I2CTxSendBit The at91_I2CTxSendBit handler clears the SCL line and decrements the number of bits to send. If all the bits have been sent, it sets the SDA line as an input for the acknowledgment and changes the interrupt handler to at91_I2CTxPrepareACK. Otherwise, it sets the SDA line depending on the value of the bit to write, and changes the interrupt handler to at91_I2CTxSetSCL. Begin | Clear SCL | Decrement bit counter | if bit counter != 0 | | Get bit to write | | Change IT handler to at91_I2CTxSetSCL | else | | Set SDA as an input | | Change IT handler to at91_I2CTxPrepareACK End at91_I2CRxReceiveBit The at91_I2CRxReceiveBit handler sets SCL line and decrements the number of bits to read. If all the bits have been read, it stores the byte in the reception buffer. Otherwise, it builds the byte depending on the value of the bit. It changes the interrupt handler to at91_I2CTxClearSCL. Begin | Set SCL | Decrement bit counter | get bit | if bit counter > 0 | | update working byte | else | | write byte in the buffer | Change IT handler to at91_I2C_RxClearSCL End at91_I2CTxsendstart SDA The at91_I2CTxSendStartSDA handler clears the SDA line and changes the interrupt handler to at91_I2CTxStartSCL. Begin | Clear SDA | Change IT handler to at91_I2CTxStartSCL End at91_I2CTxSendStart SCL The at91_I2CTxSendStartSCL handler clears the SCL line and changes the interrupt handler to at91_I2CTxSendBit. Begin | Clear SCL | Change IT handler to at91_I2CTxSendBit End 11 1742A06/01 at91_I2CTxPrepare Stop The at91_I2CTxPrepareStop handler sets the SDA line as an output, clears the SDA line and sets the SCL line. It changes the interrupt handler to at91_I2CTxSendStopSDA. Begin | Set SDA as an output | Clear SDA | Set SCL | Change IT handler to at91_I2CTxSendStopSDA End at91_I2CTxSendStop SDA The at91_I2CTxSendStopSDA handler sets the SDA line and releases the state of the line. It disables the interrupt and changes the handler to no_handler_tc. Begin | Set SDA | Change state | Disable RC compare interrupt | Change IT handler to no_handler_tc End at91_I2CTxPrepare ACK The at91_I2CTxPrepareACK handler sets the SCL line and changes the interrupt handler to at91_I2CTxWaitACK. Begin | Set SCL | Change IT handler to at91_I2CTxWaitACK End at91_I2CTxWaitACK The at91_I2CTxWaitACK handler checks the level of the SDA line. If the level is low, it clears the SCL and changes the interrupt handler, depending on the current mode flag . Otherwise, it decrements the error counter and changes the interrupt handler to at91_I2CError when the counter reaches 0. Begin | if SDA = 0 | | if mode = Stop | | | Clear SCL | | | Change IT handler to at91_I2CTxPrepareStop | | if mode = Device_read | | | Clear SCL | | | Change IT handler to at91_I2CDeviceRead | | if mode = Data_read | | | Change IT handler to at91_I2CRxReceiveByte | | else | | | Clear SCL | | | Change IT handler to at91_I2CtxSendByte | else | | decrement error counter | | if error counter = 0 | | | Change IT handler to at91_I2CError End 12 AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb at91_I2CRxPrepare ACK The at91_I2CRxPrepareACK handler sets the SCL line and changes the interrupt handler to at91_I2CTxPrepareStop, if the current mode flag is set with stop value. Otherwise, it changes the interrupt handler to at91_I2CRxDoACK. Begin | Set SCL | If mode = STOP | | Change IT handler to at91_I2CTxPrepareStop | else | | Change IT handler to at91_I2CRxDoACK | End at91_I2CRxDoACK The at91_I2CRxDoACK handler clears the SCL line and changes the interrupt handler to at91_I2CRxReceiveByte. Begin | Clear SCL | Change IT handler to at91_I2CRxReceiveByte End at91_I2CTxSetSCL The at91_I2CTxSetSCL handler sets the SCL line and changes the interrupt handler to at91_I2CTxSendBit. Begin | Set SCL | Change IT handler to at91_I2CTxSendBit End at91_I2CRxSetSCL The at91_I2CRxSetSCL handler sets the SCL line and changes the interrupt handler to at91_I2CRxReceiveBit. Begin | Set SCL | Change IT handler to at91_I2CRxReceiveBit End at91_I2CTxClearSCL The at91_I2CTxClearSCL handler clears the SCL line, sets up the SDA line as an input if the bit counter is equal to 0 and changes the interrupt handler to at91_I2CTxSendBit. Begin | Clear SCL | If bit counter = 0 | | Set SDA as an input | Change IT handler to at91_I2CTxSendBit End 13 1742A06/01 at91_I2CRxClearSCL The at91_I2CRxClearSCL handler clears the SCL line, sets up the SDA line as an output, clears the SDA line and changes the interrupt handler to at91_I2CRxPrepareACK if the bit counter is equal to 0. Otherwise, it changes the interr upt handler to at91_I2CRxReceiveBit. Begin | Clear SCL | If bit counter = 0 | | Change IT handler to at91_I2CRxPrepareACK | | Set SDA as an output | | Clear SDA | else | | Change IT handler to at91_I2CRxReceiveBit End at91_I2CError The at91_I2CError handler implements a forever loop. Begin | forever loop End EEPROM Drivers The file: test_i2c.c, implements the management of the EEPROM. It consists of: A driver for write access · NVMWrite · A driver for read access The NVMWrite function has three arguments : 1. number of bytes to write 2. first byte load address 3. address of the buffer containing the bytes to write Begin | Set number of page to program | for each page | | set the pointer at the beginning of the buffer to program | | call at91_I2Cwrite function | | wait the end of programmation of the page | if number of byte to program < number of byte per page | | set the pointer at the beginning of the buffer to program | | call at91_I2CWrite function | | wait the end of programmation of the bytes End 14 AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb NVMRead The NVMRead function has three arguments : 1. number of byte to read 2. first byte read address 3. address of the storing buffer Begin | set the pointer at the beginning of the buffer | call the function at91_I2CRead with the number of byte and the | address End 15 1742A06/01 Code test_i2c.c //*-//* ATMEL Microcontroller Software Support - ROUSSET - //*-//* The software is delivered "AS IS" without warranty or condition of any //* kind, either express, implied or statutory. This includes without //* limitation any warranty or condition with respect to merchantability or //* fitness for any particular purpose, or against the infringements of //* intellectual property rights of others. //*-//* File Name : test_i2c.c //* Object : I2C //* //* 1.0 29/05/00 EL : Creation //*- #include #include "drivers/lib_i2c/lib_i2c.h" #include "parts/m63200/lib_m63200.h" #include "parts/m63200/reg_m63200.h" #define PAGE_LENGTH 128 #define NB_PAGE 4096 #define EPROM_SIZE NB_PAGE*PAGE_LENGTH #define NB_PAGE_TEST 10 extern void tc0_interrupt_handler(void); void no_handler_tc (I2Cdesc *I2C_pt) { } void at91_I2CError(I2Cdesc *I2C_pt) { printf("I2C EPROM ERROR !\n"); while(1); } I2Cdesc I2C_line; u_char txBuffer[128]; u_char rxBuffer[128]; u_int i; int line_status = OK; 16 AT91 ARM Thumb 1742A06/01 AT91 ARM Thumb u_char NVMWrite(u_short address, u_char *data_array, u_int num_bytes) { u_short num_page = num_bytes / PAGE_LENGTH; u_short cpt; u_int j; for (cpt=0; cpt