[closed]Port vect missing interrupt signal

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

I'm trying to build communication between arduino & ATTINY814 referring to ONE-WIRE protocol.

It is really difficult for me, there is always miraculous problem before.

 

This is the basic initial step: server reset -> client presence -> server send CMD 

----------------________---____-------___---___---___---___---_---_---_---_--------------------

                     reset           presence      0       0        0       0      1    1    1   1

                     server         client          server -> 

detect edge:  |             |          |        |     |                 |

                                        ↑ pull low by client itself, don't detect it

                                                                  ↑ miss signal from here

                                                                                ↑ detect again

The only way to miss the signal should be disabled the interrupt, but did not find the bug to do this.

 

code :

//ATTINY814 ONE-WIRE simulation

#define OW_BUS_PULLLOW { PORTA_OUTCLR = PIN1_bm; PORTA_DIRSET = PIN1_bm;  }
#define OW_BUS_RELEASE { PORTA_DIRCLR = PIN1_bm; }
#define OW_READ        ( PORTA_IN & PIN1_bm )

//OW PIN interrupt
#define ENABLE_OW_INT		{ PORTA_INTFLAGS = PIN1_bm; PORTA_PIN1CTRL |= PORT_ISC_BOTHEDGES_gc; }
#define DISABLE_OW_INT		{ PORTA_PIN1CTRL &= ~PORT_ISC_BOTHEDGES_gc; }

#define OW_CHECK_TIMEOUT(ticks)		{ beginCMP2(ticks);  }
#define OW_CANCEL_CHECK_TIMEOUT		{ stopCMP2();	}
#define OW_WAIT_RELEASE_BUS(ticks)	{ beginCMP1(ticks);  }

void TCA_init(){
	/* set Normal mode */
	TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
	/* disable event counting */
	TCA0.SINGLE.EVCTRL &= ~(TCA_SINGLE_CNTEI_bm);

	TCA0.SINGLE.CTRLA |= TCA_SINGLE_CLKSEL_DIV8_gc /* System Clock */
			            | 1 << TCA_SINGLE_ENABLE_bp; /* Module Enable: disabled */
}

void owInit(void) {
	owStatus = ST_OW_IDLE;
	owIntTriggered = false;

	PORTA_PIN1CTRL |= PORT_PULLUPEN_bm; //enable pull up
	OW_BUS_RELEASE;
	ENABLE_OW_INT;

	PORTA_DIRSET = PIN4_bm; //debug
}

void beginCMP1(uint16_t ticksToWait){
	TCA0.SINGLE.INTCTRL &= ~TCA_SINGLE_CMP1_bm; //disable CMP1

	uint16_t t = TCA0_SINGLE_CNT;
	TCA0.SINGLE.CMP1 = t + ticksToWait;

	//!!!!!If the timer is running, a compare match sets the flag!!!!!
	TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP1_bm;  //clr int flag
	TCA0_SINGLE_INTCTRL |= TCA_SINGLE_CMP1_bm; //enable CMP
}

void beginCMP2(uint16_t ticksToWait){
	TCA0.SINGLE.INTCTRL &= ~TCA_SINGLE_CMP2_bm; //disable CMP2

	ticksCNTstartCmp2 = TCA0.SINGLE.CNT;
	TCA0.SINGLE.CMP2 = ticksCNTstartCmp2 + ticksToWait;

	//!!!!!If the timer is running, a compare match sets the flag!!!!!
	TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP2_bm;  //clr int flag
	TCA0.SINGLE.INTCTRL |= TCA_SINGLE_CMP2_bm;  //enable CMP2

	if(TCA0.SINGLE.CMP2<ticksCNTstartCmp2)
		ticksWraparoundCmp2 = 0xFFFF - ticksCNTstartCmp2;
	else
		ticksWraparoundCmp2 = 0;
}

//CMP1 used to release OW bus
ISR(TCA0_CMP1_vect){
	OW_BUS_RELEASE;
	TCA0.SINGLE.INTCTRL &= ~TCA_SINGLE_CMP1_bm; //disable int
	TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP1_bm; //clr int flag

	//PORTA_OUTSET = PIN4_bm;PORTA_DIRSET = PIN4_bm; //debug
}

//CMP2 used to check timeout
ISR(TCA0_CMP2_vect){
	owStatus = ST_OW_IDLE; //timeout ,set to default status: waiting for reset
	TCA0.SINGLE.INTCTRL &= ~TCA_SINGLE_CMP2_bm; //disable int
	TCA0.SINGLE.INTFLAGS = TCA_SINGLE_CMP2_bm;  //clr int flag

	//PORTA_OUTSET = PIN4_bm;PORTA_DIRSET = PIN4_bm;  //for debug
}

ISR(PORTA_PORT_vect){
	if(PORTA_INTFLAGS & PIN1_bm){
		owBusLevel = OW_READ;
		owIntTriggered = true;

		//if(i<40) debuga[i++]=owBusLevel;//!!!!!!!!!!!!!!!!!debug!!!!!!!!!!!!!!!!

		PORTA_INTFLAGS = PIN1_bm;
	}
}

