ATMEGA328PB interrupt Vector question

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

Im having TWI Slave issue as in it is not responding to anything, used Protocol Analyzer  to verify im sending the correct address and no Ack response ... even when I use a sniffer I don't get a reply.... 

 

In my searching I found that the DATA SHEET says on page 77_78 that the (TWI_vect) is for Two Wire Interface ... BUT Atmel Studio only excepts (TWI0_vect) ... 

 

Also in the iom328pb.h in Atmel Studio shows the a differant Vector # ... Data Sheet is       Vector 25 ... address 0x0030....... 

but the iom328pb.h has it              #define TWI0_vect_num        24

 

Which one is right ??? does it matter ??? just hunting for a reason why my 328pb is not working as TWI Slave ....

 

Thanks

Michael

This topic has a solution.
Last Edited: Wed. Mar 21, 2018 - 06:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are curious ... this is some of  my code

ISR :

ISR(TWI0_vect)
{
	if( (TWSR0 & 0xF8) == TW_SR_SLA_ACK ){
		TWCR0 |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
	}
	else if( (TWSR0 & 0xF8) == TW_SR_DATA_ACK )
		HeadIn = TWDR0;
	New_Data = 1;
}

 

Here is my setup of the TWI 

void I2C_init(uint8_t address){
	TWBR0 = TWBR_val;
	TWAR0 = address;
	// set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
	TWCR0 = (1<<TWIE)|(1<<TWEA)|(1<<TWINT)|(1<<TWEN);
}

Here is my address  <NON SHIFTED>

#define			HEAD			0x16

and a TWI sniffer finds NOTHING  on either 0x16 or the shifted 0x2c ... the ISR(TWI_vect) never hits.... not sure what the issue is...

 

Thanks 

Michael

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

Also in the iom328pb.h in Atmel Studio shows the a differant Vector # ... Data Sheet is       Vector 25 ... address 0x0030....... 

but the iom328pb.h has it              #define TWI0_vect_num        24

 

Which one is right ??? does it matter ??? just hunting for a reason why my 328pb is not working as TWI Slave ....

One is zero-based (AVR Libc), while the other is one-based (datasheet).  They are both the same vector.

 

Suggest you try a proven library.

http://homepage.hispeed.ch/peterfleury/avr-software.html

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I figured it was something like that ... I'm just hunting straws now..

 

I have the 328pb Master working just fine and it talks to a MCP23018 (16 IO expander) just fine... All i need this 328pb to do is to be a TWI slave and receive a single byte after it's twi address..

But I just can't seem to get it to work right ... I have a Tiny85 that is a TWI slave just to control two PWM outputs based on the byte it receives .... and the twi sniffer on the master 328pb find the MCP23017 and the Tiny85 but just does not see the Slave 328pb ... I.ve check wiring and I am wired correctly....

 

 

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

ettill777 wrote:

(TWI_vect) is for Two Wire Interface ... BUT Atmel Studio only excepts (TWI0_vect)

Unlike the ATmega328P, which has a single TWI, SPI and USART, the ATmega328PB has two of each, hence the need to use a Zero and One to distinguish between them.

Greg Muth

Portland, OR, US

Atmel Studio 7 (Version: 7.0.1652) on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

TWI master is pretty easy to do, the slave not so much.

Please post a SMALL complete program that demos the problem, in most cases you will find the problem while doing this, if not, post the code and we can help you find the problem.

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In my searching I found that the DATA SHEET says on page 77_78 that the (TWI_vect) is for Two Wire Interface ... BUT Atmel Studio only excepts (TWI0_vect) ... 

Unlike the ATmega328P, which has a single TWI, SPI and USART, the ATmega328PB has two of each, hence the need to use a Zero and One to distinguish between them.

Yes, the datasheet shows TWI_vect for the first peripheral, and TWI1_vect for the second.

 

Even Microchip's AVR Libc documentation lacks vectors for the m328PB.  However, a look at the most recent device pack containing the header for the m328pb tells a different story:

/* Two-wire Serial Interface */
#define TWI0_vect            _VECTOR(24)
#define TWI0_vect_num        24
.
.
.
/* TWI Transfer Complete */
#define TWI1_vect            _VECTOR(40)
#define TWI1_vect_num        40

Confusingly, other TWI0 specific names retain their un-suffixed forms:

