aboutsummaryrefslogtreecommitdiffstats
path: root/notes/i2c
blob: c324bb27a816205fdeb3cb782da2a74b61d6e533 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

Maple -------------------------------------------------------------------------

We'll probably want both HardwareI2C and SoftI2C implementations, with the
soft being bitbanged on arbitrary pins (and possibly only master-mode; almost
certainly not multi-master).

The first simple implementation will support up to 400khz operation, only 
7-bit addresses, no clock stretching (on our part), only blocking master
read/write (with timeout), and only master n-write,n-read combined messages.

A more advanced implementation would be event-driven, support DMA, higher
clock speeds, handle error interrupts, etc. 

Should all of these return a status code? or just fail? or fail silently?

Ring buffers etc are not needed because the length of the read/write is always
known (or handled by the application code for slave mode).

// port = {1,2}
i2c_init(port, freq)
i2c_disable(port)

// blocking/polling
i2c_master_read(port, slave_addr, *data, len)  // wrapper around writeread
i2c_master_write(port, slave_addr, *data, len) // wrapper around writeread
i2c_master_writeread(port, slave_addr, *wdata, wlen, *rdata, rlen)

// callbacks/interrupts
i2c_slave_set_addr(port, addr) // enables callbacks etc if they aren't already;
                               // set ACK high
i2c_slave_set_rx_callback(port, *function) // takes a byte?
i2c_slave_set_tx_callback(port, *function) // gives a byte?

How to init:
 - setup pins
 - setup peripheral input clock: 4MHz for fast mode
 - configure clock control registers
 - configure rise time register
 - configure interrupts
 - configure I2C_CR1 to enable the peripheral
 - set ACK flag low: won't be a slave until addr is set

How to master_write:
 - START, addr[0:7], W, ACK, DATA[0:7], ACK, DATA[8:15], ..., STOP
 - software sets START high, which toggles M/SL to master mode
 - when START actually happens, SB is set and interrupt happens; hardware
   waits until address is written to DR
 - address shifts out and an interrupt is thrown with ADDR high; if LSB of
   address was low, in transmitter mode. TRA reflects this
 - software writes to the first byte to DR and clears ADDR
 - first byte shifts out and when there's an ACK an interrupt is thrown
   with TxE high; if no new byte was written to DR since the previous
   transmission BTF goes high
 - software writes next byte to DR and clears BTF, or sets STOP bit to end
   data transmission, or sets START to begin next part of combined session
 - after STOP is set, hardware goes back to slave mode

How to master_read:
 - START, addr[0:7], R, ACK, DATA[0:7], ACK, ..., NACK, DATA[-8:-1], STOP
 - software sets START high, which toggles M/SL to master mode
 - when START actually happens, SB is set and interrupt happens; hardware
   waits until address is written to DR
 - address shifts out and an interrupt is thrown with ADDR high; if LSB of
   address was high, in receiver mode. TRA reflects this.
 - software clears ADDR; hardware shifts in first byte from slave and sends ACK
   if ACK is set. interrupt is thrown with RxNE high, with BTF set
 - if only reading one byte, ACK should be set low and STOP high; hardware will
   then NACK and STOP after reading
 - software reads from DR and clears BTF bit. next byte is shifted in
 - software sets NACK low after second-to-last byte is read by setting ACK low
   after reading from DR, and either setting STOP or START high
 - after STOP is set, hardware goes back to slave mode

How to master_writeread:
 - [START, addr[0:7], W, ACK, WDATA[0:7], ...], 
   [START, addr[0:7], R, ACK, RDATA[0:7], ACK, ..., NACK, RDATA[-8:-1]]
   STOP
 - implement the above read/write but set START high instead of STOP high at
   the end

How to slave tx (master read):
 - if address is matched, ACK is send (if ACK flag is high) and ADDR goes high;
   event interrupt is triggered if ITEVFEN flag is set. TRA indicates whether
   this is a read or write request
 - program sets DR degister and clears ADDR flag; hardware will clock stretch
   until ADDR is low
 - if ITVENFEN and ITBUFEN are set, the TxE interrupt is triggered after the
   byte is sent and the master ACKs. now the hardware stretches until BTF is
   cleared before sending again.
 - after the STOP is sent, hardware sets STOPF, throws an event if ITEVFEN is
   high, and waits for a read of SR1 and write CR1

How to slave rx (master write):
 - if address is matched, ACK is send (if ACK flag is high) and ADDR goes high;
   event interrupt is triggered if ITEVFEN flag is set. TRA indicates whether
   this is a read or write request
 - the hardware shifts in the byte to DR and sends an ACK if ACK flag is high
 - if ITEVFEN and ITBUFEN are set, an RxNE interrupt is sent. hardware waits
   until the BTF flag is reset
 - after the STOP is sent, hardware sets STOPF, throws an event if ITEVFEN is
   high, and waits for a read of SR1 and write CR1

i2c General Reference ---------------------------------------------------------

http://en.wikipedia.org/wiki/I²C

4 modes/roles for a given device. These designations are transaction specific;
a device can switch roles from one transaction to the next:
    master transmit
    master receive
    slave transmit
    slave receive


STM32 Specific Reference ------------------------------------------------------

see stm32 docs: reference manual (doc 13902 rev10) pg637/1003

see STM32F10x_StdPeriph_Lib_V3.2.0/Project/STM32F10x_StdPeriph_Examples/I2C/Interrupt for an example project (reading/writing between the two i2c buses) based on the stm32library

>100khz is "fast mode", which goes up to 400khz. stm32 supports up to 400khz.
    things are different in fast mode: 4mhz input clock

interrupts see pg652/1003
registers see pg654/1003

PEC = packet error checking. don't think this is i2c standard

each i2c port has an error and an event interrupt 

the stm32 is in slave mode by default; it enters master only when executing
a request