en:pfw:i2c
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
en:pfw:i2c [2023-09-04 18:14] – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | en:pfw:i2c [2023-09-05 06:33] (current) – ↷ Links angepasst, weil Seiten im Wiki verschoben wurden 157.90.7.32 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | {{pfw: | ||
+ | ====== I2C, The I2C protocol ====== | ||
+ | |||
+ | **The PFW universal I2C drivers** The I2C protocol is a must-have for any microcontroller. It opens up access to IO-expanders, | ||
+ | |||
+ | With these drivers, the use of I2C should not be a problem for anyone. Have fun exploring and using I2C-devices! | ||
+ | |||
+ | ===== The Idea of I2C ===== | ||
+ | |||
+ | |{{https:// | ||
+ | |SDA | ||
+ | |SCL | ||
+ | |||
+ | **Note that the I2C-protocol uses 7-bits addresses and a read/write bit, but in some cases an 8-bit address is mentioned. Even the original designer of the protocol, Philips, sometimes falls into this trap.** | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== The low level I2C states for a single master are in short: ==== | ||
+ | |||
+ | * Start condition | ||
+ | * Address a device (for read or write) A device may stretch the clock cycle to allow for a slow response\\ | ||
+ | When a device exists and is ready, it responds with an ACK | ||
+ | * Read or write one or more data bytes After each byte an ACK is received, a NAK is received when it is the last byte | ||
+ | * Stop condition | ||
+ | |||
+ | {{https:// | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Pseudo code for low level bitbang I2C ==== | ||
+ | |||
+ | This pseudo code is without the use of clock stretching. This is only necessary when you use a multi master system or I2C slaves implemented on slow microcontrollers. Note that the used example works on on a chip with a push/pull output ports | ||
+ | |||
+ | < | ||
+ | Reserve RAM memory cells named: DEV SUM NACK? | ||
+ | Function: WAIT ( -- ) | ||
+ | Delay for about 5 µsec. | ||
+ | |||
+ | Function: I2START | ||
+ | Clock line high, wait, generate low flank on data line, wait | ||
+ | |||
+ | Function: I2ACK ( -- ) | ||
+ | Clock line low, data line low, wait, | ||
+ | clock line high, wait | ||
+ | |||
+ | Function: I2NACK | ||
+ | Clock line low, data line high, wait, | ||
+ | clock line high, wait | ||
+ | |||
+ | Function: I2ACK@ | ||
+ | Clock line low, data line high, wait, clock line high, wait | ||
+ | Read status of data line, store true in NACK? if it is a nack, otherwise false | ||
+ | |||
+ | Function: BUS! ( x -- ) | ||
+ | 8 loop | ||
+ | clock line low | ||
+ | write bit-7 level of x to data line, wait | ||
+ | clock line high, wait | ||
+ | shift x left | ||
+ | Discard byte, perform i2ack@ | ||
+ | |||
+ | Function: {I2C-ADDR | ||
+ | store +n + 1 in SUM, perform i2start | ||
+ | read dev, perform bus! | ||
+ | |||
+ | |||
+ | Higher level I2C access, hides internal details! | ||
+ | |||
+ | Function: I2C-ON | ||
+ | Setup I/O-bits for two bidirectional | ||
+ | open collector lines with pull-up | ||
+ | |||
+ | Function: I2C} ( -- ) | ||
+ | Clock line high, wait, generate high flank on data line, wait | ||
+ | |||
+ | Function: BUS@ ( -- y ) | ||
+ | Initialise y at zero | ||
+ | 8 loop | ||
+ | shift y left | ||
+ | Clock line low, data line high, wait, clock line high, wait | ||
+ | read data line to bit-0 position of y | ||
+ | Decrease SUM | ||
+ | Sum not zero IF perform i2ack ELSE perform i2nack | ||
+ | |||
+ | Function: | ||
+ | Multiply dev by 2, AND result with 0xFE and store in DEV | ||
+ | |||
+ | Function: {I2C-WRITE | ||
+ | Discard +n, perform i2start, read DEV, (bus! | ||
+ | Read nack? issue error message when true | ||
+ | |||
+ | Function: {I2C-READ | ||
+ | Store +n in SUM, perform i2start, read DEV and set lowest bit, | ||
+ | Perform bus!, read nack? issue error message when true | ||
+ | |||
+ | Function: {DEVICE-OK? | ||
+ | Perform {i2c-addr, perform i2c} | ||
+ | Read nack?, leave true when result is zero | ||
+ | |||
+ | |||
+ | \ Waiting for an EEPROM write to succeed is named acknowledge polling. | ||
+ | Function: {POLL} | ||
+ | Function: {I2C-OUT | ||
+ | Function: {I2C-IN | ||
+ | Function: BUS!} ( b -- ) Perform bus!, perform i2c} | ||
+ | Function: BUS@} ( -- b ) Perform bus@, perform i2c} | ||
+ | Function: BUS-MOVE | ||
+ | </ | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== When looked to I2C from a higher level it's access is: ==== | ||
+ | |||
+ | 1) Simple write action - Open I2C-bus for write access to bus-address and output one byte to I2C-bus - Close I2C-bus access | ||
+ | |||
+ | 2) Multiple write action to a devices register or address: - Open I2C-bus for write access to bus-address and output one byte to I2C-bus - Output one ore more byte(s) to I2C-bus (with auto increment) - Close I2C-bus access | ||
+ | |||
+ | 3) A read action from a devices register or address: - Open I2C-bus for write access to bus-address and output the address byte to I2C-bus - Open I2C-bus for reading (Repeated start) - Read one byte from I2C-bus - Close I2C-bus access | ||
+ | |||
+ | 4) Multiple read action from a devices register or address: - Open I2C-bus for write access to bus-address and output the address byte to I2C-bus - Open I2C-bus for reading (Repeated start) - Read one or more byte(s) from I2C-bus (with auto increment) - Close I2C-bus access | ||
+ | |||
+ | ==== I2C pseudo code with high level factorisation ==== | ||
+ | |||
+ | < | ||
+ | Function: > | ||
+ | perform device! | ||
+ | |||
+ | Function: PCF8574> | ||
+ | perform device! | ||
+ | </ | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Generic Forth low level part of bitbang example ==== | ||
+ | |||
+ | This example has the I2C interface pins connected like this. | ||
+ | |||
+ | < | ||
+ | SDA (Serial DAta line) = bit-7 | ||
+ | SCL (Serial CLock line) = bit-6 | ||
+ | </ | ||
+ | |||
+ | **The used addresses are for port-1 of the MSP430G2553: | ||
+ | |||
+ | Note that the MSP430 controller series does not have the easiest I/O structure to implement a bitbang version of I2C! This is because it only has push/pull outputs and I2C needs an open collector (or open drain) output. So this example code mimics open collector ports. | ||
+ | |||
+ | {{https:// | ||
+ | **Read byte from I2C EEPROM** %%**%%* | ||
+ | |||
+ | ===== Generic Forth example ===== | ||
+ | |||
+ | <code forth> | ||
+ | Extra words: ABORT" | ||
+ | |||
+ | Words with hardware dependencies: | ||
+ | : *BIS ( mask addr -- ) tuck c@ or swap c! ; | ||
+ | : *BIC ( mask addr -- ) >r invert | ||
+ | : BIT* ( mask addr -- b ) c@ and ; | ||
+ | |||
+ | 20 constant P1IN \ Port-1 input register | ||
+ | 21 constant P1OUT \ Port-1 output register | ||
+ | 22 constant P1DIR \ Port-1 direction register | ||
+ | 26 constant P1SEL \ Port-1 function select | ||
+ | 27 constant P1REN \ Port-1 resistor enable (pullup/ | ||
+ | 42 constant P1SEL2 | ||
+ | |||
+ | 40 constant SCL \ I2C clock line | ||
+ | 80 constant SDA \ I2C data line | ||
+ | SCL SDA or constant IO \ I2C bus lines | ||
+ | |||
+ | : WAIT ( -- ) \ Delay of 5 µsec. must be trimmed! | ||
+ | ( true drop ) ; | ||
+ | |||
+ | : I2START | ||
+ | scl p1out *bis scl p1dir *bic wait | ||
+ | sda p1dir *bis sda p1out *bic wait ; | ||
+ | |||
+ | : I2ACK ( -- ) | ||
+ | scl p1out *bic scl p1dir *bis | ||
+ | sda p1out *bic sda p1dir *bis wait | ||
+ | scl p1out *bis scl p1dir *bic wait ; | ||
+ | |||
+ | : I2NACK | ||
+ | scl p1out *bic scl p1dir *bis | ||
+ | sda p1out *bis sda p1dir *bic wait | ||
+ | scl p1out *bis scl p1dir *bic wait ; | ||
+ | |||
+ | : I2ACK@ | ||
+ | scl p1out *bic scl p1dir *bis | ||
+ | sda p1out *bis sda p1dir *bic wait | ||
+ | scl p1out *bis scl p1dir *bic wait | ||
+ | sda p1in bit* nack? ! ; | ||
+ | |||
+ | : BUS! ( byte -- ) | ||
+ | 8 0 do | ||
+ | scl p1out *bic scl p1dir *bis | ||
+ | dup 80 and if | ||
+ | sda p1out *bis sda p1dir *bic | ||
+ | else | ||
+ | sda p1out *bic sda p1dir *bis | ||
+ | then | ||
+ | wait 2* | ||
+ | scl p1out *bis scl p1dir *bic wait | ||
+ | loop drop i2ack@ ; | ||
+ | |||
+ | : {I2C-ADDR | ||
+ | drop i2start | ||
+ | |||
+ | |||
+ | \ Higher level I2C access, hides internal details! | ||
+ | |||
+ | \ Note that this setup is valid for an MSP430 with external pull-up resistors attached! | ||
+ | \ On hardware which is able to use an open collector (or open source) with pull-up | ||
+ | \ resistor, you should initialise this mode! | ||
+ | : I2C-ON | ||
+ | io p1ren *bic \ Deactivate pull-up/ | ||
+ | io p1dir *bic \ SDA & SCL are inputs | ||
+ | io p1out *bis \ Which start high | ||
+ | io p1sel *bic \ Guarantee normal i/o on MSP430 | ||
+ | io p1sel2 *bic ; | ||
+ | |||
+ | : BUS@ ( -- byte ) | ||
+ | 0 8 0 do | ||
+ | 2* | ||
+ | scl p1out *bic scl p1dir *bis | ||
+ | sda p1out *bis sda p1dir *bic wait | ||
+ | sda p1in bit* 0= 0= 1 and or | ||
+ | scl p1out *bis scl p1dir *bic wait | ||
+ | loop -1 sum +! | ||
+ | sum @ if i2ack else i2nack | ||
+ | |||
+ | : I2C} ( -- ) | ||
+ | scl p1out *bic scl p1dir *bis | ||
+ | sda p1out *bic sda p1dir *bis wait | ||
+ | scl p1out *bis scl p1dir *bic wait | ||
+ | sda p1out *bis sda p1dir *bic ; | ||
+ | |||
+ | : DEVICE! | ||
+ | : {DEVICE-OK? | ||
+ | : {I2C-WRITE | ||
+ | | ||
+ | : {I2C-READ | ||
+ | sum ! i2start | ||
+ | nack? @ abort" Ack error" ; | ||
+ | |||
+ | |||
+ | \ Waiting for an EEPROM write to succeed is named acknowledge polling. | ||
+ | : {POLL} | ||
+ | : {I2C-OUT | ||
+ | : {I2C-IN | ||
+ | : BUS!} ( b -- ) bus! i2c} ; | ||
+ | : BUS@} ( -- b ) bus@ i2c} ; | ||
+ | : BUS-MOVE | ||
+ | </ | ||
+ | |||
+ | ==== I2C implementation examples ==== | ||
+ | |||
+ | This example is for an 8-bit PCF8574 like I/ | ||
+ | |||
+ | <code forth> | ||
+ | : > | ||
+ | device! | ||
+ | |||
+ | : PCF8574> | ||
+ | device! | ||
+ | </ | ||
+ | |||
+ | More examples can be found in the file i2c-examples.f, | ||
+ | See the list of example words below. | ||
+ | |||
+ | ^Word ^Stack | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |'' | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Dedicated implementations ==== | ||
+ | |||
+ | Have a look at the sub directories for implementations for different systems. | ||
+ | |||
+ | * [[en: | ||
+ | * [[en: | ||
+ | * [[https:// | ||
+ | * [[en: | ||