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.