#define TWCR0   _SFR_MEM8(0xBC)
#define TWIE    0
#define TWEN    2
#define TWWC    3
#define TWSTO   4
#define TWSTA   5
#define TWEA    6
#define TWINT   7
#define TWCR1   _SFR_MEM8(0xDC)
#define TWIE1   0
#define TWEN1   2
#define TWWC1   3
#define TWSTO1  4
#define TWSTA1  5
#define TWEA1   6
#define TWINT1  7

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Joey, yes that is confusing ... not all the names have the '0' added... and it has been a little challenging .

 

I wanted to keep it as simple as possible so Im only receiving a single byte..  

/*ATMEGA328p TQFP PIN OUT

1-PD3-		 9-PD5-	Spare		17-	SCLK			25-PC2
2-PD4-		10-PD6-Laser 		18-	AVCC			26-PC3-
3-PE0-		11-PD7-Eyes		19-PE2-Barrel PWM	        27- SDA
4-	VCC	12-PB0 			20-	AREF			28- SCL
5-	GND	13-PB1-Sensor A		21- GND				29- /RST
6-PE1-spare PWM	14-PB2-Sensor B		22-PE3-NECK PWM		        30- RXD0
7-	X-TAL	15-	MOSI		23-PC0				31- TXD0 
8-	X-TAL	16-	MISO		24-PC1				32- Int0 

******************* HEAD I2C Data Byte Structure  ****************
7	       6	 5	 4	3	2	1	0
Laser LED		| Sensor |	|  NECK	| 	|	Eyes
On	      OUT	IN	 OUT 	UP 	Down	         ON
 /off	      /IN						/OFF
************************ MASKs ***********************************
HLB	     HLP       HSI	HSO	HNU	HND	HB	HE

 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~	
 */

 


#define F_CPU 16000000		// AVR Clock Freq
 #include <avr/io.h> 
 #include <stdio.h>
 #include <avr/interrupt.h>
 #include "delay.h"
 
 
#define		_BAUD			38400
#define		F_SCL 400000UL 			// SCL frequency
#define		Prescaler 1
#define		TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
#define 	I2C_READ 0x01
#define 	I2C_WRITE 0x00



/* Slave Receiver */
#define TW_SR_SLA_ACK			0x60		// SLA+W received, ACK returned
#define TW_SR_ARB_LOST_SLA_ACK	0x68		// arbitration lost in SLA+RW, SLA+W received, ACK returned
#define TW_SR_GCALL_ACK			0x70		// general call received, ACK returned
#define TW_SR_ARB_LOST_GCALL_ACK 0x78		// arbitration lost in SLA+RW, general call received, ACK returned
#define TW_SR_DATA_ACK			0x80		// data received, ACK returned
#define TW_SR_DATA_NACK			0x88		// data received, NACK returned
#define TW_SR_GCALL_DATA_ACK	0x90		// general call data received, ACK returned
#define TW_SR_GCALL_DATA_NACK	0x98		// general call data received, NACK returned
#define TW_SR_STOP				0xA0		// stop or repeated start condition received while selected


#define			HEAD			0x16			// NOTE Slave address of 0x28 is shifted once to the right
												// Master sees it at 0x50
uint8_t		HeadIn		= 0;

