From 705d7269323e1d93c4fb8c7afa0aa88d4ae8f6a8 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Mon, 16 Jan 2017 16:17:30 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10055 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/lib/fallback/I2C/hal_i2c_lld.c | 99 +++++++++++++++++++++++++++++++++++ os/hal/lib/fallback/I2C/hal_i2c_lld.h | 42 +++++++++++++-- 2 files changed, 137 insertions(+), 4 deletions(-) (limited to 'os/hal') diff --git a/os/hal/lib/fallback/I2C/hal_i2c_lld.c b/os/hal/lib/fallback/I2C/hal_i2c_lld.c index 6fbdfdd6d..82b17663a 100644 --- a/os/hal/lib/fallback/I2C/hal_i2c_lld.c +++ b/os/hal/lib/fallback/I2C/hal_i2c_lld.c @@ -30,6 +30,11 @@ /* Driver local definitions. */ /*===========================================================================*/ +#define CHECK_ERROR(msg) \ + if ((msg) < (msg_t)0) { \ + return MSG_TIMEOUT; \ + } + /*===========================================================================*/ /* Driver constants. */ /*===========================================================================*/ @@ -66,6 +71,100 @@ I2CDriver I2CD4; /* Driver local functions. */ /*===========================================================================*/ +static msg_t i2c_delay(I2CDriver *i2cp) { + + if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), i2cp->start, i2cp->end)) { + return MSG_TIMEOUT; + } + +#if SW_I2C_USE_OSAL_DELAY || defined(__DOXYGEN__) + osalThreadSleep(i2cp->config->ticks); +#else + i2cp->config->delay(); +#endif + return MSG_OK; +} + +static msg_t i2c_write_start(I2CDriver *i2cp) { + +} + +static msg_t i2c_write_restart(I2CDriver *i2cp) { + +} + +static msg_t i2c_write_stop(I2CDriver *i2cp) { + +} + +static msg_t i2c_writebit(I2CDriver *i2cp, unsigned bit) { + + palWriteLine(i2cp->config->sda, bit); + CHECK_ERROR(i2c_delay(i2cp)); + palSetLine(i2cp->config->scl); + CHECK_ERROR(i2c_delay(i2cp)); + + /* Clock stretching.*/ + while (palReadLine(i2cp->config->scl) == PAL_LOW) { + CHECK_ERROR(i2c_delay(i2cp)); + } + + /* Arbitration check.*/ + if ((bit == PAL_HIGH) && (palReadLine(i2cp->config->sda) == PAL_LOW)) { + i2cp->errors |= I2C_ARBITRATION_LOST; + return MSG_RESET; + } + + palClearLine(i2cp->config->scl); + + return MSG_OK; +} + +static msg_t i2c_readbit(I2CDriver *i2cp) { + msg_t bit; + + palSetLine(i2cp->config->sda); + CHECK_ERROR(i2c_delay(i2cp)); + palSetLine(i2cp->config->scl); + + /* Clock stretching.*/ + while (palReadLine(i2cp->config->scl) == PAL_LOW) { + CHECK_ERROR(i2c_delay(i2cp)); + } + + CHECK_ERROR(i2c_delay(i2cp)); + bit = palReadLine(i2cp->config->sda); + palClearLine(i2cp->config->scl); + + return bit; +} + +static msg_t i2c_writebyte(I2CDriver *i2cp, uint8_t byte) { + uint8_t mask; + + for (mask = 0x80U; mask > 0U; mask >>= 1U) { + CHECK_ERROR(i2c_writebit(i2cp, (byte & mask) != 0)); + } + + return i2c_readbit(i2cp); +} + +static msg_t i2c_readbyte(I2CDriver *i2cp, unsigned nack) { + msg_t byte; + unsigned i; + + byte = 0U; + for (i = 0; i < 8; i++) { + msg_t msg = i2c_readbit(i2cp); + CHECK_ERROR(msg); + byte = (byte << 1U) | msg; + } + + CHECK_ERROR(i2c_writebit(i2cp, PAL_LOW)); + + return byte; +} + /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ diff --git a/os/hal/lib/fallback/I2C/hal_i2c_lld.h b/os/hal/lib/fallback/I2C/hal_i2c_lld.h index 0bcb3dfbe..c6c4908a4 100644 --- a/os/hal/lib/fallback/I2C/hal_i2c_lld.h +++ b/os/hal/lib/fallback/I2C/hal_i2c_lld.h @@ -39,6 +39,16 @@ * @name Configuration options * @{ */ +/** + * @brief Use OSAL delays. + * @details If set to @p TRUE then delays are implemented using the + * thread-friendy delay function else a delay function must + * be provided extenally. + */ +#if !defined(SW_I2C_USE_OSAL_DELAY) || defined(__DOXYGEN__) +#define SW_I2C_USE_OSAL_DELAY TRUE +#endif + /** * @brief I2C1 driver enable switch. * @details If set to @p TRUE the support for I2C1 is included. @@ -94,10 +104,34 @@ typedef uint16_t i2caddr_t; */ typedef uint8_t i2cflags_t; +/** + * @brief Type of a delay function. + */ +typedef void (*i2c_delay_t)(void); + /** * @brief Type of I2C driver configuration structure. */ typedef struct { + /** + * @brief I2C clock line. + */ + ioline_t scl; + /** + * @brief I2C data line. + */ + ioline_t sda; +#if SW_I2C_USE_OSAL_DELAY || defined(__DOXYGEN__) + /** + * @brief Delay of an half bit time in system ticks. + */ + systime_t ticks; +#else + /** + * @brief Pointer to an externally defined delay function. + */ + i2c_delay_t delay; +#endif } I2CConfig; /** @@ -129,13 +163,13 @@ struct I2CDriver { #endif /* End of the mandatory fields.*/ /** - * @brief I2C clock line. + * @brief Time of operation begin. */ - ioline_t clk; + systime_t start; /** - * @brief I2C data line. + * @brief Time of operation timeout. */ - ioline_t data; + systime_t end; }; /*===========================================================================*/ -- cgit v1.2.3