HALICERY

free-time coding, hardware dev, articles

Top
Home 8042 Blogs About
Home Bare Metal Hardware Projects Live Video on S3 chips I2C

Last modified: Wed Nov 13 22:42:41 UTC+0100 2019 © A. Tarpai


S3 and the I2C-bus

Notes on S3 Trio64V+ and S3 ViRGE/DX. This was used to communicate with monitor DDC and Bt819/Bt829 video digitizers.

Little about I2C

2-wire protocol: clock and data

SCL and SDA lines. Pulled up to Vcc (4.7 or 10K it varies) on idle bus. I2C devices can pull lines low.

  +----- 4.7KΩ -- Vcc
  |  +---- 4.7KΩ -- Vcc
  |  |
  +-----
  |  +-- I2C device
  |  |
  +-----
  |  +-- I2C device
  |  |
  +-----
  |  +-- I2C device
  |  |
 SCL |
    SDA

Rules:
- SCL is driven only by master (regardless of data transfer direction)
- SDA can change only when SCL pulled low (therefore the 'START'-condition is special)

Master and slave

The bus is idle, SCL and SDA is pulled high by the resistors. Any device can act as master and initiate start condition, 'S'. After that for the whole transfer it is the master and drives SCL.

Based on direction master writes or reads 8-bits of data and 1-bit ACK:

Slave address

Hard-wired and dedicated 7-bit values.

S3 and I2C

ViRGE has 2 pins for the I2C-bus: pin 205 and 206. Programming is via bit-banging, and I used only MMFF20 to control the I2C-bus to read DDC info from the monitor and to control LPB peripherials, like Bt819/829.

ViRGE is the bus master.

These basic I2C protocol routines worked for me:

The code writes both SDA/SCL in one operation and in stages. In the first stage I assume unknown state of the lines (X).

Note: every cycles include hold too

iic_start from idle bus

Valuse from eg. AT24C02B EEPROM datasheet (i2c standard is stricter).

         0.6    0.6 us  (400kHz)
         4.7    4.0 us  (100kHz)

        SETUP   HOLD
          <--> <-->
         _____|     |     |
   SDA        \_____|_____|_ 0
              |     |     |
         _____|_____|     |
   SCL        |     \_____|_ 0
              |     |     |
              |     |     |
              1  2  3  4  5
              S

1. Start condition (S): pull SDA low (1,0)
2. Hold for START hold time is least 4µs

Rest is prepare for next bit write:

3. pull SCL low too (0,0)
4. keep SCL low for SCL LOW TIME 4-5µs
5. we end up in (0,0) ready for write (SDA can change now)

After START there is always write for addressing + R/W. Proceed with writes.

CLOCK STRETCHING: lets put this now in every bit read and write (later, only for the first ones after ACK).

iic_write_bit 0/1

We always get here when we pulled SCL low, and held it previously, so change SDA first:

1. change SDA to zero or one (0,b) i.e. write data bit. Previous state is dont's care.
2. release SCL with no wait: do this in 2 I/O-writes gives enough time for DATA SU TIME 250ns? (1,b)
3. keep SCL high for SCL HIGH TIME 4-5µs?
4. pull back SCL low (0,b) with keeping data valid for a bit
5. release SDA. Do this in 2 I/O-writes gives enough time for DATA HOLD TIME 250ns? (0,1)
6. keep SCL low for SCL LOW TIME 4-5µs
7. we end up in (0,1) ready for another write or read to start

       __| |     | |_____|__
SDA  X __XXXXXXXXXXX     |   1
         | |     | |     |
         | |_____| |     |
SCL  0 __|_/     \_|_____|__ 0
         | |     | |     |
         | |     | |     |
         1 2  3  4 5  6  7
         W



         2.1 WITH CLOCK STRETCHING


       __| | |     |     | |_____|__
SDA  X __XXXXXXXXXXXXXXXXXXX     |   1
         | | |     |     | |     |
         | |_|_ _ _|_____| |     |
SCL  0 __|_/ |     |     \_|_____|__ 0
         | | |     |     | |     |
         | | |     |     | |     |
         1 2   2.1    3  4 5  6  7
         W

2.1 WITH CLOCK STRETCHING: after releasing SCL wait until SCL is released.

