aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
authorGiovanni Di Sirio <gdisirio@gmail.com>2017-01-17 13:20:48 +0000
committerGiovanni Di Sirio <gdisirio@gmail.com>2017-01-17 13:20:48 +0000
commit4765efbaa9d939601a65b63a7f43cbe44e947aec (patch)
tree6bb13737d3cfe511417ab9bd3a5ab3cc0ee2d178 /os/hal
parentea894a4583d431b127489b02ce3f5450bfec94a5 (diff)
downloadChibiOS-4765efbaa9d939601a65b63a7f43cbe44e947aec.tar.gz
ChibiOS-4765efbaa9d939601a65b63a7f43cbe44e947aec.tar.bz2
ChibiOS-4765efbaa9d939601a65b63a7f43cbe44e947aec.zip
I2C fallback driver finished, to be tested.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10059 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/lib/fallback/I2C/hal_i2c_lld.c252
-rw-r--r--os/hal/lib/fallback/I2C/hal_i2c_lld.h4
2 files changed, 193 insertions, 63 deletions
diff --git a/os/hal/lib/fallback/I2C/hal_i2c_lld.c b/os/hal/lib/fallback/I2C/hal_i2c_lld.c
index 82b17663a..77b9e2e29 100644
--- a/os/hal/lib/fallback/I2C/hal_i2c_lld.c
+++ b/os/hal/lib/fallback/I2C/hal_i2c_lld.c
@@ -71,48 +71,110 @@ I2CDriver I2CD4;
/* Driver local functions. */
/*===========================================================================*/
-static msg_t i2c_delay(I2CDriver *i2cp) {
+static msg_t i2c_write_stop(I2CDriver *i2cp);
- if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
- return MSG_TIMEOUT;
- }
+static inline void i2c_delay(I2CDriver *i2cp) {
#if SW_I2C_USE_OSAL_DELAY || defined(__DOXYGEN__)
osalThreadSleep(i2cp->config->ticks);
#else
i2cp->config->delay();
#endif
+}
+
+static inline msg_t i2c_check_arbitration(I2CDriver *i2cp) {
+
+ if (palReadLine(i2cp->config->sda) == PAL_LOW) {
+ i2cp->errors |= I2C_ARBITRATION_LOST;
+ return MSG_RESET;
+ }
+
+ return MSG_OK;
+}
+
+static inline msg_t i2c_check_timeout(I2CDriver *i2cp) {
+
+ if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
+ i2c_write_stop(i2cp);
+ return MSG_TIMEOUT;
+ }
+
+ return MSG_OK;
+}
+
+static msg_t i2c_wait_clock(I2CDriver *i2cp) {
+
+ while (palReadLine(i2cp->config->scl) == PAL_LOW) {
+ if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) {
+ return MSG_TIMEOUT;
+ }
+ i2c_delay(i2cp);
+ }
+
return MSG_OK;
}
-static msg_t i2c_write_start(I2CDriver *i2cp) {
+static inline msg_t i2c_write_start(I2CDriver *i2cp) {
+
+ /* Arbitration check.*/
+ CHECK_ERROR(i2c_check_arbitration(i2cp));
+ palClearLine(i2cp->config->sda);
+ i2c_delay(i2cp);
+ palClearLine(i2cp->config->scl);
+
+ return MSG_OK;
}
static msg_t i2c_write_restart(I2CDriver *i2cp) {
+ palSetLine(i2cp->config->sda);
+ i2c_delay(i2cp);
+ palSetLine(i2cp->config->scl);
+
+ /* Clock stretching.*/
+ CHECK_ERROR(i2c_wait_clock(i2cp));
+
+ i2c_delay(i2cp);
+ i2c_write_start(i2cp);
+
+ return MSG_OK;
}
static msg_t i2c_write_stop(I2CDriver *i2cp) {
+ palClearLine(i2cp->config->sda);
+ i2c_delay(i2cp);
+ palSetLine(i2cp->config->scl);
+
+ /* Clock stretching.*/
+ CHECK_ERROR(i2c_wait_clock(i2cp));
+
+ i2c_delay(i2cp);
+ palSetLine(i2cp->config->sda);
+ i2c_delay(i2cp);
+
+ /* Arbitration check.*/
+ CHECK_ERROR(i2c_check_arbitration(i2cp));
+
+ i2c_delay(i2cp);
+
+ return MSG_OK;
}
-static msg_t i2c_writebit(I2CDriver *i2cp, unsigned bit) {
+static msg_t i2c_write_bit(I2CDriver *i2cp, unsigned bit) {
palWriteLine(i2cp->config->sda, bit);
- CHECK_ERROR(i2c_delay(i2cp));
+ i2c_delay(i2cp);
palSetLine(i2cp->config->scl);
- CHECK_ERROR(i2c_delay(i2cp));
+ i2c_delay(i2cp);
/* Clock stretching.*/
- while (palReadLine(i2cp->config->scl) == PAL_LOW) {
- CHECK_ERROR(i2c_delay(i2cp));
- }
+ CHECK_ERROR(i2c_wait_clock(i2cp));
/* Arbitration check.*/
- if ((bit == PAL_HIGH) && (palReadLine(i2cp->config->sda) == PAL_LOW)) {
- i2cp->errors |= I2C_ARBITRATION_LOST;
- return MSG_RESET;
+ if (bit == PAL_HIGH) {
+ CHECK_ERROR(i2c_check_arbitration(i2cp));
}
palClearLine(i2cp->config->scl);
@@ -120,51 +182,95 @@ static msg_t i2c_writebit(I2CDriver *i2cp, unsigned bit) {
return MSG_OK;
}
-static msg_t i2c_readbit(I2CDriver *i2cp) {
+static msg_t i2c_read_bit(I2CDriver *i2cp) {
msg_t bit;
palSetLine(i2cp->config->sda);
- CHECK_ERROR(i2c_delay(i2cp));
+ i2c_delay(i2cp);
palSetLine(i2cp->config->scl);
/* Clock stretching.*/
- while (palReadLine(i2cp->config->scl) == PAL_LOW) {
- CHECK_ERROR(i2c_delay(i2cp));
- }
+ CHECK_ERROR(i2c_wait_clock(i2cp));
- CHECK_ERROR(i2c_delay(i2cp));
+ i2c_delay(i2cp);
bit = palReadLine(i2cp->config->sda);
palClearLine(i2cp->config->scl);
return bit;
}
-static msg_t i2c_writebyte(I2CDriver *i2cp, uint8_t byte) {
+static msg_t i2c_write_byte(I2CDriver *i2cp, uint8_t byte) {
+ msg_t msg;
uint8_t mask;
+ CHECK_ERROR(i2c_check_timeout(i2cp));
+
for (mask = 0x80U; mask > 0U; mask >>= 1U) {
- CHECK_ERROR(i2c_writebit(i2cp, (byte & mask) != 0));
+ CHECK_ERROR(i2c_write_bit(i2cp, (byte & mask) != 0));
}
- return i2c_readbit(i2cp);
+ msg = i2c_read_bit(i2cp);
+ CHECK_ERROR(msg);
+
+ /* Checking for NACK.*/
+ if (msg == PAL_HIGH) {
+ i2cp->errors |= I2C_ACK_FAILURE;
+ return MSG_RESET;
+ }
+
+ return MSG_OK;
}
-static msg_t i2c_readbyte(I2CDriver *i2cp, unsigned nack) {
+static msg_t i2c_read_byte(I2CDriver *i2cp, unsigned nack) {
msg_t byte;
unsigned i;
+ CHECK_ERROR(i2c_check_timeout(i2cp));
+
byte = 0U;
for (i = 0; i < 8; i++) {
- msg_t msg = i2c_readbit(i2cp);
+ msg_t msg = i2c_read_bit(i2cp);
CHECK_ERROR(msg);
byte = (byte << 1U) | msg;
}
- CHECK_ERROR(i2c_writebit(i2cp, PAL_LOW));
+ CHECK_ERROR(i2c_write_bit(i2cp, nack));
return byte;
}
+static msg_t i2c_write_header(I2CDriver *i2cp, i2caddr_t addr, bool rw) {
+
+ CHECK_ERROR(i2c_write_start(i2cp));
+
+ /* Check for 10 bits addressing.*/
+ if (i2cp->config->addr10) {
+ /* It is 10 bits.*/
+ uint8_t b1, b2;
+
+ b1 = 0xF0U | ((addr >> 8U) << 1U);
+ b2 = (uint8_t)(addr & 255U);
+ if (rw) {
+ b1 |= 1U;
+ }
+ CHECK_ERROR(i2c_write_byte(i2cp, b1));
+ CHECK_ERROR(i2c_write_byte(i2cp, b2));
+ }
+ else {
+ /* It is 7 bits.*/
+ if (rw) {
+ /* Read.*/
+ CHECK_ERROR(i2c_write_byte(i2cp, (addr << 1U) | 1U));
+ }
+ else {
+ /* Write.*/
+ CHECK_ERROR(i2c_write_byte(i2cp, (addr << 1U) | 0U));
+ }
+ }
+
+ return MSG_OK;
+}
+
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
@@ -182,7 +288,16 @@ void i2c_lld_init(void) {
#if SW_I2C_USE_I2C1
i2cObjectInit(&I2CD1);
-#endif /* SW_I2C_USE_I2C1 */
+#endif
+#if SW_I2C_USE_I2C2
+ i2cObjectInit(&I2CD2);
+#endif
+#if SW_I2C_USE_I2C3
+ i2cObjectInit(&I2CD3);
+#endif
+#if SW_I2C_USE_I2C4
+ i2cObjectInit(&I2CD4);
+#endif
}
/**
@@ -194,14 +309,8 @@ void i2c_lld_init(void) {
*/
void i2c_lld_start(I2CDriver *i2cp) {
- /* If in stopped state then enables the I2C and DMA clocks.*/
- if (i2cp->state == I2C_STOP) {
-
-#if SW_I2C_USE_I2C1
- if (&I2CD1 == i2cp) {
- }
-#endif /* SW_I2C_USE_I2C1 */
- }
+ /* Does nothing.*/
+ (void)i2cp;
}
/**
@@ -213,17 +322,8 @@ void i2c_lld_start(I2CDriver *i2cp) {
*/
void i2c_lld_stop(I2CDriver *i2cp) {
- /* If not in stopped state then disables the I2C clock.*/
- if (i2cp->state != I2C_STOP) {
-
- /* I2C disable.*/
- //i2c_lld_abort_operation(i2cp);
-
-#if SW_I2C_USE_I2C1
- if (&I2CD1 == i2cp) {
- }
-#endif
- }
+ /* Does nothing.*/
+ (void)i2cp;
}
/**
@@ -250,15 +350,25 @@ void i2c_lld_stop(I2CDriver *i2cp) {
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout) {
- msg_t msg = MSG_OK;
- (void)i2cp;
- (void)addr;
- (void)rxbuf;
- (void)rxbytes;
- (void)timeout;
+ /* Setting timeout fields.*/
+ i2cp->start = osalOsGetSystemTimeX();
+ i2cp->end = i2cp->start;
+ if (timeout != TIME_INFINITE) {
+ i2cp->end += timeout;
+ }
+
+ /* Sending anddress and mode.*/
+ CHECK_ERROR(i2c_write_header(i2cp, addr, true));
+
+ do {
+ /* Last byte sends a NACK.*/
+ msg_t msg = i2c_read_byte(i2cp, rxbytes > 1U ? 0U : 1U);
+ CHECK_ERROR(msg);
+ *rxbuf++ = (uint8_t)msg;
+ } while (--rxbytes);
- return msg;
+ return i2c_write_stop(i2cp);
}
/**
@@ -290,17 +400,33 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout) {
- msg_t msg = MSG_OK;
- (void)i2cp;
- (void)addr;
- (void)txbuf;
- (void)txbytes;
- (void)rxbuf;
- (void)rxbytes;
- (void)timeout;
-
- return msg;
+ /* Setting timeout fields.*/
+ i2cp->start = osalOsGetSystemTimeX();
+ i2cp->end = i2cp->start;
+ if (timeout != TIME_INFINITE) {
+ i2cp->end += timeout;
+ }
+
+ /* Sending anddress and mode.*/
+ CHECK_ERROR(i2c_write_header(i2cp, addr, false));
+
+ do {
+ CHECK_ERROR(i2c_write_byte(i2cp, *txbuf++));
+ } while (--txbytes);
+
+ /* Is there a read phase? */
+ if (rxbytes > 0U) {
+ CHECK_ERROR(i2c_write_restart(i2cp));
+ do {
+ /* Last byte sends a NACK.*/
+ msg_t msg = i2c_read_byte(i2cp, rxbytes > 1U ? 0U : 1U);
+ CHECK_ERROR(msg);
+ *rxbuf++ = (uint8_t)msg;
+ } while (--rxbytes);
+ }
+
+ return i2c_write_stop(i2cp);
}
#endif /* HAL_USE_I2C */
diff --git a/os/hal/lib/fallback/I2C/hal_i2c_lld.h b/os/hal/lib/fallback/I2C/hal_i2c_lld.h
index c6c4908a4..5b63bc6cd 100644
--- a/os/hal/lib/fallback/I2C/hal_i2c_lld.h
+++ b/os/hal/lib/fallback/I2C/hal_i2c_lld.h
@@ -114,6 +114,10 @@ typedef void (*i2c_delay_t)(void);
*/
typedef struct {
/**
+ * @brief 10 bits addressing switch.
+ */
+ bool addr10;
+ /**
* @brief I2C clock line.
*/
ioline_t scl;