Serial loop randomly stops

Hello,

I've been trying to make an EEPROM programmer using an Atmega32 for a while now, and I think I'm one or two stupid errors away from completion...
For my burning code, I have a loop to detect if there is any serial data waiting. From what I can tell, it has 2 options; send the "NEXT" command, or process a
byte from the buffer. However, I sometimes get 2048 bytes to send, but more often than not, I can't get past 64. The RX/TX lights on the USB/Serial converter
are not on, so something is frozen. Resetting the chip allows me to repeat this process, but without a reset, it will not give me anything.

My PC side program is written in python, and if anyone thinks that is the problem, I'll post it as well. Any help is much appreciated. Thank you

#include <stdint.h>

//**************************************************************************************
//**************************************************************************************
//**************************************************************************************
//**************************************************************************************
//**USING PORT B TO WRITE DATA FASTER. THIS IS DIFFERENT FROM THE OTHER VERSION*********
//**************************************************************************************
//**************************************************************************************
//**************************************************************************************
//**************************************************************************************
// On my board, I've connected digital pins 0-15
// to the A0-A15 lines, and digital pins 24-31 (Port "B") to the Q0-Q7 lines. 

#define MAX_ADDR 65536L //Max address for the chip

#define AD0 0 //Address pins

#define OE 18 //Output enable pin
#define CE 19 //Chip Enable pin
#define A9S 20 //A9 12V Super Voltage Relay
#define OES 21 //OE 12V Super Voltage Relay
#define PWR 22 //All Good LED Pin
#define ERR 23 //Error LED pin

#define serbaud 115200 //baudrate

int i; //Generic variable

void setup() {
  // Setup Control Pins
  pinMode(OE, OUTPUT);
  pinMode(CE, OUTPUT);
  pinMode(A9S, OUTPUT);
  pinMode(OES, OUTPUT);

  // Disable Chip, and disable read and write.
  digitalWrite(CE, LOW);
  digitalWrite(OE, HIGH);
  //Disable program and erase
  digitalWrite(A9S, LOW);
  digitalWrite(OES, LOW);

  //Serial.begin(115200);
  Serial.begin(serbaud);
}

void writeAddr(uint32_t addr) {
  uint32_t mask = 0x01;
  for (int i = AD0; i < AD0+16; i++) {
    if ((mask & addr) != 0) {
      digitalWrite(i,HIGH);
    } 
    else { 
      digitalWrite(i,LOW);
    }
    mask = mask << 1;
  }
  digitalWrite(OE,LOW);
}

/*

 //**********************************************************************
 //**********************************************************************
 //I DONT THINK ILL NEED THIS IF I CAN USE PORT MANIPULATION CORRECTLY!!!
 //**********************************************************************
 //**********************************************************************
 
 //TEST FOR WRITING DATA PINS
 uint8_t writeByte() {
 
 uint8_t data = B;
 
 for (int i = 0; i < 8; i++) {
 int QP = bitRead(D, i); //Read each bit in the byte
 data += QP;
 
 //digitalWrite(Q0 + i, QP); //Set the pins to the value of each bit
 //Serial.println(QP); //Test to print bits
 }
 
 PORTB = QP
 
 //for (int i = Q0; i < Q0+8; i++) {
 //if (bitRead(i) == HIGH) {
 //data |= mask;
 //}
 //mask = mask << 1;
 //}
 //return data;
 }
 
 */

void readChip() {

  // Disable Chip, and disable read and write.
  digitalWrite(CE, LOW);

  DDRB = B00000000; //Set port "B" as input

  for (int i = AD0; i < AD0+16; i++) {
    digitalWrite(i,LOW);
    pinMode(i, OUTPUT);
  }

  uint32_t addr = 0;
  while (addr < MAX_ADDR) {
    for (int i = 0; i < 16; i++) {
      writeAddr(addr);
      uint8_t b = PINB; //Read port "B" to a variable
      Serial.print(b, HEX);
      Serial.print(" ");
      addr++;
    }
    Serial.println("");
  }
  while (1) {
  }
}

