Skip to content

Commit d492132

Browse files
committed
extmod/machine_i2c_target: Improve events, add memaddr() getter.
Signed-off-by: Damien George <[email protected]>
1 parent 38958d4 commit d492132

File tree

1 file changed

+87
-50
lines changed

1 file changed

+87
-50
lines changed

extmod/machine_i2c_target.c

Lines changed: 87 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,33 @@
3232
#include "shared/runtime/mpirq.h"
3333

3434
enum {
35-
I2C_TARGET_IRQ_ADDR_MATCH = 1 << 0,
36-
I2C_TARGET_IRQ_READ_REQ = 1 << 1,
37-
I2C_TARGET_IRQ_WRITE_REQ = 1 << 2,
38-
I2C_TARGET_IRQ_END = 1 << 3,
39-
I2C_TARGET_IRQ_STOP = 1 << 4, // should be able to support this on all targets (rp2 needs custom code though), but maybe can't support addr_match?
40-
41-
I2C_TARGET_IRQ_MEM_ADDR_MATCH = 1 << 5, // needed?
42-
I2C_TARGET_IRQ_READ_START = 1 << 6, // needed?
43-
I2C_TARGET_IRQ_WRITE_START = 1 << 7, // needed?
44-
I2C_TARGET_IRQ_READ_END = 1 << 8, // needed?
45-
I2C_TARGET_IRQ_WRITE_END = 1 << 9, // needed?
35+
// Events exposed to Python.
36+
I2C_TARGET_IRQ_ADDR_MATCH_READ = 1 << 0,
37+
I2C_TARGET_IRQ_ADDR_MATCH_WRITE = 1 << 1,
38+
I2C_TARGET_IRQ_READ_REQ = 1 << 2,
39+
I2C_TARGET_IRQ_WRITE_REQ = 1 << 3,
40+
I2C_TARGET_IRQ_END_READ = 1 << 4,
41+
I2C_TARGET_IRQ_END_WRITE = 1 << 5,
42+
43+
// Internal events, not exposed to Python.
44+
I2C_TARGET_IRQ_STOP = 1 << 6,
45+
I2C_TARGET_IRQ_MEM_ADDR_MATCH = 1 << 7,
46+
I2C_TARGET_IRQ_READ_START = 1 << 8,
47+
I2C_TARGET_IRQ_WRITE_START = 1 << 9,
4648
};
4749

48-
/*
49-
mp_machine_i2c_target_event_addr_match(*, read_write)
50-
mp_machine_i2c_target_event_read_req(*)
51-
mp_machine_i2c_target_event_write_req(*)
52-
mp_machine_i2c_target_event_stop(*)
53-
*/
50+
// Define the IRQs that require a hard interrupt.
51+
#define I2C_TARGET_IRQ_ALL_HARD ( \
52+
I2C_TARGET_IRQ_ADDR_MATCH_READ \
53+
| I2C_TARGET_IRQ_ADDR_MATCH_WRITE \
54+
| I2C_TARGET_IRQ_READ_REQ \
55+
| I2C_TARGET_IRQ_WRITE_REQ \
56+
)
5457

