Arduino TWI module adapted for Mega0 and AS7

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

This is a continuation of several previous threads involving Mega4809 Xplained Pro and TWI/I2C. Some of those threads are:

 

https://www.avrfreaks.net/forum/...

https://www.avrfreaks.net/forum/...

https://www.avrfreaks.net/forum/...

https://www.avrfreaks.net/forum/...

 

In the fourth one, Ron Sutherland suggested a review of the Arduino mega4809 TWI module since it was written by Microchip. I did that review and found it bloated, in the usual Arduino style. BUT, it was also relatively easy to modify to use as a library for non-Arduino environments. The code can be found at:

 

https://github.com/arduino/Ardui...

 

Here is what I did to modify this library:

 

1. twi.h:  Add the following code at the top of the file:

 

#define TWI_MUX 0		//TWI_MASTER on PA3:PA2

#define F_CPU 10000000UL        //my configuration
#define F_CPU_CORRECTED F_CPU	//for twi.h

#define TWISCL (1<<3)  	        //PA3
#define TWISDA (1<<2)	        //PA2

#define false 0
#define true 1

2. twi.c:  comment out   #include "Arduino.h"

 

3. twi.c add  #include <avr/interrupt.h>

 

4. twi.c in "TWI_MasterInit()" add before #ifdef NO_EXTERNAL_I2C_PULLUP

 

	//Configure TWI Master IO
	//PORTMUX.TWISPIROUTEA default for Master SCL/SDA on PA[3:2]
	PORTA.DIRSET = TWISCL + TWISDA;		//TWI pins as output
	PORTA.PIN3CTRL = 1<<3;				//SCL pullup on for testing
	PORTA.PIN2CTRL = 1<<3;				//SDA pullup on for testing

5. twi.c in "TWI_MasterInit()"  remove

#ifdef NO_EXTERNAL_I2C_PULLUP
	pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
	pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
#endif

Thats all it takes! You DO have to enable interrupts in your code, somewhere before the first use of the read or write functions. You also have to define a write buffer and a read buffer that are passed, by pointer, to the read and write functions.

 

TWI_MasterRead() and TWI_MasterWrite() are just wrappers that call the "do-everything" TWI_MasterWriteRead(). If you need to do the common sequence of start, write a register address, then read from that register, you need to call TWI_MasterWriteRead() directly or first do a TWI_MasterWrite() with the stop flag false to send the register address, then do a TWI_MasterRead() with the stop flag set to get the data at the register location.

 

The modified library is attached for your convenience. It should work for ATmega 808/9, ATmega 1608/9, ATmega3208/9 and ATmega4808/9.

 

I plan, in the near future, to modify the library to remove the need for an interrupt and to clean up some details. But, at least as a master, this code works.

 

Jim

 

 

 

Attachment(s): 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Thu. Feb 27, 2020 - 06:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jim prompted me to try building this i2c into my non-priority project.

 

https://github.com/epccs/PiUpdi/commit/a5ad2fca69372e8f7fe6becaca41c2b01931fe74

 

Not tested, but

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jim, could you include a small example file showing its use.  Maybe reading and writing to an eeprom similar to the example in fleurys code.

Thanks

 

Jim

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I will. It is coming.

 

Jim

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Side note on Msg #1 -

 

So far, I have not been able to make a single write, then read call to TWI_MasterWriteRead(). There is no argument for the return (read) data. So, I have resorted to using a single byte write to set the register address that will be read (without a STOP condition), then a one or more byte read. Fairly sure that there is a way to do it in a single call, but there might not be a way (with existing code), so that needs to be sorted out. At the very least, a single write-then-read function CAN be constructed to wrap around the two calls (write call, then read call).

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Sat. Feb 29, 2020 - 09:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is a wrapper that works for write then read. A typical application is a peripheral that is organized with registers. The common procedure is to write the register address to the device,

do a repeated start, then read from the device. How many bytes are required to address a register depends on the device organization and the number of bytes to be read likewise depends on the device organization. In particular, the number of bytes to read will depend on whether the returned value is an 8-bit byte or a 16 bit (or more) data type.

 

Please note that I did try testing the results of the initial write operation to determine whether to continue with the  read. In my setup, the write returned 0, even if it was successful. I think this is a flaw in TWI_MasterWriteRead().

 

 It is typical Arduino BloatWare but it functions:

 

/*! \brief TWI write-then-read transaction.
 *
 *  This function is TWI Master wrapper for a write-then-read transaction.
 *
 *  \param twi          The TWI_Master_t struct instance.
 *  \param address      Slave address.
 *  \param writeData    Pointer to data to write.
 *  \param bytesToWrite Number of data bytes to write.
 *  \param readData	Pointer to received data
 *  \param bytesToRead	Number of data bytes to read
 *
 *  \retval number of bytes read  If transaction could be started.
 *  \retval 0           If transaction could not be started.
 */
 uint8_t TWI_MasterWrite_Then_Read( uint8_t slave_address,
 				    uint8_t *write_data,
				    uint8_t bytes_to_write,
				    uint8_t *read_data,
				    uint8_t bytes_to_read,
				    uint8_t send_stop)
 {

	uint8_t status;

	status = TWI_MasterWrite(slave_address,write_data,bytes_to_write,0); //no stop

	status = TWI_MasterRead(slave_address,read_data,bytes_to_read,send_stop); 

	return status;
}

 

If you add it to the library included in Msg #1, you need to remember to also add a prototype to twi.h.

 

 uint8_t TWI_MasterWrite_Then_Read( uint8_t slave_address,
 				    uint8_t *write_data,
				    uint8_t bytes_to_write,
				    uint8_t *read_data,
				    uint8_t bytes_to_read,
				    uint8_t send_stop);

 

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Sat. Feb 29, 2020 - 11:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am not sure what to think of the TWI_MasterWriteRead() function. It must have started life a little different, and then ended up...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree. It seems, hmmm, a bit twisted? Convoluted? My thought was that maybe it was torn, kicking and screaming, from START or something.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net