// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // I2C interface // Uses the built in I2C functionality of the LPC2xxx // This is the generic I2C driver with ARM as the master // To drive individual devices // NOTE: This file only makes use of I2C channel 0, there is // another channel but it is not implemented here // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // HISTORY: // Aug 2007 *updated by adding a few extra words // *added a section at the back // Oct 2007 *error with P, should not use i2-valid (corrected) // *added libaraies // Dec 2007 *loader added // *sid used in loader-1 // Feb 2008 *this file is now a library with // *only the public words exposed // Nov 2008 *Renamed the AA,SI,STO & STA constants to prevent // clashes when using with sid=0 // *Increased number of re-tries on i2-start to cater for // slow devices // REQUIRES: // #URL-lib "http://pin1.org/forthlib/flb/General/soft1.flb" sid=0 // #URL-lib "http://pin1.org/forthlib/flb/General/pinsel.flb" sid=101 // Register CONSTANTS: // channel 0 - only channel 0 used, there is a channel 1, extend // this file as required. &E001C000 constant I2CONSET &E001C004 constant I2STAT &E001C008 constant I2DAT &E001C00C constant I2ADR // not used &E001C010 constant I2SCLH &E001C014 constant I2SCLL &E001C018 constant I2CONCLR // easier to understand 4 constant I2_AA 8 constant I2_SI 16 constant I2_STO 32 constant I2_STA // Set I2C frequency in Hz, this is for starters and can be changed // by the public word at the end of the file 50000 constant i2cBusSpeed // conservative // run this first to set up hardware // (---) : i2c-init 2 1 pinselect // set i2c functions 3 1 pinselect // on pins p0.2 and p0.3 pclk i2cBusSpeed / // I2C speed dup I2SCLH ! I2SCLL ! // 75khz @ plck = 60Mhz &40 I2CONSET ! // enable i2c ; // enables speed to be set after initialisation // set speed in Hz, i.e 100000 = 100kHz // ( speed ---) : i2-speed pclk swap / dup I2SCLH ! I2SCLL ! ; // send start condition return true if master can // take charge of bus, otherwise returns 0 // ( --- -1|0) : i2-start 0 10000 for I2_STA I2CONSET ! // start I2STAT @ &08 = if drop -1 leave then next ; // when a command is issued the status goes to &f8 // this can keep the command here until its finished // the time out of 100000 should be long enough for the slowest of // i2c devices. It is about 300ms : i2-valid 100000 for i2stat @ &f8 <> if leave then next ; // Checks status of I2c device with timeout, if // no agreement will abort, otherwise continues // ( stat ---) : i2-stat i2stat @ 2dup <> if cr ." i2c Error - Status recieved " ph. ." Expecting " ph. abort else 2drop then ; // I2c data register for putting and fetching the data : i2-dat@ i2dat @ ; // ( --- data) : i2-dat! i2dat ! ; // ( data ---) // In general i2c3 will do as a stop condition, but not always // these commands take a finite time to establish, and when they are // not ready the status is &f8, i2-valid returns when these commands // return a valid state or a time out occures // conditions, see datasheet STA ST0 SI AA : i2c1 I2_STA I2_STO + I2_SI + i2conclr ! i2-valid ; // 0 0 0 x : i2c2 I2_STA i2conset ! I2_STO I2_SI + i2conclr ! i2-valid ; // 1 0 0 x : i2c3 I2_STO i2conset ! I2_STA I2_SI + i2conclr ! i2-valid ; // 0 1 0 x : i2c4 I2_STA I2_STO + i2conset ! I2_SI i2conclr ! i2-valid ; // 1 1 0 x : i2c5 I2_STA I2_STO + I2_SI + I2_AA + i2conclr ! i2-valid ; // 0 0 0 0 : i2c6 I2_AA i2conset ! I2_STA I2_STO + I2_SI + i2conclr ! i2-valid ; // 0 0 0 1 // : i2-8 i2dat ! I2_STO I2_SI + i2conclr ! i2-valid ; // ( device-address --- ) : i2-10 i2dat ! I2_STO I2_SI + i2conclr ! i2-valid ; // ( device-address --- ) // ************************************************************** // The following uses the above to create an I2C interface // ************************************************************** // Example // To write to a simple device address &50 // &50 s ; start and sends address // 12 i2-sb ; send byte // p ; stop // To read // &51 s // i2-rn // i2-rl ; lasyt byte ** bus will hang if not used // p // Start and send address // ( address ---) : (s) i2-start 0= abort" Error I2C cant start" i2stat @ &8 = if i2-8 escape then i2stat @ &10 = if i2-10 escape then ." Error start returns " i2stat @ ph. ." as status value" ; // =================== Public interface ========================== // Stop - should return &f8 as a status but may need // a small amount of time to do this. : <0>p I2_STO i2conset ! I2_STA I2_SI + i2conclr ! // i2c3 without valid checkg -1 100000 for i2stat @ &f8 = if 1+ leave then next if ." I2C Stop error" then ; // Start and send address // ( address ---) : <0>s (s) // check if device exists & bus okay i2stat @ // should not be 38,48,or 0x58 dup &38 = swap dup &48 = swap &58 = or or if ." Device does not acknowledge" p then ; // repeated start // ( address ---) : <0>rs i2c2 i2stat @ &10 = if i2-10 else ." Repeated start error" then ; // send next byte, no need for last byte // ( data ---) : <0>sb i2dat ! i2c1 ; // read next byte // ( --- data) : <0>rn i2c6 &50 i2-stat i2-dat@ ; // read last byte - does not do stop // ( --- data) : <0>rl i2c5 &58 i2-stat i2-dat@ ; : <0>I2-init ( -- ) i2c-init ; : <0>i2Speed ( Hz -- ) I2-speed ;