From: Doug Szumski Date: Thu, 4 Sep 2014 20:54:25 +0000 (+0200) Subject: examples: Extends i2ctest to include a second TWI driver X-Git-Tag: v1.3~70^2 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=2190f69580c71bc715a9dd24c27ebcd81d53b29b;p=sx%2Fsimavr.git examples: Extends i2ctest to include a second TWI driver Adds a commonly used alternative to the Atmel TWI driver. This particular driver is choosen because it covers a non-interrupt driven approach to using the TWI module. --- diff --git a/examples/board_i2ctest/Makefile b/examples/board_i2ctest/Makefile index ec0197b..73d8983 100644 --- a/examples/board_i2ctest/Makefile +++ b/examples/board_i2ctest/Makefile @@ -36,7 +36,7 @@ all: obj ${firmware} ${target} include ${simavr}/Makefile.common -atmega1280_${target}.axf: atmega1280_${target}.c +atmega1280_${target}.axf: atmega1280_${target}.c twimaster.c atmega1280_${target}.axf: ${simavr}/examples/shared/avr_twi_master.c atmega1280_${target}.axf: ${simavr}/examples/shared/avr_twi_master.h diff --git a/examples/board_i2ctest/atmega1280_i2ctest.c b/examples/board_i2ctest/atmega1280_i2ctest.c index e40e73f..8bab174 100644 --- a/examples/board_i2ctest/atmega1280_i2ctest.c +++ b/examples/board_i2ctest/atmega1280_i2ctest.c @@ -28,9 +28,12 @@ AVR_MCU(F_CPU, "atmega1280"); #include "../shared/avr_twi_master.h" +#include "../shared/twimaster.h" #include +#define EEPROM_ADDR 0xA0 + static int uart_putchar(char c, FILE *stream) { if (c == '\n') uart_putchar('\r', stream); @@ -42,17 +45,14 @@ static int uart_putchar(char c, FILE *stream) { static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); -int main() +static void +test_twi_with_atmel_driver(void) { - stdout = &mystdout; - - sei(); - TWI_Master_Initialise(); { // write 2 bytes at some random address uint8_t msg[8] = { - 0xa0, // TWI address, + EEPROM_ADDR, // TWI address, 0xaa, 0x01, // eeprom address, in little endian 0xde, 0xad, // data bytes }; @@ -63,7 +63,7 @@ int main() } { uint8_t msg[8] = { - 0xa0, // TWI address, + EEPROM_ADDR, // TWI address, 0xa8, 0x01, // eeprom address, in little endian }; TWI_Start_Transceiver_With_Data(msg, 3, 0); // dont send stop! @@ -73,14 +73,68 @@ int main() } { uint8_t msg[9] = { - 0xa0 + 1, // TWI address, + EEPROM_ADDR + 1, // TWI address, }; TWI_Start_Transceiver_With_Data(msg, 9, 1); // write 1 byte, read 8, send stop while (TWI_Transceiver_Busy()) sleep_mode(); } +} + +/* + * Tests the TWI using a commonly used and non-interrupt driven + * alternative to the Atmel driver: + * + * "I2C master library using hardware TWI interface" + * Author: Peter Fleury http://jump.to/fleury + */ +static void +test_twi_with_pf_driver(void) +{ + /* + * This init followed by a start condition is enough to overwrite all TWI + * related bits set by TWI_Master_Initialise () in the Atmel driver. + */ + i2c_init(); + + i2c_start(EEPROM_ADDR + I2C_WRITE); + // eeprom address, in little endian + i2c_write(0xaa); + i2c_write(0x01); + // data bytes + i2c_write(0xd0); + i2c_write(0x0d); + i2c_stop(); + + i2c_start(EEPROM_ADDR + I2C_WRITE); + // set address + i2c_write(0xa8); + i2c_write(0x01); + // Don't stop + + // Read back data + i2c_start (EEPROM_ADDR + I2C_READ); + for (uint8_t i = 0; i < 8; ++i) { + i2c_readNak(); + }; + i2c_stop(); +} + +int main() +{ + stdout = &mystdout; + + sei(); + + test_twi_with_atmel_driver(); + + /* + * This should produce *exactly* the same output as above, except + * the data written should be D00D as opposed to DEAD. + */ + test_twi_with_pf_driver (); + cli(); sleep_mode(); } - diff --git a/examples/shared/twimaster.c b/examples/shared/twimaster.c new file mode 100755 index 0000000..43925b3 --- /dev/null +++ b/examples/shared/twimaster.c @@ -0,0 +1,204 @@ +/************************************************************************* +* Title: I2C master library using hardware TWI interface +* Author: Peter Fleury http://jump.to/fleury +* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ +* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 +* Target: any AVR device with hardware TWI +* Usage: API compatible with I2C Software Library i2cmaster.h +**************************************************************************/ +#include +#include +#include + +#include "twimaster.h" + + +/* define CPU frequency in Mhz here if not defined in Makefile */ +#ifndef F_CPU +#define F_CPU 7372800UL +#endif + +/* I2C clock in Hz */ +#define SCL_CLOCK 100000L + + +/************************************************************************* + Initialization of the I2C bus interface. Need to be called only once +*************************************************************************/ +void i2c_init(void) +{ + /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */ + + TWSR |= (1 << TWPS0); /* no prescaler */ + TWBR = ((F_CPU/SCL_CLOCK)-16)/(2*4); /* must be > 10 for stable operation */ + +}/* i2c_init */ + + +/************************************************************************* + Issues a start condition and sends address and transfer direction. + return 0 = device accessible, 1= failed to access device +*************************************************************************/ +unsigned char i2c_start(unsigned char address) +{ + uint8_t twst; + + // send START condition + TWCR = (1< http://jump.to/fleury +* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $ +* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 +* Target: any AVR device +* Usage: see Doxygen manual +**************************************************************************/ + +#ifdef DOXYGEN +/** + @defgroup pfleury_ic2master I2C Master library + @code #include @endcode + + @brief I2C (TWI) Master Software Library + + Basic routines for communicating with I2C slave devices. This single master + implementation is limited to one bus master on the I2C bus. + + This I2c library is implemented as a compact assembler software implementation of the I2C protocol + which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). + Since the API for these two implementations is exactly the same, an application can be linked either against the + software I2C implementation or the hardware I2C implementation. + + Use 4.7k pull-up resistor on the SDA and SCL pin. + + Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module + i2cmaster.S to your target when using the software I2C implementation ! + + Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion. + + @note + The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted + to GNU assembler and AVR-GCC C call interface. + Replaced the incorrect quarter period delays found in AVR300 with + half period delays. + + @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + + @par API Usage Example + The following code shows typical usage of this library, see example test_i2cmaster.c + + @code + + #include + + + #define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet + + int main(void) + { + unsigned char ret; + + i2c_init(); // initialize I2C library + + // write 0x75 to EEPROM address 5 (Byte Write) + i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode + i2c_write(0x05); // write address = 5 + i2c_write(0x75); // write value 0x75 to EEPROM + i2c_stop(); // set stop conditon = release bus + + + // read previously written value back from EEPROM address 5 + i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode + + i2c_write(0x05); // write address = 5 + i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode + + ret = i2c_readNak(); // read one byte from EEPROM + i2c_stop(); + + for(;;); + } + @endcode + +*/ +#endif /* DOXYGEN */ + +/**@{*/ + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + +#include + +/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */ +#define I2C_READ 1 + +/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */ +#define I2C_WRITE 0 + + +/** + @brief initialize the I2C master interace. Need to be called only once + @param void + @return none + */ +extern void i2c_init(void); + + +/** + @brief Terminates the data transfer and releases the I2C bus + @param void + @return none + */ +extern void i2c_stop(void); + + +/** + @brief Issues a start condition and sends address and transfer direction + + @param addr address and transfer direction of I2C device + @retval 0 device accessible + @retval 1 failed to access device + */ +extern unsigned char i2c_start(unsigned char addr); + + +/** + @brief Issues a repeated start condition and sends address and transfer direction + + @param addr address and transfer direction of I2C device + @retval 0 device accessible + @retval 1 failed to access device + */ +extern unsigned char i2c_rep_start(unsigned char addr); + + +/** + @brief Issues a start condition and sends address and transfer direction + + If device is busy, use ack polling to wait until device ready + @param addr address and transfer direction of I2C device + @return none + */ +extern void i2c_start_wait(unsigned char addr); + + +/** + @brief Send one byte to I2C device + @param data byte to be transfered + @retval 0 write successful + @retval 1 write failed + */ +extern unsigned char i2c_write(unsigned char data); + + +/** + @brief read one byte from the I2C device, request more data from device + @return byte read from I2C device + */ +extern unsigned char i2c_readAck(void); + +/** + @brief read one byte from the I2C device, read is followed by a stop condition + @return byte read from I2C device + */ +extern unsigned char i2c_readNak(void); + +/** + @brief read one byte from the I2C device + + Implemented as a macro, which calls either i2c_readAck or i2c_readNak + + @param ack 1 send ack, request more data from device
+ 0 send nak, read is followed by a stop condition + @return byte read from I2C device + */ +extern unsigned char i2c_read(unsigned char ack); +#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); + + +/**@}*/ +#endif