After writing data bit there can be:
- another write bit (OK: SCL pulled low, SDA dont's care)
- read bit for ACK/NACK (OK, SCL pulled low, SDA released by master)

iic_read_bit

Read bit can come after write bit or another read bit (never after START).

       __|_____|_|_____|__
SDA  1   |     | |     |   1
         |     | |     |
         |_____|_|     |
SCL  0 __/     | \_____|__ 0
         |     | |     |
         |     | |     |
         1  2  3 4  5  6
               R



        1.1 WITH CLOCK STRETCHING

       __|_|_____|_____|_|_____|__
SDA  1   | |     |     | |     |   1
         | |     |     | |     |
         |_|_ _ _|_____|_|     |
SCL  0 __/ |     |     | \_____|__ 0
         | |     |     | |     |
         | |     |     | |     |
         1   1.1    2  3 4  5  6
                       R

1.1 WITH CLOCK STRETCHING. After releasing SCL wait until SCL is released.

1. release SCL and SDA (1,1). SDA already released from previous r/w
2. keep SCL high for SCL HIGH TIME 4-5µs
3. Read data bit on SDA
4. pull down SCL with no wait (0,1)
5. keep SCL low for SCL LOW TIME 4-5µs
7. we end up in (0,1) ready for another write or read

iic_read_ack

This comes after a read or write bit, where after both SDA is released, SCL is pulled low.
Slave pulls SDA low (ACK) or does not pull low, i.e. SDA kept released (NACK).

After NACK there should be a STOP CONDITION generated on the bus to not leave the bus in unknown state!

After ACK there can be:

ACK

Master does a normal read bit. Slave does Q and P with SDA and possibly CLOCK STRETCHING. We handle the latter in both.

Q: Slave must pull down SDA after the 8th data bit. Here SDA is released by Master after read or write bit. SCL pulled low.
1-6. Master normal read
P: I suppose slave releases SDA right after the falling edge of SCL

       __| |     | | |_____|__ 1
SDA  X __\_|_____|_|_/     |       Slave drives SDA
         | |     | | |     |
       __|_|_____|_|_|_____|__
SDA  1   | |     | | |     |   1   Master released SDA
         | |     | | |     |
         | |_____|_| |     |
SCL  0 __|_/     | \_|_____|__ 0   Master
         | |     | | |     |
         | |     | | |     |
         Q 1  2  3 4 P  5  6
                 |

R=0 ACK

       __|_|_____|_|_|_____|__ 1
SDA  X   | |     | | |     |       Slave has NOT driven SDA
         | |     | | |     |
       __|_|_____|_|_|_____|__
SDA  1   | |     | | |     |   1   Master released SDA
         | |     | | |     |
         | |_____|_| |     |
SCL  0 __|_/     | \_|_____|__ 0   Master
         | |     | | |     |
         | |     | | |     |
         Q 1  2  3 4 P  5  6
                 |

R=1 NACK

After ACK we're ready for:
- another read or write byte and ACK
- the STOP condition ONLY when no clock stretching:

No stretching before ACK.

iic_stop:

We're after ACK or NACK. SDA is supposed to be released by slave by now.
SCL may be kept low by slave for clock-stretcing. Extra step for check and wait (possibly with time-out and report SCL-stuck-low?).

1. so we pull SDA down (0,0)
2. now release SCL (1,0) with no wait
2.1 EXTRA: wait for SCL is released (clock-stretcing)
3. keep SCL high for SCL HIGH TIME 4-5µs OR STOP SETUP TIME (that meets for sure)
4. release SDA: STOP CONTITION, P (1,1)
5. we can wait BUS FREE TIME to make sure between STOP and next START condition
6. we end up in free bus

                    0.25   0.5 us  (400kHz)
                    0.6    1.2 us  (100kHz)

                   SETUP   HOLD=BUS FREE
                     <--> <-->
       __| | |     |     |_____|__
SDA  1   \_|_|_ _ _|_____/     |   1
         | | |     |     |     |
         | |_|_ _ _|_____|_____|__
SCL  0 __|_/ |     |     |     |   1
         | | |     |     |     |
         | | |     |     |     |
         1 2   2.1    3  4  5  6      Bus free
                         P

or 3/4 swap as in write

iic_restart:

       __|_|_|_ _ _|_____|     |     |
SDA  1   | | |     |     \_____|_____|_  0
         | | |     |     |     |     |
         | |_|_ _ _|_____|_____|     |
SCL  0 __|_/ |     |     |     \_____|_  0
         | | |     |     |     |     |
         | | |     |     |     |     |
         1 2   2.1    3  4  5  6  7  8
                         Sr





iic_start

1. pull down SCL and release SDA
2. release both: prepare for start condition
3. start condition (S). Pull SDA low: the hold time is least 4µs
4. pull SCL low too: prepare for data transfer (can be left out)

Notes

The 1. stage of these sequences. F.ex. the S condition (3) is defined as 'pull SDA low while SCL is high'. Meaning before the S condition both SDA and SCL should be stable high (2). But we cannot just start the sequence by releasing both lines or assuming both lines are released: what if SLC is already high but SDA low and we pull it up? That's a Sp condition. So it's always a good practice to start any sequence with pulling SCL low anyway to make the bus busy (only master drives SCL) and not to confuse slaves accidentally (I assume).

Little about the 4. stage. Because all transfer sequence starts with pulling SCL low, this can be left out. After iic_start we address the slave anyway and will write bits by iic_write.

iic_write_bit 0/1

1. set SDA to desired level (keep SCL low)
2-3. clock it in pulse: write (W)

iic_read_bit

1. release SDA (let slave drive it) and set SCL low
2-3. clock it in pulse: master reads SDA between 2-3 (R)

iic_stop:

1. pull down SCL and SDA
2. release SCL (prepare for start condition)
3. release SDA: start condition (S)

Byte transfers on the I2C-bus

All byte transfer involve 9-bits (8-bit data MSB first + ACK). Master drives SCL.

SCL pulses, SDA latched on rising edges and held for a while. ACK is hopefully pulled low at the end by master (read) or slave (write).

           7       6       5       4       3       2       1       0      ACK
           |       |       |       |       |       |       |       |       |
 SDA       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_________    slave + master ACK (read) or
                                                                                     master + slave ACK (write)

           ___     ___     ___     ___     ___     ___     ___     ___     ___
 SCL    __/   \___/   \___/   \___/   \___/   \___/   \___/   \___/   \___/   \__    master

iic_write_byte

iic_read_byte

7-bit slave addressing + R/W bit (1=read)

Scanning the I2C-bus

EDID

Seems like my Dell 1907 has a 2K-EEPROM:

00 ff ff ff ff ff ff 00 10 ac 10 30 55 55 42 41 32 0d 01 03 0e 22 1b 78 ee 6f 86 a2 5a 4d 94 24
1a 4f 54 a5 4b 00 71 4f 81 80 01 01 01 01 01 01 01 01 01 01 01 01 30 2a 00 98 51 00 2a 40 30 70
13 00 52 0e 11 00 00 1e 00 00 00 ff 00 34 59 32 37 39 33 43 44 41 42 55 55 0a 00 00 00 fc 00 44
45 4c 4c 20 31 37 30 33 46 50 0a 20 00 00 00 fd 00 38 4c 1e 50 0e 00 0a 20 20 20 20 20 20 00 dc
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

00 ff ff ff ff ff ff 00 ← Header
10 ac 10 30 55 55 42 41 32 0d
01 03 ← Version 1.3
0e 22 1b 78 ee
6f 86 a2 5a 4d 94 24 1a 4f 54
a5 4b 00
71 4f ← 1152
81 80 ← 1280
01 01 ←
01 01 ←
01 01 ←
01 01 ←
01 01 ←
01 01 ←
30 2a 00 98 51 00 2a 40 30 70 13 00 52 0e 11 00 00 1e ←
00 00 00 ff 00 34 59 32 37 39 33 43 44 41 42 55 55 0a ←
00 00 00 fc 00 44 45 4c 4c 20 31 37 30 33 46 50 0a 20 ←
00 00 00 fd 00 38 4c 1e 50 0e 00 0a 20 20 20 20 20 20 ←
00 ← no extension blocks
dc ← chksum to make sum zero

ATi-TV ISA

Scanning the i2c bus. Loooots of clock-stretching here.

CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr
Slave 11
CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr
Slave 38
CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr
Slave 44
CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr
Slave 60
CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp CSw CSw CSw CSw CSw CSw CSw CSw CSr CSp

Slave 11 22 0010 0010 - SAA5281 Teletext decoder
Slave 38 70 0111 0000 - PCF8574A I2C 8-bit I/O expander
Slave 44 88 1000 1000 - Bt829B
Slave 60 C0 1100 0000 - FI1216 TV-TUNER