void eraseChip() {
  Serial.println(F("Chip would be erased"));
  //***************************************
  //All of this is commented out for safety
  //***************************************
  /*
  pinMode(OES, HIGH);
   pinMode(A9S, HIGH):
   pinMode(CE, LOW);
   delay(100);
   pinMode(OES, LOW);
   pinMode(A9S, LOW);
   readChip();
   */
}

void burnChip() {

  digitalWrite(CE, LOW); // Disable Chip, and disable read and write.
  digitalWrite(OES, HIGH); //12v on OE

  for (int i = AD0; i < AD0+16; i++) {
    digitalWrite(i,LOW);
    pinMode(i, OUTPUT);
  }

  DDRB = B11111111; //Set port "B" as output

  for (uint32_t addr = 0; addr <= MAX_ADDR; addr++) { 

    int waiting = 0;

    while(Serial.available() <= 0) {
      //delay(2);

      if (waiting == 0) {  
        delay(1);
        Serial.println(F("NEXT")); // Tell Python script to send next byte
        waiting = 1;
      }  
    }

    byte bval = 0;

    if (Serial.available() > 0) {
      delay(4);
      //Start receiving data  
      char D = Serial.read(); //Read a byte
      bval = (int) D;
      //Serial.println(addr);
      //Serial.println(D, HEX); //Test to see bytes getting to the arduino
      for (int i = 0; i < 16; i++) {
        writeAddr(addr);
        //writeByte();
      }  

      byte data;

      for (int i = 0; i < 8; i++) {
        int QP = bitRead(D, i); //Read each bit in the byte
        data += QP;

        //digitalWrite(Q0 + i, QP); //Set the pins to the value of each bit
        //Serial.println(QP); //Test to print bits
      }
    }

    //PORTB = data;
  }

  Serial.println(F("END")); //Send end command

}

void loop() {

  if (Serial.available()) { 
    char ser = Serial.read();
    if(ser == 'a'){
      readChip();
    }
    else if(ser == 'b'){
      eraseChip();
    }
    else if(ser == 'c'){
      burnChip();
    }
  }
}

That's only a snippet - posting all of the code really helps as the problem isn't always where you think it is.

I'm puzzled by the call to delay after Serial.available() succeeds - at any normal baud rate that delay will
prevent the Arduino keeping up with the incoming serial stream.

You'd be better off concentrating on reading a block of data, and after then starting to talk to the EPROM -
communication is time-critical, the EPROM can wait.

The original post has been updated with the whole program. There are a lot of brainstorming comments in there lol.
This is a major work in progress.

So I should read the 64 bytes to a list, and operate on the list? I'll try to rework it that way.

Thanks!

This code would result in the 'NEXT' response being sent as soon as the serial input buffer was drained:

    while(Serial.available() <= 0) {
      //delay(2);

      if (waiting == 0) {  
        delay(1);
        Serial.println(F("NEXT")); // Tell Python script to send next byte
        waiting = 1;
      }  
    }

Are you really sending a separate response for every single received byte?

What's this code supposed to do?

      for (int i = 0; i < 16; i++) {
        writeAddr(addr);
        //writeByte();
      }  

      byte data;

      for (int i = 0; i < 8; i++) {
        int QP = bitRead(D, i); //Read each bit in the byte
        data += QP;

        //digitalWrite(Q0 + i, QP); //Set the pins to the value of each bit
        //Serial.println(QP); //Test to print bits
      }

Your setup function does not set the address pins 0 - 15 as outputs.

Pete

To PeterH-
At one point I was sending a byte at a time, but now the python program sends 64 bytes at a time.

The writeaddress part will write the A0-A15 pins with the correct address, and the other stuff is that work in progress stuff.
This is code modified from a Gameboy ram writer/reader someone did.

To el_supremo-

A0 is defined at the top. The writeaddress function increments the pin number. The readChip function works well using this, so I know that part works.
All of the address lines are tied to digital pins that are in order, so the function can just increase the pin number by 1.

