Quantcast
Channel: Arduino Forum - Latest topics
Viewing all articles
Browse latest Browse all 15574

Arduino goes into while-loop even though it should'nt

$
0
0

Hello,
My Arduino Uno is programmed to communicate with a serial interface.
For this, it has to read and write to certain lines. Now, I have a problem with the function that is supposed to read a byte. I use a logic-analyzer tool, which can precisely measure the signals that the Arduino receives or sends.

I am using lines called "CLK" (clock) and "DATA" for the actual communication, while i have "HELP" and "HELP2" for setting markers while debugging.

Here is my code for the function:

uint8_t readByte(){ 
  uint8_t Byte = 0;
  while(digitalRead(CLK) == LOW){} //wait for the signal that tells me it is ready

  digitalWrite(DATA,HIGH); //respond that the Arduino is ready

  int usc = 0;
  while(digitalRead(CLK) == HIGH && usc <= 20){ //now, I  wait for a special case in the 
                                                //protocol. if CLK doesnt go low within 200 microseconds, there is a handshake to send
      delayMicroseconds(10); 
      usc++;                                   // i wait 10microseconds and increment a counter, if the 
                                                    // counter goes >20, i know that 200 microseconds have passed
  }
  if(usc >= 20){              
    //perform the special handshake
    eoi = true;      
    digitalWrite(DATA,LOW);
    delayMicroseconds(80);
    digitalWrite(DATA,HIGH);
    while(digitalRead(CLK) == 1){}
  }


  
  pinMode(DATA, INPUT_PULLUP); 

  uint8_t c = 0;
  while(c < 8){               //repeat this 8 times, once for every bit

    digitalWrite(HELP2,HIGH); //HELP2 signals that we are in the beginning of the loop

    while(digitalRead(CLK) == LOW){} //wait for the CLK to go high

    digitalWrite(HELP,HIGH); //HELP signals that CLK has been read as high

    bitWrite(Byte, c, digitalRead(DATA)); //read the bit from DATA 

    c++;

    while(digitalRead(CLK) == HIGH){} //now, wait for the end of the clock pulse
    digitalWrite(HELP,LOW);
    digitalWrite(HELP2,LOW); //HELP and HELP2 signal that the end of the method is reached
  }
  pinMode(DATA,OUTPUT);
  digitalWrite(DATA,LOW);  //at the end, DATA is set low (required by the protocol)

  digitalWrite(HELP,HIGH); //set a marker that signals that DATA has been set low
  delayMicroseconds(30);
  digitalWrite(HELP,LOW); 

  return Byte;
}

Following the logic in my function, the HELP2 line should go high exactly 8 times (for each start of the while-loop), once before every new pulse of CLK.

Here is the logic diagram for the case that it works:


(i hope everything is readable)

The top two lines are CLK and DATA, the other two are HELP and HELP2.

My problem is, that sometimes this does not work. Here is the logic diagram:

As you can see, HELP2 goes high again after the 8th completion of the while-loop.
Here, the loop should not execute anymore, because c is now 8 and not <8. But it still does, as HELP2 actually goes high again (indicating the start of the loop). Also, DATA is not set to low, which shows the loop is not finished.

In my eyes, this does not make any sense at all. This error occurs about once in ~100 Bytes.

I have tried everything I could thing of to fix this. I turned off interrupts during the function, and I tried multiple counting variables.
Debugging is also extra hard on this, since I cannot use the serial port (I already use it to send the read bytes to my pc).

I hope anyone understands my problem and can help me to figure out this behaviour.

Also, here is the whole code, if anyone is interested, it is quite confusing though I think:

int ATN = 3;
int CLK = 4;
int DATA = 5;
int HELP = 9;
int RESET = 10;
int WELP = 11;

int usc = 0;
int bc = 0;


bool eoi = false;

bool helpon = false;

char buffer[2];

char dataToSend[2];

bool line = false;

char status = 0;


