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