Thank you both

But those are all digital pins. You've set OE, CE etc. as digital OUTPUTs and I think you need to do the same with pins 0 to 15.

Pete

void burnChip() {

  digitalWrite(CE, LOW); // Disable Chip, and disable read and write.
  digitalWrite(OES, HIGH); //12v on OE

  for (int i = AD0; i < AD0+16; i++) {
    digitalWrite(i,LOW);
    pinMode(i, OUTPUT);
  }

That puts them all as outputs, and starts them off low. Once I get the whole thing working, I might try to use port manipulation, like I did for the data pins. Just doing it
on the data pins reduced the compiled size by 500 bytes!

and I think you need to do the same with pins 0 to 15.

Of course, once you diddle with pins 0 and 1, there goes your ability to receive or send serial data.

fret669:
To PeterH-
At one point I was sending a byte at a time, but now the python program sends 64 bytes at a time.

In that case you need to wait until you have received all 64 bytes before you request the next block. (This is not the same thing as waiting for the serial port input buffer to be empty.)

Oh, here's the way the Atmega32 is set up

* ATMEL ATMEGA32 & 644(P) / AVR-NetIO
 *
 *                   +---\/---+
 * INT0 (D 24) PB0  1|        |40  PA0 (AI 0 / D8)
 * INT1 (D 25) PB1  2|        |39  PA1 (AI 1 / D9)
 * INT2 (D 26) PB2  3|        |38  PA2 (AI 2 / D10)
 *  PWM (D 27) PB3  4|        |37  PA3 (AI 3 / D11)
 *PWM+SS(D 28) PB4  5|        |36  PA4 (AI 4 / D12)
 * MOSI (D 29) PB5  6|        |35  PA5 (AI 5 / D13)
 * MISO (D 30) PB6  7|        |34  PA6 (AI 6 / D14)
 *  SCK (D 31) PB7  8|        |33  PA7 (AI 7 / D15)
 *             RST  9|        |32  AREF
 *             VCC 10|        |31  GND 
 *             GND 11|        |30  AVCC
 *           XTAL2 12|        |29  PC7 (D  7)
 *           XTAL1 13|        |28  PC6 (D  6)
 *  RX0 (D 16) PD0 14|        |27  PC5 (D  5) TDI
 *  TX0 (D 17) PD1 15|        |26  PC4 (D  4) TDO
 *  RX1 (D 18) PD2 16|        |25  PC3 (D  3) TMS
 *  TX1 (D 19) PD3 17|        |24  PC2 (D  2) TCK
 *  PWM (D 20) PD4 18|        |23  PC1 (D  1) SDA
 *  PWM (D 21) PD5 19|        |22  PC0 (D  0) SCL
 *  PWM+(D 22) PD6 20|        |21  PD7 (D 23) PWM
 *                   +--------+
 *

RX/TX are untouched. The read function uses that same setup, and works fine. The burn function is sending and receiving, but randomly freezes and never gets past about 2000 bytes.

Paul-

So I would just check the length of the buffer? I've learned a lot about Python and Arduino with this project, but I'm definetly more of a hands on type of person lol.
Oh, when I was sending/processing a byte at a time, this same thing happened.

Also, so somebody can replicate this issue (hopefully), here's the relevant Python3 code.

#!/usr/bin/python3
#Python Script.py3
#Blank Python3 script

import serial

def burnBinBuff():
    
    #Open a bin file of your choice (64kb is what I'm writing to)    
    bytes_read = open('YOUR BIN FILE HERE',  "rb")    
   
    bytes_read.seek(0)
        
    ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1)

    ser.write(bytes('c', 'UTF-8'))
        
    addressTEST = 0
        
    while True:
            
        waitArduino = 1
                
        while waitArduino == 1:
            line = ser.readline()
            lineascii = ascii(line)
            print(line)
        
            if lineascii.find('NEXT') >= 0:
                waitArduino = 0
                print('received next')
            
            elif lineascii.find('END') >= 0:
                print('END command received')
                return 1
                
        b = bytes_read.read(64)
        ser.write(b)
        print(addressTEST)
        addressTEST = addressTEST + 64
        
