From: batt Date: Tue, 11 Nov 2008 17:19:05 +0000 (+0000) Subject: Rename arm twi driver to i2c. X-Git-Tag: 2.0.0~11 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=8ef424e8fe50a16b2ac69ddbd2ba34347f628aca;p=bertos.git Rename arm twi driver to i2c. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1923 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/cpu/arm/drv/i2c_arm.c b/bertos/cpu/arm/drv/i2c_arm.c new file mode 100644 index 00000000..5a3cbe1c --- /dev/null +++ b/bertos/cpu/arm/drv/i2c_arm.c @@ -0,0 +1,52 @@ +/** + * \file + * + * + * \brief Low-level TWI module for ARM (inplementation). + * + * \version $Id$ + * + * \author Daniele Basile + * + * This module is automatically included so no need to include + * in test list. + * notest: arm + * + */ + +#include + +#if CPU_ARM_AT91 + #include "twi_at91.c" +/*#elif Add other ARM families here */ +#else + #error Unknown CPU +#endif diff --git a/bertos/cpu/arm/drv/i2c_arm.h b/bertos/cpu/arm/drv/i2c_arm.h new file mode 100644 index 00000000..4242956c --- /dev/null +++ b/bertos/cpu/arm/drv/i2c_arm.h @@ -0,0 +1,48 @@ +/** + * \file + * + * + * \brief Low-level TWI module for ARM (interface). + * + * \version $Id$ + * + * \author Daniele Basile + * + */ + +#include + +#if CPU_ARM_AT91 + #include "twi_at91.h" +/*#elif Add other ARM families here */ +#else + #error Unknown CPU +#endif diff --git a/bertos/cpu/arm/drv/i2c_at91.c b/bertos/cpu/arm/drv/i2c_at91.c new file mode 100644 index 00000000..49fd74ae --- /dev/null +++ b/bertos/cpu/arm/drv/i2c_at91.c @@ -0,0 +1,268 @@ +/** + * \file + * + * + * \brief Driver for the AT91 ARM TWI (implementation) + * + * \version $Id$ + * + * \author Francesco Sacchi + */ + +#include "twi_at91.h" + +#include "cfg/cfg_twi.h" +#include +#include +#include +#include + +#include + +#include + +/** + * Timeout for ACK slave waiting. + */ +#define TWI_TIMEOUT ms_to_ticks(50) + +/** + * Send \a size bytes over the twi line to slave \a id. + * If the device requires internal addressing before writing, \a byte1 \a byte2 and \a byte3 can + * be specified. Internal addressign bytes not used *must* be set to TWI_NO_IADDR. If 1 or 2 bytes + * are required for internal addressing you *must* first use \a byte1 and than \a byte2. + * \note Atmel TWI implementation is broken so it was not possible to supply a better + * interface. Additionally NACK handling is also broken, so if the i2c device reply nack + * this function will return after TWI_TIMEOUT. + * \return true if ok, false on slave timeout. + */ +bool twi_write(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, const void *_buf, size_t size) +{ + uint8_t addr_size = 0; + const uint8_t *buf = (const uint8_t *)_buf; + ticks_t start; + + /* At least 1 byte *must* be transmitted, thanks to crappy hw implementation */ + ASSERT(size >= 1); + + /* Check internal byte address presence */ + if (byte1 != TWI_NO_IADDR) + addr_size++; + + if (byte2 != TWI_NO_IADDR) + { + ASSERT(addr_size == 1); + addr_size++; + } + + if (byte3 != TWI_NO_IADDR) + { + ASSERT(addr_size == 2); + addr_size++; + } + + start = timer_clock(); + /* Wait tx buffer empty */ + while (!(TWI_SR & BV(TWI_TXRDY))) + { + if (timer_clock() - start > TWI_TIMEOUT) + return false; + } + + /* Set slave address and (optional) internal slave addresses */ + TWI_MMR = (uint32_t)id << TWI_DADR_SHIFT | (uint32_t)addr_size << TWI_IADRSZ_SHIFT; + + TWI_IADR = ((uint32_t)(byte3 & 0xff) << 16) | ((uint32_t)(byte2 & 0xff) << 8) | ((uint32_t)(byte1 & 0xff)); + + while (size--) + { + /* Send data */ + TWI_THR = *buf++; + + start = timer_clock(); + /* Wait tx buffer empty */ + while (!(TWI_SR & BV(TWI_TXRDY))) + { + if (timer_clock() - start > TWI_TIMEOUT) + return false; + } + } + + /* Wait transmit complete bit */ + start = timer_clock(); + while (!(TWI_SR & BV(TWI_TXCOMP))) + { + if (timer_clock() - start > TWI_TIMEOUT) + return false; + } + + return true; +} + + +/** + * Read \a size bytes from the twi line from slave \a id. + * If the device requires internal addressing before reading, \a byte1 \a byte2 and \a byte3 must + * be specified. Internal addressign bytes not used *must* be set to TWI_NO_IADDR. If 1 or 2 bytes + * are required for internal addressing you *must* first use \a byte1 and than \a byte2. + * \note Atmel TWI implementation is broken so it was not possible to supply a better + * interface. Additionally NACK handling is also broken, so if the i2c device reply nack + * this function will return after TWI_TIMEOUT. + * \return true if ok, false on slave timeout. + */ +bool twi_read(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, void *_buf, size_t size) +{ + uint8_t addr_size = 0; + uint8_t *buf = (uint8_t *)_buf; + bool stopped = false; + ticks_t start; + + /* At least 1 byte *must* be transmitted, thanks to crappy twi implementation */ + ASSERT(size >= 1); + + /* Check internal byte address presence */ + if (byte1 != TWI_NO_IADDR) + addr_size++; + + if (byte2 != TWI_NO_IADDR) + { + ASSERT(addr_size == 1); + addr_size++; + } + + if (byte3 != TWI_NO_IADDR) + { + ASSERT(addr_size == 2); + addr_size++; + } + + /* Wait tx buffer empty */ + start = timer_clock(); + while (!(TWI_SR & BV(TWI_TXRDY))) + { + if (timer_clock() - start > TWI_TIMEOUT) + return false; + } + + + /* Set slave address and (optional) internal slave addresses */ + TWI_MMR = ((uint32_t)id << TWI_DADR_SHIFT) | BV(TWI_MREAD) | ((uint32_t)addr_size << TWI_IADRSZ_SHIFT); + + TWI_IADR = ((uint32_t)(byte3 & 0xff) << 16) | ((uint32_t)(byte2 & 0xff) << 8) | ((uint32_t)(byte1 & 0xff)); + + /* + * Start reception. + * Kludge: if we want to receive only 1 byte, the stop but *must* be set here + * (thanks to crappy twi implementation again). + */ + if (size == 1) + { + TWI_CR = BV(TWI_START) | BV(TWI_STOP); + stopped = true; + } + else + TWI_CR = BV(TWI_START); + + while (size--) + { + /* If we are at the last byte, inform the crappy hw that we + want to stop the reception. */ + if (!size && !stopped) + TWI_CR = BV(TWI_STOP); + + /* Wait until a byte is received */ + start = timer_clock(); + while (!(TWI_SR & BV(TWI_RXRDY))) + { + if (timer_clock() - start > TWI_TIMEOUT) + { + TWI_CR = BV(TWI_STOP); + return false; + } + } + + + *buf++ = TWI_RHR; + } + + /* Wait transmit complete bit */ + start = timer_clock(); + while (!(TWI_SR & BV(TWI_TXCOMP))) + { + if (timer_clock() - start > TWI_TIMEOUT) + return false; + } + + return true; +} + +MOD_DEFINE(twi); + +/** + * Init the (broken) sam7 twi driver. + */ +void twi_init(void) +{ + /* Disable PIO on TWI pins */ + PIOA_PDR = BV(TWD) | BV(TWCK); + + /* Enable oper drain on TWI pins */ + PIOA_MDER = BV(TWD); + + /* Disable all irqs */ + TWI_IDR = 0xFFFFFFFF; + + TWI_CR = BV(TWI_SWRST); + + /* Enable master mode */ + TWI_CR = BV(TWI_MSEN); + + PMC_PCER = BV(TWI_ID); + + /* + * Compute twi clock. + * CLDIV = ((Tlow * 2^CKDIV) -3) * Tmck + * CHDIV = ((THigh * 2^CKDIV) -3) * Tmck + * Only CLDIV is computed since CLDIV = CHDIV (50% duty cycle) + */ + uint16_t cldiv, ckdiv = 0; + while ((cldiv = ((CLOCK_FREQ / (2 * CONFIG_TWI_FREQ)) - 3) / (1 << ckdiv)) > 255) + ckdiv++; + + /* Atmel errata states that ckdiv *must* be less than 5 for unknown reason */ + ASSERT(ckdiv < 5); + + TWI_CWGR = ((uint32_t)ckdiv << TWI_CKDIV_SHIFT) | (cldiv << TWI_CLDIV_SHIFT) | (cldiv << TWI_CHDIV_SHIFT); + TRACEMSG("TWI_CWGR [%08lx]", TWI_CWGR); + + MOD_INIT(twi); +} + diff --git a/bertos/cpu/arm/drv/i2c_at91.h b/bertos/cpu/arm/drv/i2c_at91.h new file mode 100644 index 00000000..ecf4974e --- /dev/null +++ b/bertos/cpu/arm/drv/i2c_at91.h @@ -0,0 +1,54 @@ +/** + * \file + * + * + * \brief Driver for the AT91 ARM TWI (implementation) + * + * \version $Id$ + * + * \author Francesco Sacchi + */ + + +#ifndef DRV_AT91_TWI_H +#define DRV_AT91_TWI_H + +#include + +typedef int16_t twi_iaddr_t; + +#define TWI_NO_IADDR (-1) + +void twi_init(void); +bool twi_read(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, void *_buf, size_t len); +bool twi_write(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, const void *_buf, size_t len); + +#endif /* DRV_AT91_TWI_H */ diff --git a/bertos/cpu/arm/drv/twi_arm.c b/bertos/cpu/arm/drv/twi_arm.c deleted file mode 100644 index 5a3cbe1c..00000000 --- a/bertos/cpu/arm/drv/twi_arm.c +++ /dev/null @@ -1,52 +0,0 @@ -/** - * \file - * - * - * \brief Low-level TWI module for ARM (inplementation). - * - * \version $Id$ - * - * \author Daniele Basile - * - * This module is automatically included so no need to include - * in test list. - * notest: arm - * - */ - -#include - -#if CPU_ARM_AT91 - #include "twi_at91.c" -/*#elif Add other ARM families here */ -#else - #error Unknown CPU -#endif diff --git a/bertos/cpu/arm/drv/twi_arm.h b/bertos/cpu/arm/drv/twi_arm.h deleted file mode 100644 index 4242956c..00000000 --- a/bertos/cpu/arm/drv/twi_arm.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * \file - * - * - * \brief Low-level TWI module for ARM (interface). - * - * \version $Id$ - * - * \author Daniele Basile - * - */ - -#include - -#if CPU_ARM_AT91 - #include "twi_at91.h" -/*#elif Add other ARM families here */ -#else - #error Unknown CPU -#endif diff --git a/bertos/cpu/arm/drv/twi_at91.c b/bertos/cpu/arm/drv/twi_at91.c deleted file mode 100644 index 49fd74ae..00000000 --- a/bertos/cpu/arm/drv/twi_at91.c +++ /dev/null @@ -1,268 +0,0 @@ -/** - * \file - * - * - * \brief Driver for the AT91 ARM TWI (implementation) - * - * \version $Id$ - * - * \author Francesco Sacchi - */ - -#include "twi_at91.h" - -#include "cfg/cfg_twi.h" -#include -#include -#include -#include - -#include - -#include - -/** - * Timeout for ACK slave waiting. - */ -#define TWI_TIMEOUT ms_to_ticks(50) - -/** - * Send \a size bytes over the twi line to slave \a id. - * If the device requires internal addressing before writing, \a byte1 \a byte2 and \a byte3 can - * be specified. Internal addressign bytes not used *must* be set to TWI_NO_IADDR. If 1 or 2 bytes - * are required for internal addressing you *must* first use \a byte1 and than \a byte2. - * \note Atmel TWI implementation is broken so it was not possible to supply a better - * interface. Additionally NACK handling is also broken, so if the i2c device reply nack - * this function will return after TWI_TIMEOUT. - * \return true if ok, false on slave timeout. - */ -bool twi_write(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, const void *_buf, size_t size) -{ - uint8_t addr_size = 0; - const uint8_t *buf = (const uint8_t *)_buf; - ticks_t start; - - /* At least 1 byte *must* be transmitted, thanks to crappy hw implementation */ - ASSERT(size >= 1); - - /* Check internal byte address presence */ - if (byte1 != TWI_NO_IADDR) - addr_size++; - - if (byte2 != TWI_NO_IADDR) - { - ASSERT(addr_size == 1); - addr_size++; - } - - if (byte3 != TWI_NO_IADDR) - { - ASSERT(addr_size == 2); - addr_size++; - } - - start = timer_clock(); - /* Wait tx buffer empty */ - while (!(TWI_SR & BV(TWI_TXRDY))) - { - if (timer_clock() - start > TWI_TIMEOUT) - return false; - } - - /* Set slave address and (optional) internal slave addresses */ - TWI_MMR = (uint32_t)id << TWI_DADR_SHIFT | (uint32_t)addr_size << TWI_IADRSZ_SHIFT; - - TWI_IADR = ((uint32_t)(byte3 & 0xff) << 16) | ((uint32_t)(byte2 & 0xff) << 8) | ((uint32_t)(byte1 & 0xff)); - - while (size--) - { - /* Send data */ - TWI_THR = *buf++; - - start = timer_clock(); - /* Wait tx buffer empty */ - while (!(TWI_SR & BV(TWI_TXRDY))) - { - if (timer_clock() - start > TWI_TIMEOUT) - return false; - } - } - - /* Wait transmit complete bit */ - start = timer_clock(); - while (!(TWI_SR & BV(TWI_TXCOMP))) - { - if (timer_clock() - start > TWI_TIMEOUT) - return false; - } - - return true; -} - - -/** - * Read \a size bytes from the twi line from slave \a id. - * If the device requires internal addressing before reading, \a byte1 \a byte2 and \a byte3 must - * be specified. Internal addressign bytes not used *must* be set to TWI_NO_IADDR. If 1 or 2 bytes - * are required for internal addressing you *must* first use \a byte1 and than \a byte2. - * \note Atmel TWI implementation is broken so it was not possible to supply a better - * interface. Additionally NACK handling is also broken, so if the i2c device reply nack - * this function will return after TWI_TIMEOUT. - * \return true if ok, false on slave timeout. - */ -bool twi_read(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, void *_buf, size_t size) -{ - uint8_t addr_size = 0; - uint8_t *buf = (uint8_t *)_buf; - bool stopped = false; - ticks_t start; - - /* At least 1 byte *must* be transmitted, thanks to crappy twi implementation */ - ASSERT(size >= 1); - - /* Check internal byte address presence */ - if (byte1 != TWI_NO_IADDR) - addr_size++; - - if (byte2 != TWI_NO_IADDR) - { - ASSERT(addr_size == 1); - addr_size++; - } - - if (byte3 != TWI_NO_IADDR) - { - ASSERT(addr_size == 2); - addr_size++; - } - - /* Wait tx buffer empty */ - start = timer_clock(); - while (!(TWI_SR & BV(TWI_TXRDY))) - { - if (timer_clock() - start > TWI_TIMEOUT) - return false; - } - - - /* Set slave address and (optional) internal slave addresses */ - TWI_MMR = ((uint32_t)id << TWI_DADR_SHIFT) | BV(TWI_MREAD) | ((uint32_t)addr_size << TWI_IADRSZ_SHIFT); - - TWI_IADR = ((uint32_t)(byte3 & 0xff) << 16) | ((uint32_t)(byte2 & 0xff) << 8) | ((uint32_t)(byte1 & 0xff)); - - /* - * Start reception. - * Kludge: if we want to receive only 1 byte, the stop but *must* be set here - * (thanks to crappy twi implementation again). - */ - if (size == 1) - { - TWI_CR = BV(TWI_START) | BV(TWI_STOP); - stopped = true; - } - else - TWI_CR = BV(TWI_START); - - while (size--) - { - /* If we are at the last byte, inform the crappy hw that we - want to stop the reception. */ - if (!size && !stopped) - TWI_CR = BV(TWI_STOP); - - /* Wait until a byte is received */ - start = timer_clock(); - while (!(TWI_SR & BV(TWI_RXRDY))) - { - if (timer_clock() - start > TWI_TIMEOUT) - { - TWI_CR = BV(TWI_STOP); - return false; - } - } - - - *buf++ = TWI_RHR; - } - - /* Wait transmit complete bit */ - start = timer_clock(); - while (!(TWI_SR & BV(TWI_TXCOMP))) - { - if (timer_clock() - start > TWI_TIMEOUT) - return false; - } - - return true; -} - -MOD_DEFINE(twi); - -/** - * Init the (broken) sam7 twi driver. - */ -void twi_init(void) -{ - /* Disable PIO on TWI pins */ - PIOA_PDR = BV(TWD) | BV(TWCK); - - /* Enable oper drain on TWI pins */ - PIOA_MDER = BV(TWD); - - /* Disable all irqs */ - TWI_IDR = 0xFFFFFFFF; - - TWI_CR = BV(TWI_SWRST); - - /* Enable master mode */ - TWI_CR = BV(TWI_MSEN); - - PMC_PCER = BV(TWI_ID); - - /* - * Compute twi clock. - * CLDIV = ((Tlow * 2^CKDIV) -3) * Tmck - * CHDIV = ((THigh * 2^CKDIV) -3) * Tmck - * Only CLDIV is computed since CLDIV = CHDIV (50% duty cycle) - */ - uint16_t cldiv, ckdiv = 0; - while ((cldiv = ((CLOCK_FREQ / (2 * CONFIG_TWI_FREQ)) - 3) / (1 << ckdiv)) > 255) - ckdiv++; - - /* Atmel errata states that ckdiv *must* be less than 5 for unknown reason */ - ASSERT(ckdiv < 5); - - TWI_CWGR = ((uint32_t)ckdiv << TWI_CKDIV_SHIFT) | (cldiv << TWI_CLDIV_SHIFT) | (cldiv << TWI_CHDIV_SHIFT); - TRACEMSG("TWI_CWGR [%08lx]", TWI_CWGR); - - MOD_INIT(twi); -} - diff --git a/bertos/cpu/arm/drv/twi_at91.h b/bertos/cpu/arm/drv/twi_at91.h deleted file mode 100644 index ecf4974e..00000000 --- a/bertos/cpu/arm/drv/twi_at91.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * \file - * - * - * \brief Driver for the AT91 ARM TWI (implementation) - * - * \version $Id$ - * - * \author Francesco Sacchi - */ - - -#ifndef DRV_AT91_TWI_H -#define DRV_AT91_TWI_H - -#include - -typedef int16_t twi_iaddr_t; - -#define TWI_NO_IADDR (-1) - -void twi_init(void); -bool twi_read(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, void *_buf, size_t len); -bool twi_write(uint8_t id, twi_iaddr_t byte1, twi_iaddr_t byte2, twi_iaddr_t byte3, const void *_buf, size_t len); - -#endif /* DRV_AT91_TWI_H */