void statusManager(void){
	uint16_t cnt=0;

	switch(owStatus){
		case ST_OW_IDLE:
			if(!owBusLevel){
				OW_CHECK_TIMEOUT(OWI_DELAY_H_TICK_MAX);
				owStatus = ST_OW_RESET_FALL;
			}
			break;
		case ST_OW_RESET_FALL:
			OW_CANCEL_CHECK_TIMEOUT; //stop timeout check

			if(owBusLevel){
				DISABLE_OW_INT; //don't trigger interrupt by next code(pull low)
				OW_BUS_PULLLOW; //presence
				ENABLE_OW_INT;
				OW_WAIT_RELEASE_BUS(OWI_DELAY_I_TICK_MAX); //presence delay
				owStatus = ST_OW_PRESENCE_FALL;
			}else
				owStatus = ST_OW_IDLE;
			break;
		case ST_OW_PRESENCE_FALL:
			if(owBusLevel){ //presence raise, now sent back presence signal, prepare to receive CMD from server
				owAction = OWA_Rcv;
				bytesToRcvSend = 1;
				curByte = owBuffer+0;
				curByteIdx = 0;
				curBitIdx = 0;
				owStatus = ST_OW_RCV_CMD;

				OW_CHECK_TIMEOUT(OWI_TIMEOUT_TICK); // maybe sensor can't receive CMD forever, so it is better to check timeout
			}else
				owStatus = ST_OW_IDLE;
			break;
		case ST_OW_RCV_CMD:
			OW_CANCEL_CHECK_TIMEOUT; // in order to decrease response time, not check timeout yet

			//waiting for 1 bit: fall to raise
			if(!owBusLevel){ // fall,start timeout check,and waiting for raise
				OW_CHECK_TIMEOUT(OWI_DELAY_C_TICK_MAX); //1:A 0:C,the timeout should be bigger than C
				break;
			}

			//RAISE, 1 bit received, 1/0 check
			cnt = TCA0_SINGLE_CNT; //remember current count as soon as possible
			//OW_CANCEL_CHECK_TIMEOUT;
			cnt = (cnt>ticksCNTstartCmp2) ? (cnt-ticksCNTstartCmp2) : (cnt+ticksWraparoundCmp2);

    	       	        if(i<40) debuga[i++]=cnt; //!!!!!!!!!!!!!!!!!debug!!!!!!!!!!!!!!!!

			if(OW_IS_1(cnt)){
				*curByte |= 1<<(curBitIdx);
			}else if(OW_IS_0(cnt)){
				//do nothing
			}else{ //error, reset to IDLE
				owStatus = ST_OW_IDLE;
				break;
			}

			//prepare for next bit
			if((++curBitIdx)>=8){
				if((++curByteIdx)>=bytesToRcvSend){ //received all bytes
					owStatus = ST_OW_CMD_RECEIVED;
					DISABLE_OW_INT;
					beginFlash(); //!!!!!!!!!!!!!!!debug!!!!!!!!!!!!!!!!!!!!!!!!
					break;
				}
				curByte = owBuffer+curByteIdx; //move to new position to save next byte
				*curByte = 0;  //clear it first
				curBitIdx = 0; //reset bit index
			}

			break;
		case ST_OW_CMD_RECEIVED:
			//process in main(),too much computation( CRC8 )

			break;
		case ST_OW_CMD_VERIFIED:

			break;
	}

}

int main(void){
	TCA_init();
	owInit();
	sei();

	while (1){
		if(owIntTriggered){
			statusManager();
			owIntTriggered = false;
		}
    }
}

 

     Code under ST_OW_RCV_CMD status receive the CMD.

 

This topic has a solution.
Last Edited: Wed. Nov 27, 2019 - 06:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or the time to excute the code under  ST_OW_RCV_CMD  is too long, interrupt has set the variant many times?

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

I cannot see any declaration of owIntTriggered or owStatus. Is that really the complete code?

/Jakob Selbing

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

not all, indeed.

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

I can't see how it works - for ONEWIRE, you need to pulse the pin low for 8us (??) then see how long the slave device holds it low. 

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

Have you see any of the atmel app notes for OW comms, most use the usart rather then bit banging the comms.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

I have read it, and give up that at last.

The reasons include:

1) hard to debug, you don't know what happened inner, only way is to check register;

2) not easy to change MCU later.

 

I want to create a sensor module, easy to plug in.

It is rare to develop module in clinet mode.

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

The reason found : pulse time interval is not long enough.

 

              0            0           0         0         1       1      1       1

---------____----____----____----____----__----__----__----__------------------

           ↑ 1 edge fall,execute interrupt code

                   ↑ 2 edge raise, execute interrupt code

                        ↑ 3   ↑ 4

 

The Interrupt(2/3/4) will be ignored if the time reserved for 1->2 / 2->3 is not long enough.