I2C Slave info Request for MEGA328pb

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

 

I have other posts regarding a project Im working on that uses a I2C Master(ATMEGA328pb) and slave setup, But it looks like the Master is just getting overloaded with NRF24L01+ on the SPI bus, two PWM outputs, one MCP23017 for random led lights and a slave ATMEGA328pb that accepts a single byte.  I got everything working EXCEPT the PWM on the Master... 

 

So, i'm going to off load the PWM  to an additional ATMEGA328pb that get's the PWM Data from the Master via the I2C bus.... BUT i need to send TWO bytes, and Im not sure if the same coding will work that I used for the other Slave ATMEGA328pb .

Here is the code:


#include <util/twi.h>

// misc non I2C code

volatile uint8_t data;
static void (*I2C_recv)(uint8_t);
static void (*I2C_req)();

// *********  CALL BACKS  ***********
void I2C_setCallbacks(void (*recv)(uint8_t), void (*req)()){
	I2C_recv = recv;
	I2C_req = req;
}

// misc NON I2C code

ISR(TWI0_vect){
	switch(TW_STATUS)
	{
		case TW_SR_DATA_ACK:
		// received data from master, call the receive callback
		I2C_recv(TWDR0);
		TWCR0 = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
		break;
		case TW_ST_SLA_ACK:
		// master is requesting data, call the request callback
		I2C_req();
		TWCR0 = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
		break;
		case TW_ST_DATA_ACK:
		// master is requesting data, call the request callback
		I2C_req();
		TWCR0 = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
		break;
		case TW_BUS_ERROR:
		// some sort of erroneous state, prepare TWI to be readdressed
		TWCR0 = 0;
		TWCR0 = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
		break;
		default:
		TWCR0 = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
		break;
		}
	}
	
// Misc IO setup function

// ************ I2C FUNCTIONS START *  WORKS *************
void I2C_init(uint8_t address){
	cli();
	//TWBR0 = TWBR_val;
	TWAR0 = (address<<1);
	// set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
	TWCR0 = (1<<TWIE)|(1<<TWEA)|(1<<TWINT)|(1<<TWEN);
	sei();
	}
void I2C_received(uint8_t received_data){
	I2C_RECV_DATA = received_data;
	//printf(" IN = %#x\n",HeadIn);
	}
void I2C_stop(void){
	// clear acknowledge and enable bits
	cli();
	TWCR0  = 0;
	TWAR0 = 0;
	sei();
	}
void I2C_requested()	{
	//I2C_transmitByte(data);
	}
inline void __attribute__((always_inline)) I2C_transmitByte(uint8_t data){
	TWDR0 = data;
	}
//  **********  I2C Functions END  ****************


//  int main(void)
// set received/requested callbacks
	I2C_setCallbacks(I2C_received, I2C_requested);
	I2C_init(HEAD);
	
//  While(){
//      Actions based on I2C_RECV_DATA
//	}

And if your not sure ... please point me in the right direction ....  I would like to <send PWM_Slave Address> then Send <PWM0> then send <PWM1> .. stop I2C.

 

Any help would be great.

 

Thank you

-Michael

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

 

I guess I'm being too vague ....

 

I've done more reading from the Data sheet in the TWI section ...

I guess what I need to know is the format of the Slave's response.

 

IE ..

1st Master Starts Bus

2nd -Master sends Address-->Slave Acknowledges ... 

3rd Master sends 1st byte ---> Slave sees byte , BUT should it be a NACK or ACK from the Slave if it is going to get sent another Byte ?

4th Master sends 2nd byte ---> Slave sees byte , Im assuming that this one should be a ACK to complete the transmission ??

5th Master Stops Bus.

 

Thanks

-Michael

 

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

When a slave is receiving data, it must ack all data received.   When the slave is sending data, the master will ack data until the last byte, which it must nak to tell slave to release the bus so master can send stop.

The nice thing about i2c is it will tell you when something goes wrong, but all of your functions are void functions so that is impossible to do....

why not use proven i2c code instead of winging it???

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

ettill777 wrote:

 

2nd -Master sends Address-->Slave Acknowledges ... 

 

 

You are missing an important part here -- the R/W bit. 

 

In this specific example, the R/W bit would be `0`, for Write or SLA+W. 

 

As ki0bk said, the slave should ACK everything it receives. For your slave, for the data it receives  (after the address and R/W bit) it should interpret first byte is always <PWM0> and second byte is always <PWM1>. 

 

The slave cannot prevent master from continue sending a third byte or fourth byte and so on. 

 

 

 

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

Thank you Jim,

 

Then if the Slave always response with a ACK why is there a setting for NACK ?... or just a feature they added just in case?

 

And as stressful as it is writing the code and figuring out how to make it work is very enjoyable for me once I figure it out, I do use snippets from other peoples libraries sometimes as a way to figure out what each bit of code is doing and how altering it changes the affect.  It's the Electronics Engineer in me... IE what happens if I increase the resistance... type of thing.

 

Also I have a tendency to think too big... and when I started to play with Arduino I found quickly that all of the libraries their IDE adds to the code... I was running out of memory or programming space.. so I shifted to AVR Studio and have been learning C.

 

For example this thread is cause I was trying to have a single ATMEGA328pb (16Mhz) operate as a NRF24L01 retriever <via SPI at 1 Mhz> and a Random Number generator driving 12 LED via MCP23017 I/O Expander to light LEDS at random times(Timer0), and sending out I2C commands to another ATMEGA328pb (at only 100Khz), AND create two separate PWM signals for the driving motors..... It just got bogged down ...

I tested EVERYTHING but the PWM part and it all worked.... until I added PWM.... so Now i'm creating another MCU for just the PWM... and since I already have the I2C bus going Im going to kick it up to 400Khz and hope the added traffic will not cause issues.

 

Sorry for the long explanation 

-Michael

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

 

Fuse,

 

You are correct, I was just assuming since it was in Slave Receiver mode only and not transmitting anything that it was implied.

 

 

-Michael

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

Also it looks like your I2C code is made up of code from various sources. In particular, for the 

ISR(TWI0_vect)

code you are using, sometimes SLA+R can be offset by one or more bytes because it does not check if TWI is busy before writing to TWDR. 

 

I would recommend starting off with the Atmel app note. https://microchip.app.box.com/s/...

 

With regards to NACK, here's what TI says:

There are several conditions that lead to the generation of a NACK:

1. The receiver is unable to receive or transmit because it is performing some real-time function and is not ready to start communication with the master.

2. During the transfer, the receiver gets data or commands that it does not understand.

3. During the transfer, the receiver cannot receive any more data bytes.

4. A master-receiver is done reading data and indicates this to the slave through a NACK

So your I2C slave only takes two bytes <PWM0> and <PWM1>. But if master keeps sending more bytes to the slave after these two you can NACK the third byte (case #3). Or if your slave expect <PWM0> to be in range of 0 to 100, but it got a value like 200, you can also NACK it (case #2).