From c3b9392212cb43a5496c80f3d2ab61ce4caf1dab Mon Sep 17 00:00:00 2001 From: gdisirio Date: Mon, 19 Aug 2013 11:45:52 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6175 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/i2c.h | 26 ++++++ os/hal/osal/chibios/osal.h | 29 ++++++- os/hal/platforms/STM32/I2Cv2/i2c_lld.c | 139 +++++++++++---------------------- os/hal/platforms/STM32/I2Cv2/i2c_lld.h | 9 ++- 4 files changed, 106 insertions(+), 97 deletions(-) (limited to 'os/hal') diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index b70767609..dfae26e64 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -92,6 +92,32 @@ typedef enum { /* Driver macros. */ /*===========================================================================*/ +/** + * @brief Wakes up the waiting thread notifying no errors. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define _i2c_wakeup_isr(i2cp) do { \ + osalSysLockFromISR(); \ + osalThreadResumeI(&(i2cp)->thread, MSG_OK); \ + osalSysUnlockFromISR(); \ +} while(0) + +/** + * @brief Wakes up the waiting thread notifying errors. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define _i2c_wakeup_error_isr(i2cp) do { \ + osalSysLockFromISR(); \ + osalThreadResumeI(&(i2cp)->thread, MSG_RESET); \ + osalSysUnlockFromISR(); \ +} while(0) + /** * @brief Wrap i2cMasterTransmitTimeout function with TIME_INFINITE timeout. * @api diff --git a/os/hal/osal/chibios/osal.h b/os/hal/osal/chibios/osal.h index 4114ddfc9..d3d2e2b40 100644 --- a/os/hal/osal/chibios/osal.h +++ b/os/hal/osal/chibios/osal.h @@ -383,7 +383,6 @@ static inline void osalSysUnlockFromISR(void) { chSysUnlockFromISR(); } -#if CH_PORT_SUPPORTS_RT || defined(__DOXYGEN__) /** * @brief Polled delay. * @note The real delay is always few cycles in excess of the specified @@ -393,6 +392,7 @@ static inline void osalSysUnlockFromISR(void) { * * @xclass */ +#if CH_PORT_SUPPORTS_RT || defined(__DOXYGEN__) static inline void osalSysPolledDelayX(rtcnt_t cycles) { chSysPolledDelayX(cycles); @@ -510,7 +510,32 @@ static inline void osalThreadSleep(systime_t time) { */ static inline msg_t osalThreadSuspendS(thread_reference_t *trp) { - return osalThreadSuspendS(trp); + return chThreadSuspendS(trp); +} + +/** + * @brief Sends the current thread sleeping and sets a reference variable. + * @note This function must reschedule, it can only be called from thread + * context. + * + * @param[in] trp a pointer to a thread reference object + * @param[in] timeout the timeout in system ticks, the special values are + * handled as follow: + * - @a TIME_INFINITE the thread enters an infinite sleep + * state. + * - @a TIME_IMMEDIATE the thread is not enqueued and + * the function returns @p MSG_TIMEOUT as if a timeout + * occurred. + * . + * @return The wake up message. + * @retval MSG_TIMEOUT if the operation timed out. + * + * @sclass + */ +static inline msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, + systime_t timeout) { + + return chThreadSuspendTimeoutS(trp, timeout); } /** diff --git a/os/hal/platforms/STM32/I2Cv2/i2c_lld.c b/os/hal/platforms/STM32/I2Cv2/i2c_lld.c index 5cdebd052..eb5b67d47 100644 --- a/os/hal/platforms/STM32/I2Cv2/i2c_lld.c +++ b/os/hal/platforms/STM32/I2Cv2/i2c_lld.c @@ -92,25 +92,6 @@ I2CDriver I2CD2; /* Driver local functions. */ /*===========================================================================*/ -/** - * @brief Wakes up the waiting thread. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] msg wakeup message - * - * @notapi - */ -#define wakeup_isr(i2cp, msg) { \ - osalSysLockFromISR(); \ - if ((i2cp)->thread != NULL) { \ - thread_t *tp = (i2cp)->thread; \ - (i2cp)->thread = NULL; \ - tp->p_u.rdymsg = (msg); \ - chSchReadyI(tp); \ - } \ - osalSysUnlockFromISR(); \ -} - /** * @brief Aborts an I2C transaction. * @@ -134,27 +115,6 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) { dmaStreamDisable(i2cp->dmarx); } -/** - * @brief Handling of stalled I2C transactions. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static void i2c_lld_safety_timeout(void *p) { - I2CDriver *i2cp = (I2CDriver *)p; - - osalSysLockFromISR(); - if (i2cp->thread) { - thread_t *tp = i2cp->thread; - i2c_lld_abort_operation(i2cp); - i2cp->thread = NULL; - tp->p_u.rdymsg = MSG_TIMEOUT; - chSchReadyI(tp); - } - osalSysUnlockFromISR(); -} - /** * @brief I2C shared ISR code. * @@ -202,12 +162,11 @@ static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); - if (i2cp->errors) { - wakeup_isr(i2cp, MSG_RESET); - } - else { - wakeup_isr(i2cp, MSG_OK); - } + /* The wake up message depends on the presence of errors.*/ + if (i2cp->errors) + _i2c_wakeup_error_isr(i2cp); + else + _i2c_wakeup_isr(i2cp); } } @@ -233,7 +192,7 @@ static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) { dmaStreamDisable(i2cp->dmarx); dp->CR2 |= I2C_CR2_STOP; - wakeup_isr(i2cp, MSG_OK); + _i2c_wakeup_isr(i2cp); } /** @@ -285,7 +244,7 @@ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) { /* If some error has been identified then sends wakes the waiting thread.*/ if (i2cp->errors != I2C_NO_ERROR) - wakeup_isr(i2cp, MSG_RESET); + _i2c_wakeup_error_isr(i2cp); } /*===========================================================================*/ @@ -612,33 +571,39 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, systime_t timeout) { I2C_TypeDef *dp = i2cp->i2c; - virtual_timer_t vt; uint32_t addr_cr2 = addr & I2C_CR2_SADD; + systime_t start, end; osalDbgCheck((rxbytes > 0)); /* Resetting error flags for this transfer.*/ i2cp->errors = I2C_NO_ERROR; - /* Global timeout for the whole operation.*/ - if (timeout != TIME_INFINITE) - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); - /* Releases the lock from high level driver.*/ osalSysUnlock(); - /* Waits until BUSY flag is reset and the STOP from the previous operation - is completed, alternatively for a timeout condition.*/ - while (dp->ISR & I2C_ISR_BUSY) { + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { osalSysLock(); - if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (dp->ISR & I2C_ISR_BUSY) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) return MSG_TIMEOUT; + osalSysUnlock(); } - /* This lock will be released in high level driver.*/ - osalSysLock(); - /* Adjust slave address (master mode) for 7-bit address mode */ if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0) addr_cr2 = (addr_cr2 & 0x7f) << 1; @@ -658,22 +623,12 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Enable RX DMA */ dmaStreamEnable(i2cp->dmarx); - /* Atomic check on the timer in order to make sure that a timeout didn't - happen outside the critical zone.*/ - if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) - return MSG_TIMEOUT; - /* Starts the operation.*/ dp->CR2 |= I2C_CR2_RD_WRN; dp->CR2 |= I2C_CR2_START; /* Waits for the operation completion or a timeout.*/ - i2cp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); - if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) - chVTResetI(&vt); - - return chThdGetSelfX()->p_u.rdymsg; + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); } /** @@ -706,33 +661,39 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, systime_t timeout) { I2C_TypeDef *dp = i2cp->i2c; - virtual_timer_t vt; uint32_t addr_cr2 = addr & I2C_CR2_SADD; + systime_t start, end; osalDbgCheck(((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL)))); /* Resetting error flags for this transfer.*/ i2cp->errors = I2C_NO_ERROR; - /* Global timeout for the whole operation.*/ - if (timeout != TIME_INFINITE) - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); - /* Releases the lock from high level driver.*/ osalSysUnlock(); - /* Waits until BUSY flag is reset and the STOP from the previous operation - is completed, alternatively for a timeout condition.*/ - while (dp->ISR & I2C_ISR_BUSY) { + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { osalSysLock(); - if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (dp->ISR & I2C_ISR_BUSY) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) return MSG_TIMEOUT; + osalSysUnlock(); } - /* This lock will be released in high level driver.*/ - osalSysLock(); - /* Adjust slave address (master mode) for 7-bit address mode */ if ((i2cp->config->cr2 & I2C_CR2_ADD10) == 0) addr_cr2 = (addr_cr2 & 0x7f) << 1; @@ -757,11 +718,6 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Enable TX DMA */ dmaStreamEnable(i2cp->dmatx); - /* Atomic check on the timer in order to make sure that a timeout didn't - happen outside the critical zone.*/ - if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt)) - return MSG_TIMEOUT; - /* Transmission complete interrupt enabled.*/ dp->CR1 |= I2C_CR1_TCIE; @@ -770,12 +726,7 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, dp->CR2 |= I2C_CR2_START; /* Waits for the operation completion or a timeout.*/ - i2cp->thread = chThdGetSelfX(); - chSchGoSleepS(CH_STATE_SUSPENDED); - if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) - chVTResetI(&vt); - - return chThdGetSelfX()->p_u.rdymsg; + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); } #endif /* HAL_USE_I2C */ diff --git a/os/hal/platforms/STM32/I2Cv2/i2c_lld.h b/os/hal/platforms/STM32/I2Cv2/i2c_lld.h index 7bde99a6f..a2687cbc8 100644 --- a/os/hal/platforms/STM32/I2Cv2/i2c_lld.h +++ b/os/hal/platforms/STM32/I2Cv2/i2c_lld.h @@ -77,6 +77,13 @@ #define STM32_I2C_USE_I2C2 FALSE #endif +/** + * @brief I2C timeout on busy condition in milliseconds. + */ +#if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_I2C_BUSY_TIMEOUT 50 +#endif + /** * @brief I2C1 interrupt priority level setting. */ @@ -287,7 +294,7 @@ struct I2CDriver{ /** * @brief Thread waiting for I/O completion. */ - thread_t *thread; + thread_reference_t thread; /** * @brief Current slave address without R/W bit. */ -- cgit v1.2.3