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
|