Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: i2C on digital only pins?

  1. #1
    Senior Member
    Join Date
    Jun 2013
    Posts
    474

    i2C on digital only pins?

    Looking at the pinout for T4.1, I see that i2C SCL/SDA are on analog pins. For my current project I need all my analog pins. Assuming in MUX chip is out of the question, is there are amount of software hacking that would allow me to move SCL/SDA to digital only pins so I don't need to sacrifice two analog pins? Or is the i2C protocol designed in such a way that it needs to use analog pins? I only need very slow one-way communication.

    Interestingly, this seems to indicate that it is possible:
    https://sites.google.com/site/martha...wPrintDialog=1
    Last edited by yeahtuna; 01-14-2023 at 03:42 AM.

  2. #2
    Senior Member
    Join Date
    Jun 2013
    Posts
    474
    Looks like i2C bit-banging is the solution.

  3. #3
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,382
    Could also maybe use flexio. I have not tried it but they show an example in the reference manual

  4. #4
    Senior Member
    Join Date
    Jun 2013
    Posts
    474
    I'm pressed for digital pins too. There's not a lot of info on FlexIO. Can FlexIO run on only two digital pins? I'm still in prototyping. What two pins might I reserve so I can look at implementing flexIO in the future?

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,408
    Kurt's big pinout chart has the easiest info

    https://forum.pjrc.com/threads/66144...l=1#post268934

    Choose 2 pins with the same FlexIO peripheral (3 separate ones exist). For example, pins 4 and 5 are have FlexIO1 bits 6 and 8.

    Bitbanging I2C on any 2 digital pins is always an option, if you're willing to spend the CPU time. If you use that code meant for Arduino Uno, you will need to sprinkle "delayMicroseconds(5);" in several places.

  6. #6
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,382
    There is some information about Flexio up on my github project: https://github.com/kurte/flexio_t4
    The readme shows the different pins for the T4.x boards.

    Code:
    The Teensy 4.1 (ARDUINO_TEENSY41) Will have additional IO pins.
    FlexIO 1 - The three rows are: Teensy pin, Flex IO pin, and MUX setting for that pin:
    
        2,       3,    4,    5,  33,    49,   50,   52,   54
        4,       5,    6,    8,  7,     13,   14,   12,   15
        0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14
    Ranges: 4-8,12-15
    
    FlexIO 2
    
        6,       7,    8,    9,  10,    11,   12,   13,   32,   34,   35,   36,   37
        10,     17,   16,   11,  0,      2,    1,    3,   12,   29,   28,   18,   19
        0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14
    Ranges 0-3, 10-12, 16-19, 28-29
    
    FlexIO 3 - Note Flex IO 3 does not have DMA support
    
        7,       8,   14,   15,   16,   17,   18,   19,   20,  21,    22,   23,   26,   27,   34,   35,   36,   37,   38,   39,   40,   41
        17,     16,    2,    3,    7,    6,    1,    0,   10,   11,    8,    9,   14,   15,   29,   28,   18,   19,   12,   13,    4,    5 
        0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 
    Ranges: 0-19, 28-29
    Probably should update my comment there that it will have... In each of these groups first line is Teensy pin, the second line is the
    FlexIO pin number within that FlexIO object and the 3rd line is the Mux setting.

    Note this library is now in the TD releases. Although I don't think he picks up the readme.

  7. #7
    Senior Member
    Join Date
    Jun 2013
    Posts
    474
    So if I use teensy pins 9 and 32, that should work with FlexIO2 right?

  8. #8
    Senior Member
    Join Date
    Jun 2013
    Posts
    474
    I wrote out a very low level Bit Bang IC2 header only class. I think this will take care of my needs, but perhaps I'll try to tackle FlexIO further down the road.

    Code:
    #ifndef __BIT_BANG_IC2__
    #define __BIT_BANG_IC2__
    
    
    #define BIT_BANG_DEBUG
    
    
    class BitBang_IC2 {
    public:
    	BitBang_IC2(uint8_t SCL_PIN, uint8_t SDA_PIN, bool use_pullups = false) {
    
    		BB_SDA = SDA_PIN;
    		BB_SCL = SCL_PIN;
    		usePullup = use_pullups;
    
    		#ifdef BIT_BANG_DEBUG
    		Serial.println("Bit Bang I2C: Initializing...");
    		#endif
    	}
    
    	void init() {
    		pinMode(BB_SDA, OUTPUT);
    		pinMode(BB_SCL, OUTPUT);
    		sda_high();
    		scl_high();
    		dly();
    	}
    
    	void start() {
    		sda_high();
    		dly();
    		scl_high();
    		dly();
    		sda_low();
    		dly();
    		scl_low();
    		dly();
    	}
    
    	void stop() {
    		sda_low();
    		dly();
    		scl_high();
    		dly();
    		sda_high();
    		dly();
    	}
    
    	/* Transmit 8 bit data to slave */
    	bool tx(uint8_t data) {
    		sda_set_write_mode();
    		for (int i = 7; i >= 0; i--) {
    
    			if (data & (0x01 << i)) sda_high(); else sda_low();
    			dly();
    			scl_high();
    			dly();
    			scl_low();
    			dly();
    		}
    
    		sda_set_read_mode();
    		scl_high();
    		dly();
    		bool ack = !digitalRead(BB_SDA);    // Acknowledge bit
    		scl_low();
    		sda_set_write_mode();
    		sda_high();
    		return ack;
    	}
    
    	uint8_t rx() {
    		sda_set_read_mode();
    		dly();
    		uint8_t data = 0;
    
    		for (int i = 7; i >= 0; i--) {
    			#ifdef BIT_BANG_DEBUG
    			Serial.print(".");
    			#endif
    
    			if (digitalRead(BB_SDA) == HIGH) data |= (0x01 << i);
    
    			scl_high();
    			dly();
    			scl_low();
    			dly();
    		}
    
    		#ifdef BIT_BANG_DEBUG
    		Serial.println(" Byte Read");
    		#endif
    
    		scl_low();
    		sda_set_write_mode();
    		sda_high();
    		return(data);
    	}
    
    	void setDelayTime(int micro_seconds = 5) {
    		delay_us = micro_seconds;
    	}
    
    protected:
    
    	inline void dly() { delayMicroseconds(delay_us); }
    
    	inline void sda_high() { digitalWrite(BB_SDA, HIGH); }
    	inline void sda_low() { digitalWrite(BB_SDA, LOW); }
    	inline void scl_high() { digitalWrite(BB_SCL, HIGH); }
    	inline void scl_low() { digitalWrite(BB_SCL, LOW); }
    
    	inline void sda_set_write_mode() { pinMode(BB_SDA, OUTPUT); }
    	void sda_set_read_mode() {
    		if (usePullup)
    			pinMode(BB_SDA, INPUT_PULLUP);
    		else
    			pinMode(BB_SDA, INPUT);
    	}
    
    	bool usePullup;
    	uint8_t BB_SDA;
    	uint8_t BB_SCL;
    
    	int delay_us = 5;
    };
    
    
    
    #endif

  9. #9
    Quote Originally Posted by yeahtuna View Post
    I wrote out a very low level Bit Bang IC2 header only class. I think this will take care of my needs, but perhaps I'll try to tackle FlexIO further down the road.
    Curious if you tried your bit-bang I2C and whether it worked? Seems like a useful thing!

  10. #10
    Senior Member
    Join Date
    Jun 2013
    Posts
    474
    Quote Originally Posted by joepasquariello View Post
    Curious if you tried your bit-bang I2C and whether it worked? Seems like a useful thing!
    Yes, it works. I used it read some values from an EEPROM chip connected to a Teensy 3.2. It's bare bones. To make it useful for communicating with chips, you would likely want to extend the class. For example, here's the class I've written for communicating with 4 digital rheostats (hasn't been tested yet as I'm still waiting for my proto board to arrive).

    Code:
    #ifndef __MCP4332_BIT_BANG_I2C__
    #define __MCP4332_BIT_BANG_I2C__
    
    #define MCP4332_BASE_ID 0xB
    
    
    #include "AF_BitBang.h"
    #include <stdint.h>
    
    struct MCP4332_DeviceID {
    	uint8_t writeAddress;
    	uint8_t readAddress;
    };
    
    
    class MCP4332_Bit_Bang_IC2 {
    public:
    	MCP4332_Bit_Bang_IC2(uint8_t SCL_PIN, uint8_t SDA_PIN, bool use_pullups = false)
    	: bitBang(SCL_PIN, SDA_PIN, use_pullups) {
    
    		writeAddress = (MCP4332_BASE_ID << 3);
    		readAddress = writeAddress | 0x01;
    
    		wiperAddress[0] = 0;
    		wiperAddress[1] = 0x01 << 4;
    		wiperAddress[2] = 0x06 << 4;
    		wiperAddress[3] = 0x07 << 4;
    
    	}
    
    	void init() {
    		bitBang.init();
    	}
    
    	//SET THE GAIN OF THE RHEOSTAT
    	void write(uint8_t devIndex, uint8_t wiperIndex, uint8_t gain) {
    
    		if (devIndex < 4 && wiperIndex < 4) {
    			bitBang.start();
    			bitBang.tx(dev[devIndex].writeAddress);
    			bitBang.tx(wiperAddress[wiperIndex]);
    			bitBang.tx(gain);
    			bitBang.stop();
    		}
    	}
    
    	void setDeviceID(uint8_t index, uint8_t a0, uint8_t a1) {
    		if (index < 4) {
    			dev[index].writeAddress = writeAddress | (a1 << 2) | (a0 << 1);
    			dev[index].readAddress = writeAddress | 0x01;
    		}
    	}
    	
    protected:
    
    	BitBang_IC2 bitBang;
    
    	int writeAddress;
    	int readAddress;
    
    	MCP4332_DeviceID dev[4];
    
    	uint8_t wiperAddress[4];
    };
    
    #endif
    Last edited by yeahtuna; 01-21-2023 at 10:28 PM.

  11. #11
    Quote Originally Posted by yeahtuna View Post
    Yes, it works. I used it read some values from an EEPROM chip connected to a Teensy 3.2. It's bare bones. To make it useful for communicating with chips, you would likely want to extend the class. For example, here's the class I've written for communicating with 4 digital rheostats (hasn't been tested yet as I'm still waiting for my proto board to arrive).
    Thanks, that's pretty cool. Nice thing to have in the toolbox.

  12. #12
    Senior Member
    Join Date
    Jun 2013
    Posts
    474
    Quote Originally Posted by joepasquariello View Post
    Thanks, that's pretty cool. Nice thing to have in the toolbox.
    This is just to confirm that it's working to control my 4 quad digipots. I used to use SPI with CS pins, which worked out to 6 pins total. Nice to see that I can now accomplish the same thing using just 2 digital pins (didn't even need external pullups).

  13. #13
    Quote Originally Posted by yeahtuna View Post
    This is just to confirm that it's working to control my 4 quad digipots. I used to use SPI with CS pins, which worked out to 6 pins total. Nice to see that I can now accomplish the same thing using just 2 digital pins (didn't even need external pullups).
    Good news!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •