Skip to content

Commit a3474ff

Browse files
committed
pbio/drv/i2c/i2c_ev3.c: Implement I2C operation
This implements performing an I2C operation asynchronously. It does not hook this up to any higher-level functionality.
1 parent 2a8cd62 commit a3474ff

File tree

2 files changed

+98
-12
lines changed

2 files changed

+98
-12
lines changed

lib/pbio/drv/i2c/i2c_ev3.c

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,75 @@ static void pbdrv_i2c_irq_3(void) {
100100
pbio_os_request_poll();
101101
}
102102

103-
pbio_error_t pbdrv_i2c_placeholder_operation(pbdrv_i2c_dev_t *i2c_dev, const char *operation) {
104-
debug_pr("I2C placeholder operation %s\n", operation);
105-
return PBIO_SUCCESS;
103+
pbio_error_t pbdrv_i2c_placeholder_operation(
104+
pbio_os_state_t *state,
105+
pbdrv_i2c_dev_t *i2c_dev,
106+
uint8_t dev_addr,
107+
const uint8_t *wdata,
108+
size_t wlen,
109+
uint8_t *rdata,
110+
size_t rlen,
111+
bool nxt_quirk) {
112+
113+
PBIO_OS_ASYNC_BEGIN(state);
114+
115+
if (wlen && !wdata) {
116+
return PBIO_ERROR_INVALID_ARG;
117+
}
118+
if (rlen && !rdata) {
119+
return PBIO_ERROR_INVALID_ARG;
120+
}
121+
if (wlen > 0xff || rlen > 0xff) {
122+
return PBIO_ERROR_INVALID_ARG;
123+
}
124+
125+
if (i2c_dev->busy) {
126+
return PBIO_ERROR_BUSY;
127+
}
128+
129+
// Prepare TX data
130+
if (wlen) {
131+
memcpy(i2c_dev->buffer, wdata, wlen);
132+
}
133+
i2c_dev->busy = true;
134+
pbdrv_cache_prepare_before_dma(i2c_dev->buffer, PRU_I2C_MAX_BYTES_PER_TXN);
135+
136+
// Kick off transfer
137+
pbdrv_rproc_ev3_pru1_shared_ram.i2c[i2c_dev->pru_i2c_idx].flags = PBDRV_RPROC_EV3_PRU1_I2C_PACK_FLAGS(
138+
dev_addr,
139+
rlen,
140+
wlen,
141+
PBDRV_RPROC_EV3_PRU1_I2C_CMD_START | (nxt_quirk ? PBDRV_RPROC_EV3_PRU1_I2C_CMD_NXT_QUIRK : 0)
142+
);
143+
144+
// Wait for transfer to finish
145+
PBIO_OS_AWAIT_WHILE(state, i2c_dev->busy);
146+
147+
uint32_t flags = pbdrv_rproc_ev3_pru1_shared_ram.i2c[i2c_dev->pru_i2c_idx].flags;
148+
debug_pr("i2c %d done flags %08x\r\n", i2c_dev->pru_i2c_idx, flags);
149+
if (!(flags & PBDRV_RPROC_EV3_PRU1_I2C_STAT_DONE)) {
150+
debug_pr("i2c %d not actually done???\r\n", i2c_dev->pru_i2c_idx);
151+
return PBIO_ERROR_FAILED;
152+
}
153+
switch (flags & PBDRV_RPROC_EV3_PRU1_I2C_STAT_MASK) {
154+
case PBDRV_RPROC_EV3_PRU1_I2C_STAT_OK:
155+
break;
156+
case PBDRV_RPROC_EV3_PRU1_I2C_STAT_TIMEOUT:
157+
return PBIO_ERROR_TIMEDOUT;
158+
case PBDRV_RPROC_EV3_PRU1_I2C_STAT_NAK:
159+
return PBIO_ERROR_IO;
160+
default:
161+
debug_pr("i2c %d unknown error occurred???\r\n", i2c_dev->pru_i2c_idx);
162+
return PBIO_ERROR_FAILED;
163+
}
164+
165+
// If we got here, there's no error. Copy RX data.
166+
pbdrv_cache_prepare_after_dma(i2c_dev->buffer, PRU_I2C_MAX_BYTES_PER_TXN);
167+
if (rlen) {
168+
memcpy(rdata, &i2c_dev->buffer[wlen], rlen);
169+
}
170+
171+
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
106172
}
107173

108174
static pbio_os_process_t ev3_i2c_init_process;

lib/pbio/include/pbdrv/i2c.h

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <pbdrv/config.h>
1515
#include <pbio/error.h>
16+
#include <pbio/os.h>
1617
#include <pbio/port.h>
1718
#include <contiki.h>
1819

@@ -30,16 +31,27 @@ typedef struct _pbdrv_i2c_dev_t pbdrv_i2c_dev_t;
3031
pbio_error_t pbdrv_i2c_get_instance(uint8_t id, pbdrv_i2c_dev_t **i2c_dev);
3132

3233
/**
33-
* Does an I2C operation. To be replaced.
34+
* Does an I2C operation. To be integrated with higher-level code.
3435
*
35-
* Doesn't do anything yet. This is a placeholder so someone knowledgable with
36-
* EV3 I2C has a starting point without setting up all the boilerplate.
37-
*
38-
* @param [in] i2c_dev The I2C device.
39-
* @param [in] operation Dummy parameter.
40-
* @return ::PBIO_SUCCESS on success.
36+
* @param [in] state Protothread state for async operation.
37+
* @param [in] i2c_dev The I2C device.
38+
* @param [in] dev_addr I2C device address (unshifted).
39+
* @param [in] wdata Data to be sent to the device.
40+
* @param [in] wlen Length of \p wdata.
41+
* @param [out] rdata Buffer for data read from the device.
42+
* @param [in] rlen Size of \p rdata.
43+
* @param [in] nxt_quirk Whether to use NXT I2C transaction quirk.
44+
* @return ::PBIO_SUCCESS on success.
4145
*/
42-
pbio_error_t pbdrv_i2c_placeholder_operation(pbdrv_i2c_dev_t *i2c_dev, const char *operation);
46+
pbio_error_t pbdrv_i2c_placeholder_operation(
47+
pbio_os_state_t *state,
48+
pbdrv_i2c_dev_t *i2c_dev,
49+
uint8_t dev_addr,
50+
const uint8_t *wdata,
51+
size_t wlen,
52+
uint8_t *rdata,
53+
size_t rlen,
54+
bool nxt_quirk);
4355

4456
// Delete above and add read/write functions here. See I2C driver for examples, also protothreads.
4557

@@ -50,7 +62,15 @@ static inline pbio_error_t pbdrv_i2c_get_instance(uint8_t id, pbdrv_i2c_dev_t **
5062
return PBIO_ERROR_NOT_SUPPORTED;
5163
}
5264

53-
static inline pbio_error_t pbdrv_i2c_placeholder_operation(pbdrv_i2c_dev_t *i2c_dev, const char *operation) {
65+
static inline pbio_error_t pbdrv_i2c_placeholder_operation(
66+
pbio_os_state_t *state,
67+
pbdrv_i2c_dev_t *i2c_dev,
68+
uint8_t dev_addr,
69+
const uint8_t *wdata,
70+
size_t wlen,
71+
uint8_t *rdata,
72+
size_t rlen,
73+
bool nxt_quirk) {
5474
return PBIO_ERROR_NOT_SUPPORTED;
5575
}
5676

0 commit comments

Comments
 (0)