burnBinBuff()

You'll need pyserial and preferably as 64kb bin file for testing. Thanks

Anything? I've been testing more, and I've made it to about 9000 bytes before it quits, but more often than not I get to around 2000 bytes.

This code in burnchip should not be there:

  for (int i = AD0; i < AD0+16; i++) {
    digitalWrite(i,LOW);
    pinMode(i, OUTPUT);
  }

  DDRB = B11111111; //Set port "B" as output

You only need to set the pins as digital outputs once so it should be in setup. You are also writing to a pin before it is configured. And after the loop, you directly set all of port B as outputs.
You should do it one way or the other, not both.
If you use a loop in setup, it should be:

  for (int i = AD0; i < AD0+16; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i,LOW);
  }

Pete

fret669:
Anything? I've been testing more, and I've made it to about 9000 bytes before it quits, but more often than not I get to around 2000 bytes.

I'm not at all confident that your output code does what you want, but at the moment your problem seems to be specifically about handling the serial input so I'll only worry about that. You mentioned previously that you were going to make some changes that had been suggested. Can you post your current code? If you have time, I suggest you copy it to a test sketch and take out all code not directly needed to demonstrate the serial problem.

All true, but why does my stream randomly stop? The EEPROM reading code is set up the same way as far as setting up the address pins.
I'm writing port B because that's how the whole thing will be, but I just want to get it up and running, and then worry about speed.

I tried reading to a list as suggested, but the result was the same.

Python code (just use your own 64kb file, and change to your serial port):

#!/usr/bin/python3
#Python Script.py3
#Blank Python3 script

import serial

def burnBinBuff():
    
    #Open a bin file of your choice (64kb is what I'm writing to)    
    bytes_read = open('your bin',  "rb")    
   
    bytes_read.seek(0)
        
    ser = serial.Serial('/dev/ttyUSB0', 57600, timeout=1)

    ser.write(bytes('c', 'UTF-8'))
        
    addressTEST = 0
        
    while True:
            
        waitArduino = 1
                
        while waitArduino == 1:
            line = ser.readline()
            lineascii = ascii(line)
            print(line)
        
            if lineascii.find('NEXT') >= 0:
                waitArduino = 0
                print('received next')
            
            elif lineascii.find('END') >= 0:
                print('END command received')
                return 1
                
        b = bytes_read.read(64)
        ser.write(b)
        
burnBinBuff()

And relevant Arduino code (With extra stuff taken out, and this is running on an Atmega32):

#include <stdint.h>

#define MAX_ADDR 65536L //Max address for the chip

#define AD0 0 //Address pins

#define OE 18 //Output enable pin
#define CE 19 //Chip Enable pin
#define A9S 20 //A9 12V Super Voltage Relay
#define OES 21 //OE 12V Super Voltage Relay
#define PWR 22 //All Good LED Pin
#define ERR 23 //Error LED pin

#define serbaud 57600 //baudrate

int i; //Generic variable

void setup() {
  // Setup Control Pins
  pinMode(OE, OUTPUT);
  pinMode(CE, OUTPUT);
  pinMode(A9S, OUTPUT);
  pinMode(OES, OUTPUT);

  // Disable Chip, and disable read and write.
  digitalWrite(CE, LOW);
  digitalWrite(OE, HIGH);
  //Disable program and erase
  digitalWrite(A9S, LOW);
  digitalWrite(OES, LOW);

  Serial.begin(serbaud);
}

void writeAddr(uint32_t addr) {
  uint32_t mask = 0x01;
  for (int i = AD0; i < AD0+16; i++) {
    if ((mask & addr) != 0) {
      digitalWrite(i,HIGH);
    } 
    else { 
      digitalWrite(i,LOW);
    }
    mask = mask << 1;
  }
  digitalWrite(OE,LOW);
}

