Skip to content

Commit 423ca03

Browse files
committedMar 3, 2016
runtime: bit-banged i2c support (untested)
1 parent 73bfbe5 commit 423ca03

File tree

5 files changed

+214
-2
lines changed

5 files changed

+214
-2
lines changed
 

Diff for: ‎artiq/gateware/targets/kc705.py

+1
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ def __init__(self, cpu_type="or1k", **kwargs):
353353
i2c = platform.request("i2c")
354354
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
355355
self.register_kernel_cpu_csrdevice("i2c")
356+
self.config["I2C_BUS_COUNT"] = 1
356357

357358

358359
def main():

Diff for: ‎artiq/runtime/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ OBJECTS := isr.o clock.o rtiocrg.o flash_storage.o mailbox.o \
77
session.o log.o analyzer.o moninj.o net_server.o bridge_ctl.o \
88
ksupport_data.o kloader.o test_mode.o main.o
99
OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.o \
10-
bridge.o rtio.o dds.o
10+
bridge.o rtio.o dds.o i2c.o
1111

1212
CFLAGS += -I$(LIBALLOC_DIRECTORY) \
1313
-I$(MISOC_DIRECTORY)/software/include/dyld \

Diff for: ‎artiq/runtime/i2c.c

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#include <generated/csr.h>
2+
3+
#include "rtio.h"
4+
#include "i2c.h"
5+
6+
7+
static void i2c_halfperiod()
8+
{
9+
timer_kernel_en_write(0);
10+
timer_kernel_load_write(CONFIG_CLOCK_FREQUENCY/10000);
11+
timer_kernel_reload_write(0);
12+
timer_kernel_en_write(1);
13+
14+
timer_kernel_update_value_write(1);
15+
while(timer_kernel_value_read() != 0)
16+
timer_kernel_update_value_write(1);
17+
}
18+
19+
#if (defined CONFIG_I2C_BUS_COUNT) && (CONFIG_I2C_BUS_COUNT > 0)
20+
21+
#define SDA_BIT (1 << (2*busno + 1))
22+
#define SCL_BIT (1 << (2*busno))
23+
24+
static int i2c_sda_i(int busno)
25+
{
26+
if(busno >= CONFIG_I2C_BUS_COUNT)
27+
return 1;
28+
else
29+
return i2c_in_read() & SDA_BIT;
30+
}
31+
32+
static void i2c_sda_oe(int busno, int oe)
33+
{
34+
int reg;
35+
36+
reg = i2c_oe_read();
37+
if(oe)
38+
reg |= SDA_BIT;
39+
else
40+
reg &= ~SDA_BIT;
41+
i2c_oe_write(reg);
42+
}
43+
44+
static void i2c_sda_o(int busno, int o)
45+
{
46+
int reg;
47+
48+
reg = i2c_out_read();
49+
if(o)
50+
reg |= SDA_BIT;
51+
else
52+
reg &= ~SDA_BIT;
53+
i2c_out_write(reg);
54+
}
55+
56+
static void i2c_scl_oe(int busno, int oe)
57+
{
58+
int reg;
59+
60+
reg = i2c_oe_read();
61+
if(oe)
62+
reg |= SCL_BIT;
63+
else
64+
reg &= ~SCL_BIT;
65+
i2c_oe_write(reg);
66+
}
67+
68+
static void i2c_scl_o(int busno, int o)
69+
{
70+
int reg;
71+
72+
reg = i2c_out_read();
73+
if(o)
74+
reg |= SCL_BIT;
75+
else
76+
reg &= ~SCL_BIT;
77+
i2c_out_write(reg);
78+
}
79+
80+
#else
81+
82+
static int i2c_sda_i(int busno)
83+
{
84+
return 1;
85+
}
86+
static void i2c_sda_oe(int busno, int oe) {}
87+
static void i2c_sda_o(int busno, int o) {}
88+
static void i2c_scl_oe(int busno, int oe) {}
89+
static void i2c_scl_o(int busno, int o) {}
90+
91+
#endif
92+
93+
94+
int i2c_init(int busno)
95+
{
96+
/* Set SCL as output, and high level */
97+
i2c_scl_o(busno, 1);
98+
i2c_scl_oe(busno, 1);
99+
/* Prepare a zero level on SDA so that i2c_sda_oe pulls it down */
100+
i2c_sda_o(busno, 0);
101+
/* Release SDA */
102+
i2c_sda_oe(busno, 0);
103+
104+
/* Check the I2C bus is ready */
105+
i2c_halfperiod();
106+
i2c_halfperiod();
107+
if(i2c_sda_i(busno))
108+
return 1; /* success */
109+
else
110+
return 0;
111+
}
112+
113+
void i2c_start(int busno)
114+
{
115+
/* Set SCL high then SDA low */
116+
i2c_scl_o(busno, 1);
117+
i2c_halfperiod();
118+
i2c_sda_oe(busno, 1);
119+
i2c_halfperiod();
120+
}
121+
122+
void i2c_stop(int busno)
123+
{
124+
/* First, make sure SCL is low, so that the target releases the SDA line */
125+
i2c_scl_o(busno, 0);
126+
i2c_halfperiod();
127+
/* Set SCL high then SDA high */
128+
i2c_sda_oe(busno, 1);
129+
i2c_scl_o(busno, 1);
130+
i2c_halfperiod();
131+
i2c_sda_oe(busno, 0);
132+
i2c_halfperiod();
133+
}
134+
135+
int i2c_write(int busno, char b)
136+
{
137+
int i;
138+
139+
/* MSB first */
140+
for(i=7;i>=0;i--) {
141+
/* Set SCL low and set our bit on SDA */
142+
i2c_scl_o(busno, 0);
143+
i2c_sda_oe(busno, b & (1 << i) ? 0 : 1);
144+
i2c_halfperiod();
145+
/* Set SCL high ; data is shifted on the rising edge of SCL */
146+
i2c_scl_o(busno, 1);
147+
i2c_halfperiod();
148+
}
149+
/* Check ack */
150+
/* Set SCL low, then release SDA so that the I2C target can respond */
151+
i2c_scl_o(busno, 0);
152+
i2c_halfperiod();
153+
i2c_sda_oe(busno, 0);
154+
/* Set SCL high and check for ack */
155+
i2c_scl_o(busno, 1);
156+
i2c_halfperiod();
157+
/* returns 1 if acked (I2C target pulled SDA low) */
158+
return !i2c_sda_i(busno);
159+
}
160+
161+
char i2c_read(int busno, int ack)
162+
{
163+
int i;
164+
char b;
165+
166+
/* Set SCL low first, otherwise setting SDA as input may cause a transition
167+
* on SDA with SCL high which will be interpreted as START/STOP condition.
168+
*/
169+
i2c_scl_o(busno, 0);
170+
i2c_halfperiod(); /* make sure SCL has settled low */
171+
i2c_sda_oe(busno, 0);
172+
173+
b = 0;
174+
/* MSB first */
175+
for(i=7;i>=0;i--) {
176+
i2c_scl_o(busno, 0);
177+
i2c_halfperiod();
178+
/* Set SCL high and shift data */
179+
i2c_scl_o(busno, 1);
180+
i2c_halfperiod();
181+
if(i2c_sda_i(busno)) b |= (1 << i);
182+
}
183+
/* Send ack */
184+
/* Set SCL low and pull SDA low when acking */
185+
i2c_scl_o(busno, 0);
186+
if(ack)
187+
i2c_sda_oe(busno, 1);
188+
i2c_halfperiod();
189+
/* then set SCL high */
190+
i2c_scl_o(busno, 1);
191+
i2c_halfperiod();
192+
193+
return b;
194+
}

Diff for: ‎artiq/runtime/i2c.h

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef __I2C_H
2+
#define __I2C_H
3+
4+
int i2c_init(int busno);
5+
void i2c_start(int busno);
6+
void i2c_stop(int busno);
7+
int i2c_write(int busno, char b);
8+
char i2c_read(int busno, int ack);
9+
10+
#endif

Diff for: ‎artiq/runtime/ksupport.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
#include "messages.h"
1414
#include "bridge.h"
1515
#include "artiq_personality.h"
16-
#include "dds.h"
1716
#include "rtio.h"
17+
#include "dds.h"
18+
#include "i2c.h"
1819

1920
double round(double x);
2021

@@ -117,6 +118,12 @@ static const struct symbol runtime_exports[] = {
117118
{"dds_batch_exit", &dds_batch_exit},
118119
{"dds_set", &dds_set},
119120

121+
{"i2c_init", &i2c_init},
122+
{"i2c_start", &i2c_start},
123+
{"i2c_stop", &i2c_stop},
124+
{"i2c_write", &i2c_write},
125+
{"i2c_read", &i2c_read},
126+
120127
{"cache_get", &cache_get},
121128
{"cache_put", &cache_put},
122129

0 commit comments

Comments
 (0)
Please sign in to comment.