ISR(TWI0_vect)
{
	if( (TWSR0 & 0xF8) == TW_SR_SLA_ACK ){
		TWCR0 |= (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
	}
	else if( (TWSR0 & 0xF8) == TW_SR_DATA_ACK )
		HeadIn = TWDR0;
	New_Data = 1;
}

{	// Port B initialization
	// Function: PB7=Xtal PB6=Xtal PB5=Out(SCK) PB4=In(MISO)
		//		 PB3=Out(MOSI) PB2=Out(Sensor IN) PB1=Out(Sensor OUT) PB0=Out
	DDRB= 0b00101111;
/*	(0<<DDB7) |		// XTAL
	(0<<DDB6) |		// XTAL
	(1<<DDB5) |		// SCK
	(0<<DDB4) |		// MISO
	(1<<DDB3) |		// MOSI
	(1<<DDB2) |		//  Sensor IN motor 
	(1<<DDB1) |		//  Sensor Out Motor
	(1<<DDB0);		// Spare
	// State: Bit7=0 Bit6=0 Bit5=T Bit4=T Bit3=T Bit2=0 Bit1=0 Bit0=0
*/
	PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
	// NO PULL UPS
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Port C initialization
	// Function: Bit6=In (RESET) Bit5=in (SCL Slave) Bit4=in (SDA Slave) Bit3=Out Bit2=Out Bit1=Out Bit0=Out
	DDRC= 0b000000111;
/*	(0<<DDC6) |	// RESET
	(0<<DDC5) |			// SCL 
	(0<<DDC4) |			// SDA
	(1<<DDC3) |			//		optional Stepper control
	(1<<DDC2) |			//		optional Stepper control
	(1<<DDC1) |			//		optional Stepper control
	(1<<DDC0);			//		optional Stepper control
	// State: Bit6=T Bit5=0 Bit4=0 Bit3=T Bit2=T Bit1=T Bit0=T
*/	
	PORTC=(0<<PORTC6) | (1<<PORTC5) | (1<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);
	// NO PULL UPS
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Port D initialization
// Function: Bit7=Out(Eyes) Bit6=Out(Laser) Bit5=Out(Spare) Bit4=Out Bit3=Out Bit2=In(int0) Bit1=Out(TX) Bit0=In(RX)
	DDRD= 0b11111010;
/*
	(1<<DDD7) |			//  Eyes On/Off Output 
	(1<<DDD6) |			//  Laser On/Off Output 
	(1<<DDD5) |			//  Spare
	(1<<DDD4) |			//  unused
	(1<<DDD3) |			//  unused
	(0<<DDD2) |			//	INT0 - unused
	(1<<DDD1) |			//	Serial TX
	(0<<DDD0);			//	Serial RX
	// State: Bit7=0 Bit6=0 Bit5=0 Bit4=T Bit3=T Bit2=T Bit1=0 Bit0=T
*/
	PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (1<<PORTD1) | (0<<PORTD0);
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Port E initialization
// Function: Bit7=N/A Bit6=N/A Bit5=N/A Bit4=N/A 
//			 Bit3=Out(NECK pwm) Bit2=Out(BARREL pwm) Bit1=Out(Spare PWM) Bit0=Out(spare)
	DDRE=0b00001111;
/*	(1<<DDRE3) |		//  PWM Neck Output
	(1<<DDRE2) |			//	PWM Barrel output
	(1<<DDRE1) |			//	PWM Spare
	(1<<DDRE0);				//	Spare
	// State: Bit7=0 Bit6=0 Bit5=0 Bit4=T Bit3=T Bit2=T Bit1=0 Bit0=T
*/
	PORTE= (0<<PORTE3) | (0<<PORTE2) | (0<<PORTE1) | (0<<PORTE0);
	
//****** 	Timer 0 setup for PWM ***************
	// Timer 0 Init for Clk/2 CTC mode Interrupt OCIE2A enabled
	TCCR0A = 0b00000010;		// Bit 1 = WGM01  (sets Waveform for CTC mode)
	TCCR0B = 0b00000001;		// Bit 0 = CS20  ( sets Clock Select to CLKio / 1 [No prescaling])
	OCR0A  = 0x07c;				// sets Count of Clk ticks until CTC
//	TIMSK0 = 0b00000011;		// sets OCIE0A(Match) Interrupt and TOIE(Overflow) Interrupt
	TIMSK0 = 0b00000000;
}
void I2C_init(uint8_t address){
	TWBR0 = TWBR_val;
	TWAR0 = address;
	// set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
	TWCR0 = (1<<TWIE)|(1<<TWEA)|(1<<TWINT)|(1<<TWEN);
}

//  ************* USART INIT WORKS  ***************
void USART_INIT(uint16_t baud){
	uint16_t myubrr = (F_CPU/16/baud-1);
	UBRR0H = (uint8_t)(myubrr>>8);
	UBRR0L = (uint8_t)myubrr;
	//	UCSR0B |= (0b0000100);
	
	UCSR0B = ((1<<RXEN0)|(1<<TXEN0)); 		// Enable RX & TX
	//	UCSR0C |= (0b00000110);
	UCSR0C = (3<<UCSZ00);					// Setup as 8-N-1
}
int USARTWriteChar(char ch, FILE *stream){//  ******* USART TX & RX *************
	if (ch == '\n') USARTWriteChar('\r', stream);
	while (!(UCSR0A & (1<<UDRE0)) );		// waits for tx to finish
	UDR0 = ch;
	return 0;
}
int USARTReadChar(FILE *stream){
	char ch;
	while (!(UCSR0A & (1<<RXC0)));		// Ready to Read
	ch = UDR0;
	// uart_putch(ch, stream);			// echo back to TX
	return ch;
}
FILE uart_str = FDEV_SETUP_STREAM(USARTWriteChar, USARTReadChar, _FDEV_SETUP_RW);

int main(void)
{
	sei();	
	initIO();						// Call Init IO PORTS
	USART_INIT(_BAUD);				// Call Init USART
	stdout = stdin = &uart_str;
	I2C_init(HEAD);
	printf("Boot complete\n");
	
	 while(1)
    {	if (New_Data == 1) 
		{	if ((HeadIn & HLB) == HLB){					// On/OFF of the laser
				}
			 else {LaserOFF;
				}
			if ((HeadIn & HE) == HE) {					// On/OFF of the Eyes
				EyeON; 
				}
			else {EyeOFF; }
			if ((HeadIn & HSI) == HSI || ((HeadIn & HSO) == HSO)) {				// Move Sensor 
				if ((HeadIn & HSI) == HSI) {SensorIN ;}
				if ((HeadIn & HSO) == HSO) {SensorOUT;}
			else {SensorSTOP;}
			if ((HeadIn & HNU) == HNU) {NECK_Pos -= 1;	// Move Neck servo Up
				}
			if ((HeadIn & HND) == HND) {NECK_Pos += 1;	// Move Neck servo Down
				}
			if ((HeadIn & HLP) == HLP) {				// Laser position	
				BARREL_Pos = Lout; } 
			else {BARREL_Pos = Lin; } 
			
		  
			HeadIn = 1;
			New_Data = 0;
		}
		// ************* Heart Beat ***************
		if (flash == 0) 
		{	flash = 0x01;}
		else {flash = 0;}
		PORTE = flash;
		_delay_ms(50);
	// ************  Heart Beat End ***************			 
    }
}

I added this part to test the TWI Regs to make sure they are setting up right ... using 

	printf(" TWSR0 = 0B");
	if (TWSR0 & 0x80) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x40) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x20) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x10) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x08) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x04) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x02) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x01) {printf("1\n");}else {printf("0\n");}
	
	printf(" TWCR0 = 0B");
	if (TWCR0 & 0x80) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x40) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x20) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x10) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x08) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x04) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x02) {printf("1");}else {printf("0");}
	if (TWCR0 & 0x01) {printf("1\n");}else {printf("0\n");}
	
	printf(" TWAR0 = %#x\n",TWAR0);