void setup() {
  Serial.begin(115200);
  //Serial.begin(9600);
  pinMode(ATN, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(DATA, INPUT_PULLUP);
  pinMode(7,OUTPUT);
  pinMode(8,INPUT_PULLUP);
  digitalWrite(7,LOW);
  digitalWrite(ATN,HIGH);

  pinMode(HELP,OUTPUT);
  digitalWrite(HELP, LOW);

  pinMode(RESET,OUTPUT);
  digitalWrite(RESET,HIGH);

  pinMode(13,OUTPUT);

  pinMode(WELP,OUTPUT);
  digitalWrite(WELP,LOW);

}



uint8_t readByte(){
  uint8_t Byte = 0;
  while(digitalRead(CLK) == 0){}
  digitalWrite(DATA,HIGH); //end hold-off


  usc = 0;
  while(digitalRead(CLK) == HIGH && usc <= 20){ //wait for EOI timeout or non-EOI response
      delayMicroseconds(10);
      usc++;
  }
  if(usc >= 20){              
    //do EOI handshake
    eoi = true;      
    digitalWrite(DATA,LOW);
    delayMicroseconds(80);
    digitalWrite(DATA,HIGH);
    while(digitalRead(CLK) == 1){}
  }


  
  pinMode(DATA, INPUT_PULLUP);
  uint8_t c = 0;
  while(c < 8){
    digitalWrite(WELP,HIGH);
    while(digitalRead(CLK) == LOW){} //wait for clock pulse
    digitalWrite(HELP,HIGH);
    bitWrite(Byte, c, digitalRead(DATA));
    c++;
    while(digitalRead(CLK) == HIGH){} //wait until clock pulse ends before next cycle starts
    digitalWrite(HELP,LOW);
    digitalWrite(WELP,LOW);
  }
  pinMode(DATA,OUTPUT);
  digitalWrite(DATA,LOW); 
  digitalWrite(HELP,HIGH);
  delayMicroseconds(30);
  digitalWrite(HELP,LOW);
  return Byte;
}


void sendByte(int byte, bool cmd, bool send_eoi){
  if(cmd){
    digitalWrite(ATN, LOW);
    usc = 0;
    while(digitalRead(DATA) == HIGH && usc <= 100){ 
      delayMicroseconds(10);
      usc++;
    }
    if(usc >= 100){/*device not present error*/status = 1; return;}else{status=0;}
  }else{
    digitalWrite(ATN,HIGH);
  }
  digitalWrite(CLK,LOW);
  delayMicroseconds(100);
  digitalWrite(CLK, HIGH); //end talker hold-off


  while(digitalRead(DATA)==LOW){}
  

  if(send_eoi){
    delayMicroseconds(150);
    while(digitalRead(DATA) == HIGH){}
    while(digitalRead(DATA) == LOW){}
  }else{
    delayMicroseconds(40);
  }
  pinMode(DATA, OUTPUT);
  digitalWrite(CLK, LOW);
  
  for(int i = 0; i<8;i++){
    digitalWrite(DATA, bitRead(byte, i));
    delayMicroseconds(55);
    digitalWrite(CLK, HIGH);
    delayMicroseconds(60);
    digitalWrite(CLK, LOW);
  }

  pinMode(DATA, INPUT_PULLUP);
  usc = 0;
  while(digitalRead(DATA) == HIGH && usc <= 100){ 
    delayMicroseconds(10);
    usc++;
  }
  if(usc >= 100){/*frame error*/status = 2;return;}else{status=0;}
  if(cmd){delayMicroseconds(20);}
}


void receiveBytes(){ //performs turnaround, receives bytes and sends them to the pc
  digitalWrite(HELP,HIGH);digitalWrite(HELP,LOW);
  pinMode(DATA, OUTPUT);
  digitalWrite(DATA,LOW);
  eoi = false;
  helpon = true;
  digitalWrite(ATN, HIGH);
  delayMicroseconds(20);
  digitalWrite(CLK,HIGH);
  pinMode(CLK, INPUT_PULLUP);
  while(digitalRead(CLK) == HIGH){}



  while(!eoi){ 
    int receivedByte = readByte();
    
    //hold-off
    //send byte to pc
    Serial.write(0); //0 --> no error
    Serial.write(receivedByte);
  }


  Serial.write(1); //1 --> end of data

  pinMode(CLK,OUTPUT);
  digitalWrite(CLK,LOW);
  pinMode(DATA,INPUT_PULLUP);
}


void loop() {
    digitalWrite(13,HIGH);
    while(Serial.available() < 2){} //wait for data in buffer
    digitalWrite(13,LOW);
    Serial.readBytes(buffer,2);
    if(bitRead(buffer[1],4)){ //reset command
      line = false;
      status = 0;
      digitalWrite(ATN,HIGH);
      digitalWrite(RESET,LOW);
      delay(500);
      digitalWrite(RESET,HIGH);
      delay(2000); //wait for drive to be ready
    }
    else if(bitRead(buffer[1],3)){ //receive_bytes command
      receiveBytes(); 
    }else{
      //if(buffer[0] == 0xf0) helpon = true;
      sendByte(buffer[0],bitRead(buffer[1],0),bitRead(buffer[1],1));
      if(bitRead(buffer[1],2)){ //release_atn command
        digitalWrite(ATN, HIGH);
        delayMicroseconds(50); //leave ATN high before the next command is send
      }
    }
    Serial.write(status); //send status
}

6 posts - 3 participants

Read full topic


Viewing all articles
Browse latest Browse all 15574

Latest Images

Trending Articles



Latest Images