void handShake() {

  int waiting = 0;

  while(Serial.available() <= 0) {

    if (waiting == 0) {  
      //delay(1);
      Serial.println(F("NEXT")); // Tell Python script to send next byte
      delay(1);
      waiting = 1;
    }  
  }

  byte bval = 0;

  if (Serial.available() > 0) {
  
    //Start receiving data  
    char D = Serial.read(); //Read a byte
    bval = (int) D;
  }
}

void burnChip() {

  digitalWrite(CE, LOW); // Disable Chip, and disable read and write.
  digitalWrite(OES, HIGH); //12v on OE

  for (int i = AD0; i < AD0+16; i++) {
    digitalWrite(i,LOW);
    pinMode(i, OUTPUT);
  }

  DDRB = B11111111; //Set port "B" as output
  for (uint32_t addr = 0; addr <= MAX_ADDR; addr++) { 
    handShake();
  }
  Serial.println(F("END")); //Send end command
}

void loop() {

  if (Serial.available()) { 
    char ser = Serial.read();

    if(ser == 'c'){
      burnChip();
    }
  }
}

Also, if I restart the Python program without resetting the Arduino, it doesn't restart the loop, so I'm fairly certain it's the Arduino side.

fret669:
All true, but why does my stream randomly stop?

Does all that code in burnChip() and writeAddr() have anything to do with the problem?

Don't you think you should sort out the flow control so that it sends the NEXT response when it has finished processing the whole data block, and not just when it has emptied the serial input buffer?

Your code is still using the I/O pins 0 and 1 as address pins. Aren't these the serial Rx and Tx pins?

The RX/TX with my setup are D16/D17, and are fine because I can read the contents with no issue.

I suppose you could just run handShake() and it should do the same thing. The Python script is sending 64 bytes at a time. When the Arduino processes the buffer, which I'm assuming will be 64 bytes, it sends the NEXT command back to Python. Am I doing too much assuming? lol It still seems funky to me that it would just halt. I've tried 9600, 57600, and 112500 baud rates, but it still craps out.

I noticed that without my Serial.println(D); in every loop it made it to 50,000 to 70,000... and I get "EN" and it freezes again. The chip is exactly 65536 bytes,so that's strange too.

I still don't get how you expect the flow control to work. Are you assuming that the PC will send data over the serial link faster than your sketch reads it? How do you know that is a valid assumption?

Is it worth mentioning yet again that you still have a ton of code in there that seems irrelevant to the problem which you should get rid of, so you can eliminate it from the investigation?

#include <stdint.h>

#define MAX_ADDR 65536L //Max address for the chip

#define serbaud 115200 //baudrate

void setup() {
  Serial.begin(serbaud);
}

void handShake() {

  int waiting = 0;

  while(Serial.available() <= 0) {

    if (waiting == 0) {  
      //delay(1);
      Serial.println(F("NEXT")); // Tell Python script to send next byte
      delay(1);
      waiting = 1;
    }  
  }

  byte bval = 0;

  if (Serial.available() > 0) {
  
    //Start receiving data  
    char D = Serial.read(); //Read a byte
    bval = (int) D;
    delay(3);
  }
}

void burnChip() {

  for (uint32_t addr = 0; addr < MAX_ADDR; addr++) { 
    handShake();
    
 }
Serial.println(F("END")); //Send end command
}

void loop() {

  if (Serial.available()) { 
    char ser = Serial.read();

    if(ser == 'c'){
      burnChip();
    }
  }
}

That's about as little as I can see to make it.

If I understand the code right, My Python script will send 64 bytes, and wait for the Arduino. The Arduino shouldn't send another NEXT until it is out of serial buffer data. The Python
script shouldn't send 64 more bytes until the Arduino processes everything it sent before. The RX/TX lights on my ftdi breakout are alternating as I'd expect.

Alright, I've made a buffer of 1024 bytes, and handShake() is called once the 1024 bytes are read, and then calls for the next set. This freezes at about 10000 bytes.
Python is not receiving anything when the loop fails.