I get

 TWSR0 = 0B11111000                                                             
 TWCR0 = 0B01000101                                                             
 TWAR0 = 0x16 

 

Which I believe is correct... but I have ran TWI sniffer on my master 328pb and it does not see anything... and I added a part to set PE1 High if the ISR(TWI0_vect) hit ... no output. no indication that the Interrupt is hitting.

 

Any help would be appreciated.

 

Thank you

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	if (TWSR0 & 0x80) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x40) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x20) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x10) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x08) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x04) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x02) {printf("1");}else {printf("0");}
	if (TWSR0 & 0x01) {printf("1\n");}else {printf("0\n");}

Is that really necessary, as your printing of TWAR0 shows you are aware of %x so:

printf("TWSR0 = 0x%02X\n", TWSR0);

would have simply output:

TWSR0 = 0xF8

There can't be many programmers who don't instantly read 0xF8 as 11111000 anyway ?

 

If you really wanted it in binary then avr-gcc has an itoa() that has radix support so:

#include <stdlib.h>

char buffer[10];

printf("TWSR0 = 0b%s\n", itoa(TWSR0, buffer, 2));

The only downside of itoa() is that it does not pad leading 0's. So if the value were simply 00000101 then that would print:

TWSR0 = 0b101

 

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

I started with Arduno and shifted to straight C+ after a project ran out of program memory and realized how much space all the Arduino libraries took up. so I have not had any programming training ... so Im NOT a programmer ... the last programming language I knew was Apple Basic .... some 30+ years ago ...

 

But I Thank you for that information.

I did it that way to easily compare the Reg in binary so I don't make any mistakes.. 

Also, that bit of code was only added after I could not get the TWI Slave working ... so it will not be in the finished code.

 

Michael

 

 

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

Since this is no longer ON the topic of the Interrupts and vectors ... Could a moderator please mark this as completed  and I will open a new discussion about the TWI slave issue separately. 

 

Thank you for all your help.

 

-Michael

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

ettill777 wrote:
Could a moderator please mark this as completed
Moderators do not have that ability (a curious choice by the site designer!) so only YOU can do that. The person who creates a thread is the only one who gets to see [Mark as Solution] buttons on every post in a thread so you need to go back and click one of those to indicate which post (can be one of your own) is closest to being the actual solution.

 

Moderator.

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

ettill777 wrote:
mark this as completed 

See Tip #5

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...