5558
enum {
5659
STATE_IDLE,
60+
STATE_ADDR_MATCH_READ,
61+
STATE_ADDR_MATCH_WRITE,
5762
STATE_MEM_ADDR_SELECT,
5863
STATE_READING,
5964
STATE_WRITING,
@@ -63,6 +68,7 @@ typedef struct _machine_i2c_target_data_t {
6368
uint8_t state;
6469
uint8_t mem_addr_count;
6570
uint8_t mem_addrsize;
71+
uint32_t mem_addr_last;
6672
uint32_t mem_addr;
6773
uint32_t mem_len;
6874
uint8_t *mem_buf;
@@ -96,23 +102,26 @@ static void mp_machine_i2c_target_deinit(machine_i2c_target_obj_t *self);
96102

97103
static const mp_irq_methods_t machine_i2c_target_irq_methods;
98104

99-
#define I2C_TARGET_NUM_IRQ (4)
105+
static machine_i2c_target_data_t machine_i2c_target_data[MICROPY_PY_MACHINE_I2C_TARGET_MAX];
100106

101107
// Needed to retain a root pointer to the memory object.
102-
MP_REGISTER_ROOT_POINTER(mp_obj_t i2c_target_mem_obj[I2C_TARGET_NUM_IRQ]);
108+
MP_REGISTER_ROOT_POINTER(mp_obj_t machine_i2c_target_mem_obj[MICROPY_PY_MACHINE_I2C_TARGET_MAX]);
103109

104-
MP_REGISTER_ROOT_POINTER(void *machine_i2c_target_irq_obj[I2C_TARGET_NUM_IRQ]);
110+
MP_REGISTER_ROOT_POINTER(void *machine_i2c_target_irq_obj[MICROPY_PY_MACHINE_I2C_TARGET_MAX]);
105111

106112
void mp_machine_i2c_target_deinit_all(void) {
107-
for (size_t i = 0; i < I2C_TARGET_NUM_IRQ; ++i) {
108-
MP_STATE_PORT(i2c_target_mem_obj[i]) = MP_OBJ_NULL;
113+
for (size_t i = 0; i < MICROPY_PY_MACHINE_I2C_TARGET_MAX; ++i) {
114+
MP_STATE_PORT(machine_i2c_target_mem_obj[i]) = MP_OBJ_NULL;
109115
MP_STATE_PORT(machine_i2c_target_irq_obj[i]) = NULL;
110116
}
111117
mp_machine_i2c_target_deinit_all_port();
112118
}
113119

114-
static bool event(machine_i2c_target_data_t *data, unsigned int trigger, size_t arg0, size_t arg1) {
115-
unsigned int id = 0; // TODO
120+
static bool handle_event(machine_i2c_target_data_t *data, unsigned int trigger) {
121+
unsigned int id = data - &machine_i2c_target_data[0];
122+
if (trigger & I2C_TARGET_IRQ_MEM_ADDR_MATCH) {
123+
data->mem_addr_last = data->mem_addr;
124+
}
116125
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[id]);
117126
if (irq != NULL && (trigger & irq->trigger)) {
118127
irq->flags = trigger & irq->trigger;
@@ -126,6 +135,7 @@ static void machine_i2c_target_data_init(machine_i2c_target_data_t *data, mp_obj
126135
data->state = STATE_IDLE;
127136
data->mem_addr_count = 0;
128137
data->mem_addrsize = 0;
138+
data->mem_addr_last = 0;
129139
data->mem_addr = 0;
130140
data->mem_len = 0;
131141
data->mem_buf = NULL;
@@ -143,24 +153,30 @@ static void machine_i2c_target_data_init(machine_i2c_target_data_t *data, mp_obj
143153
}
144154

145155
static void machine_i2c_target_data_reset_helper(machine_i2c_target_data_t *data) {
146-
size_t len = 0; // TODO
147156
if (data->state == STATE_READING) {
148-
event(data, I2C_TARGET_IRQ_READ_END, data->mem_addr, len);
149-
} else if (data->state == STATE_WRITING) {
150-
event(data, I2C_TARGET_IRQ_WRITE_END, data->mem_addr, len);
157+
handle_event(data, I2C_TARGET_IRQ_END_READ);
158+
} else if (data->state == STATE_ADDR_MATCH_WRITE || data->state == STATE_WRITING) {
159+
handle_event(data, I2C_TARGET_IRQ_END_WRITE);
151160
}
152161
data->state = STATE_IDLE;
153162
}
154163

155164
static void machine_i2c_target_data_addr_match(machine_i2c_target_data_t *data, bool read) {
156-
event(data, I2C_TARGET_IRQ_ADDR_MATCH, read, 0);
157165
machine_i2c_target_data_reset_helper(data);
166+
if (read) {
167+
handle_event(data, I2C_TARGET_IRQ_ADDR_MATCH_READ);
168+
data->state = STATE_ADDR_MATCH_READ;
169+
} else {
170+
handle_event(data, I2C_TARGET_IRQ_ADDR_MATCH_WRITE);
171+
data->state = STATE_ADDR_MATCH_WRITE;
172+
}
158173
}
159174

160175
static void machine_i2c_target_data_read_request(machine_i2c_target_obj_t *self, machine_i2c_target_data_t *data) {
161176
// Let the user handle the read request.
162-
bool event_handled = event(data, I2C_TARGET_IRQ_READ_REQ, 0, 0);
177+
bool event_handled = handle_event(data, I2C_TARGET_IRQ_READ_REQ);
163178
if (data->mem_buf == NULL) {
179+
data->state = STATE_READING;
164180
if (!event_handled) {
165181
// No data source, just write out a zero.
166182
uint8_t val = 0;
@@ -171,11 +187,11 @@ static void machine_i2c_target_data_read_request(machine_i2c_target_obj_t *self,
171187
if (data->state == STATE_MEM_ADDR_SELECT) {
172188
// Got a short memory address.
173189
data->mem_addr %= data->mem_len;
174-
event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH, data->mem_addr, 0);
190+
handle_event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH);
175191
}
176192
if (data->state != STATE_READING) {
177193
data->state = STATE_READING;
178-
event(data, I2C_TARGET_IRQ_READ_START, data->mem_addr, 0);
194+
handle_event(data, I2C_TARGET_IRQ_READ_START);
179195
}
180196
uint8_t val = data->mem_buf[data->mem_addr++];
181197
if (data->mem_addr >= data->mem_len) {
@@ -187,21 +203,21 @@ static void machine_i2c_target_data_read_request(machine_i2c_target_obj_t *self,
187203

188204
static void machine_i2c_target_data_write_request(machine_i2c_target_obj_t *self, machine_i2c_target_data_t *data) {
189205
// Let the user handle the write request.
190-
bool event_handled = event(data, I2C_TARGET_IRQ_WRITE_REQ, 0, 0);
206+
bool event_handled = handle_event(data, I2C_TARGET_IRQ_WRITE_REQ);
191207
if (data->mem_buf == NULL) {
208+
data->state = STATE_WRITING;
192209
if (!event_handled) {
193210
// No data sink, just read and discard the incoming byte.
194211
uint8_t buf = 0;
195212
mp_machine_i2c_target_read_bytes(self, 1, &buf);
196213
}
197214
} else {
198215
// Have a buffer.
199-
// TODO test read-write behaviour
200216
uint8_t buf[4] = {0};
201217
size_t n = mp_machine_i2c_target_read_bytes(self, sizeof(buf), &buf[0]);
202218
for (size_t i = 0; i < n; ++i) {
203219
uint8_t val = buf[i];
204-
if (data->state == STATE_IDLE) {
220+
if (data->state == STATE_ADDR_MATCH_WRITE) {
205221
data->state = STATE_MEM_ADDR_SELECT;
206222
data->mem_addr = 0;
207223
data->mem_addr_count = data->mem_addrsize;
@@ -211,12 +227,12 @@ static void machine_i2c_target_data_write_request(machine_i2c_target_obj_t *self
211227
--data->mem_addr_count;
212228
if (data->mem_addr_count == 0) {
213229
data->mem_addr %= data->mem_len;
214-
event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH, data->mem_addr, 0);
230+
handle_event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH);
215231
}
216232
} else {
217233
if (data->state == STATE_MEM_ADDR_SELECT) {
218234
data->state = STATE_WRITING;
219-
event(data, I2C_TARGET_IRQ_WRITE_START, data->mem_addr, 0);
235+
handle_event(data, I2C_TARGET_IRQ_WRITE_START);
220236
}
221237
data->mem_buf[data->mem_addr++] = val;
222238
if (data->mem_addr >= data->mem_len) {
@@ -229,12 +245,11 @@ static void machine_i2c_target_data_write_request(machine_i2c_target_obj_t *self
229245

230246
static inline void machine_i2c_target_data_restart_or_stop(machine_i2c_target_data_t *data) {
231247
machine_i2c_target_data_reset_helper(data);
232-
event(data, I2C_TARGET_IRQ_END, 0, 0);
233248
}
234249

235250
static inline void machine_i2c_target_data_stop(machine_i2c_target_data_t *data) {
236251
machine_i2c_target_data_reset_helper(data);
237-
event(data, I2C_TARGET_IRQ_END | I2C_TARGET_IRQ_STOP, 0, 0);
252+
handle_event(data, I2C_TARGET_IRQ_STOP);
238253
}
239254

240255
// The port provides implementations of its bindings in this file.
@@ -266,9 +281,19 @@ static mp_obj_t machine_i2c_target_write(mp_obj_t self_in, mp_obj_t data_in) {
266281
}
267282
static MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_target_write_obj, machine_i2c_target_write);
268283

284+
// I2CTarget.memaddr()
285+
static mp_obj_t machine_i2c_target_memaddr(mp_obj_t self_in) {
286+
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
287+
size_t index = mp_machine_i2c_target_get_index(self);
288+
machine_i2c_target_data_t *data = &machine_i2c_target_data[index];
289+
return mp_obj_new_int(data->mem_addr_last);
290+
}
291+
static MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_target_memaddr_obj, machine_i2c_target_memaddr);
292+
269293
static machine_i2c_target_irq_obj_t *machine_i2c_target_get_irq(machine_i2c_target_obj_t *self) {
270294
// Get the IRQ object.
271-
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[0]);
295+
size_t index = mp_machine_i2c_target_get_index(self);
296+
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
272297

273298
// Allocate the IRQ object if it doesn't already exist.
274299
if (irq == NULL) {
@@ -278,17 +303,17 @@ static machine_i2c_target_irq_obj_t *machine_i2c_target_get_irq(machine_i2c_targ
278303
irq->base.parent = MP_OBJ_FROM_PTR(self);
279304
irq->base.handler = mp_const_none;
280305
irq->base.ishard = false;
281-
MP_STATE_PORT(machine_i2c_target_irq_obj[0]) = irq;
306+
MP_STATE_PORT(machine_i2c_target_irq_obj[index]) = irq;
282307
}
283308
return irq;
284309
}
285310

286-
// I2CTarget.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
311+
// I2CTarget.irq(handler=None, trigger=IRQ_END_READ|IRQ_END_WRITE, hard=False)
287312
static mp_obj_t machine_i2c_target_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
288313
enum { ARG_handler, ARG_trigger, ARG_hard };
289314
static const mp_arg_t allowed_args[] = {
290315
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
291-
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} },
316+
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = I2C_TARGET_IRQ_END_READ | I2C_TARGET_IRQ_END_WRITE} },
292317
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
293318
};
294319
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
@@ -304,9 +329,15 @@ static mp_obj_t machine_i2c_target_irq(size_t n_args, const mp_obj_t *pos_args,
304329
mp_uint_t trigger = args[ARG_trigger].u_int;
305330
bool hard = args[ARG_hard].u_bool;
306331

307-
if (!hard) {
332+
#if MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ
333+
if ((trigger & I2C_TARGET_IRQ_ALL_HARD) && !hard) {
308334
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ required"));
309335
}
336+
#else
337+
if (hard) {
338+
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ unsupported"));
339+
}
340+
#endif
310341

311342
// Disable all IRQs while data is updated.
312343
mp_machine_i2c_target_irq_config(self, 0);
@@ -330,13 +361,17 @@ static const mp_rom_map_elem_t machine_i2c_target_locals_dict_table[] = {
330361
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2c_target_deinit_obj) },
331362
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&machine_i2c_target_readinto_obj) },
332363
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&machine_i2c_target_write_obj) },
364+
{ MP_ROM_QSTR(MP_QSTR_memaddr), MP_ROM_PTR(&machine_i2c_target_memaddr_obj) },
333365
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2c_target_irq_obj) },
334366

335-
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH) },
367+
#if MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ
368+
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH_READ), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH_READ) },
369+
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH_WRITE), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH_WRITE) },
336370
{ MP_ROM_QSTR(MP_QSTR_IRQ_READ_REQ), MP_ROM_INT(I2C_TARGET_IRQ_READ_REQ) },
337371
{ MP_ROM_QSTR(MP_QSTR_IRQ_WRITE_REQ), MP_ROM_INT(I2C_TARGET_IRQ_WRITE_REQ) },
338-
{ MP_ROM_QSTR(MP_QSTR_IRQ_END), MP_ROM_INT(I2C_TARGET_IRQ_END) },
339-
{ MP_ROM_QSTR(MP_QSTR_IRQ_STOP), MP_ROM_INT(I2C_TARGET_IRQ_STOP) },
372+
#endif
373+
{ MP_ROM_QSTR(MP_QSTR_IRQ_END_READ), MP_ROM_INT(I2C_TARGET_IRQ_END_READ) },
374+
{ MP_ROM_QSTR(MP_QSTR_IRQ_END_WRITE), MP_ROM_INT(I2C_TARGET_IRQ_END_WRITE) },
340375
};
341376
static MP_DEFINE_CONST_DICT(machine_i2c_target_locals_dict, machine_i2c_target_locals_dict_table);
342377

@@ -351,7 +386,8 @@ MP_DEFINE_CONST_OBJ_TYPE(
351386

352387
static mp_uint_t machine_i2c_target_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
353388
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
354-
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[0]);
389+
size_t index = mp_machine_i2c_target_get_index(self);
390+
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
355391
mp_machine_i2c_target_irq_config(self, 0);
356392
irq->flags = 0;
357393
irq->trigger = new_trigger;
@@ -360,8 +396,9 @@ static mp_uint_t machine_i2c_target_irq_trigger(mp_obj_t self_in, mp_uint_t new_
360396
}
361397

362398
static mp_uint_t machine_i2c_target_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
363-
// machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
364-
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[0]);
399+
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
400+
size_t index = mp_machine_i2c_target_get_index(self);
401+
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
365402
if (info_type == MP_IRQ_INFO_FLAGS) {
366403
return irq->flags;
367404
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {

0 commit comments

Comments
 (0)