Uploading images through serial to Fram, Mram or SD card?

Hello, I have been trying to figure out a way to upload an image from the pc to an 4MB Mram storage on arduino. So far I can not see a way, I saw how to upload text to eeprom that is onboard but that is all.

Does anyone know of a way I can upload an image to my Mram storage? I was going to use an external eeprom But it only has a 100,000 read and write endurance. Same with an winbond. I don't have room for an SD card and I want more endurance to the storage so I choose an Mram.

Joseph

How is your Mram connected and how do you access it for other uses? Should be identical for all uses.

There is a limit on write cycles, not on read cycles. Note that writing is usually page based. If you write a single byte, it erases a page (e.g. 256 bytes) and rewrites the full page (with the updated byte). If you write 256 bytes, it also erases the page; but it is considered one write cycle.

You can consider FRAM if you need more than 100,000 write cycles. Basically unlimited write cycles. But for simply storing one image once you will not have to worry.

@Paul_KD7HB Right now not connected I have been learning about writing text to the eeprom. I'm currently soldering the 8pin sop8 to a breadboard breakout tomorrow.

@sterretje That is true. However I'm screenshoting images once every half second to overwride the old image. and that image is what I want to upload once per second to the mram. If I do that with eeprom it will in a short time reach it's 100,000 write and read cycles. That is where the MRAM comes in. I haven't looked at the Fram endurance which said it is unlimied you are correct. And I have some of them as well.

How big are the images (bytes)? If they fit in a FRAM, you'd be better off. Fast, SPI interface and existing libraries (and more commonly used) in the Arduino Ecosystem.

The Fram is more then enough it's a 4Mbyte which is if devided by 8 it's about 500KB. my image is 100KB.

That is currently not my problem. My problem is I don't know how to trasnfer that that image from the Pc to the arduino and upload it to that Fram.

You need a program on the PC to send the data from the image file out a USB port. I understand people typically use Python for this.

Then you need code on your Arduino board (you haven't told us which type) to read the data from a UART port (or perhaps native USB port depending on which board type) via a Stream object such as Serial, Serial, etc.

Which of those tasks are you having difficulty with?

You will need a fairly high data rate to transfer 100k bytes every 1/2 second. Non-volatile memory can have a fairly slow write time too.

@david_2018 i'm okay with the slow transfer speeds. I just don't know how to transfer it from the Pc to the Fram itself.

Post #8.

@gfvalvo I did not see post 8 strange. I'm lookin at it now thank you.

But you need a certain minimum speed in order to transfer the image within the available time. You will not be able to save a screenshot once every half second if the transfer or writing to storage takes over 1/2 second.

I’m curious why you would even want to do this, since you would only have the last image saved when the computer shut down, you are overwriting all the other images.

I don't have my Mram or Fram. I'm going to for now test it with an SD card. I'm attaching my code both for arduino and python. Strange part is it said Successfully sent with no errors. But When looking at the Sd card on my PC there is no image in the sd card.

Python:

import serial
import time
import os

# Function to send image in chunks
def send_image_to_arduino(image_path, arduino_port, baud_rate=115200):
    # Open the serial connection to Arduino
    ser = serial.Serial(arduino_port, baud_rate, timeout=1)
    time.sleep(2)  # Wait for Arduino to initialize
    
    if not os.path.exists(image_path):
        print(f"Error: File {image_path} does not exist.")
        return
    
    # Open image in binary mode and read it
    with open(image_path, 'rb') as file:
        image_data = file.read()

    # Send the image data in chunks
    chunk_size = 256  # Experiment with larger chunk size to achieve faster transfer speeds
    start_time = time.time()  # Track time before sending data

    for i in range(0, len(image_data), chunk_size):
        chunk = image_data[i:i + chunk_size]
        ser.write(chunk)  # Send chunk
        # Optionally add small delay to prevent overflow, depending on your hardware
        time.sleep(0.005)  # Test with different sleep durations if needed
    
    # End of transfer signal
    ser.write(b'EOF')
    print("Image sent successfully.")
    end_time = time.time()  # Track time after sending data

    # Calculate and display the transfer time
    transfer_time = end_time - start_time
    print(f"Transfer completed in {transfer_time:.3f} seconds.")
    ser.close()

# Example usage
if __name__ == "__main__":
    arduino_port = 'COM3'  # Replace with your Arduino's port (e.g., '/dev/ttyACM0' on Linux)
    image_path = 'received_image.png'  # Path to your image file 
    send_image_to_arduino(image_path, arduino_port)

Arduino:

#include <SPI.h>
#include <SD.h>

#define CS_PIN 5  // Change to your SD card CS pin if needed

File imageFile;

void setup() {
  // Start the serial communication
  Serial.begin(115200);  // Match this baud rate to the one set in Python code
  while (!Serial) { // Wait for the serial connection to be established
    ; 
  }

  // Initialize SD card
  if (!SD.begin(CS_PIN)) {
    Serial.println("Initialization failed! Make sure the SD card is properly connected.");
    return;
  }

  Serial.println("Ready to receive image data...");
  imageFile = SD.open("received_image.png", FILE_WRITE);  // Open the file for writing
  if (!imageFile) {
    Serial.println("Failed to create file on SD card.");
    return;
  }
}

void loop() {
  // Read data from serial
  if (Serial.available()) {
    byte data;
    data = Serial.read(); // Read a single byte from the serial buffer
    
    // If 'EOF' is received, close the file and stop
    if (data == 'E') {
      if (Serial.available() && Serial.read() == 'O' && Serial.available() && Serial.read() == 'F') {
        Serial.println("End of file received. Closing file.");
        imageFile.close();  // Close the file on the SD card
        return;
      }
    }

    // Write the received byte to the SD card
    imageFile.write(data);
  }
}

Not sure what to do. Can someone please help me? This is not fully my code. I found parts of it online and some I change to meet mine. I'm a lot lost and out of my dept when it comes with programmer. I'm not sure what to do now.

The way you are checking for "EOF" is going to corrupt the data. There will be times when 'E' appears in the file data, at which point you are potentially reading in additional bytes of data to check for the '0' and 'F. When you are not at end of file, these bytes are not being saved to the image file. It is also likely, even at 115200 baud, that you will receive an 'E', but will be checking for Serial.available() before the next byte has arrived.

You need to be careful of overflow in the Serial receive buffer. It can take a considerable amount of time to write data to an SD card.

In fact, the sequence 'E', '0', 'F' could even appear in binary data. Since the sending code knows the size of the file, it should send that first at the very start of the transfer. That will allow the receiving code to know when transmission is complete and also implement a timeout feature. Also, the data transmission should be followed by a CRC or Checksum for error detection.

Yea, the first thing would be to buffer the data in the RX and just write blocks to the SD. The most efficient block size probably depends on the library and the SD's sector size.

If there is still overrun on the RX, you could implement software flow control between the sending and receiving code.

I honestly think I'm outside of what I can do. I do honestly not know what to do. Can someone please help me to make these changes to fix this problem?

So what value is the Arduino adding to this project anyway? Perhaps you should look into ways of doing it entirely on the PC that is taking the screen shots.

@gfvalvo It has to be arduino. I have my reasons. Something I have been trying to work on for some time. I wish I was better skilled at programming. But I'm not my skills are better in hardware then software. I already have something that makes the screenshots. I just need arduino to send them screenshots from the pc to the arduino. That is my problem.

Just an update. A friend of mine is trying to help me. But he does not know arduino. He came up with this code.

arduino code:

#include <SPI.h>
#include <SD.h>

File myFile;

void setup() {
  Serial.begin(9600);
  if (!SD.begin(5)) {
    Serial.println("SD initialization failed!");
    return;
  }

  myFile = SD.open("received.png", FILE_WRITE);
  if (!myFile) {
    Serial.println("Error opening file!");
    return;
  }
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    static char buffer[64];
    static int index = 0;

    if (c == '<' && Serial.peek() == 'E') {  // Detect <EOF>
      delay(10);  // Wait to ensure <EOF> fully received
      Serial.read(); Serial.read(); Serial.read(); Serial.read();
      myFile.close();
      Serial.println("File transfer complete.");
      while (true);  // Halt
    } else {
      buffer[index++] = c;
      if (index == 64) {  // Buffer full
        myFile.write(buffer, index);
        index = 0;
        Serial.println("ACK");  // Send acknowledgment
      }
    }
  }
}

python code:

import serial
import time

# Configure serial port and file details
arduino_port = "COM3"  # Replace with your Arduino port
baud_rate = 9600
file_path = "screenshot.png"  # Replace with your file path
chunk_size = 64  # Size of each chunk in bytes
end_marker = b"<EOF>"  # Marker to indicate the end of transfer

try:
    with serial.Serial(arduino_port, baud_rate, timeout=5) as ser:
        print("Connected to Arduino.")
        time.sleep(2)  # Allow Arduino to reset and stabilize

        # Open the file to read
        with open(file_path, "rb") as file:
            while True:
                chunk = file.read(chunk_size)
                if not chunk:  # End of file
                    break

                # Send the chunk
                ser.write(chunk)
                print(f"Sent chunk: {chunk}")

                # Wait for Arduino acknowledgment
                ack = ser.readline().strip()  # Read acknowledgment
                if ack != b"ACK":  # Arduino should send "ACK" after processing
                    print(f"Error: No ACK received for chunk. Received: {ack}")
                    break

        # Send the end marker
        ser.write(end_marker)
        print("Sent end marker. File transfer complete.")

except Exception as e:
    print(f"Error: {e}")

having some problem not completeing. He is not sure what is wrong. It is transferring part of the image not the full image. He wanted to know what he is missing or doing wrong in the code in order for it to complete. My friend does know C language.