Writing data to a USB Host Shield and Thumb Drive

Hello. Here is a breakdown of my current components:

I cannot for the life of me figure out how to write code wherein the arduino is able to interface with the thumb drive and write it anything. I am not the best with writing code; I have been troubleshooting this issue with CHATGPT for days now, trying alternative methods and libraries.

I can go back through my literal hundreds of different versions of code and paste some examples, but I would rather hear if any of you have a better method for getting this task done.

I am currently using the newest arduino IDE version 2.1.1. It seems like no library wants to work with this version. I have redownloaded them all using different methods (such as Greiman's UsbFat and Felis' USB_Host_Shield_2.0.)

At the end of the day, my end goal is to make a simple data logger. I have an ADC and RTC connected to my arduino providing the date, time, and voltage. I want those three inputs to be sent to my USB thumb drive every minute or so. I can provide that code if you want:

#include <Wire.h>
#include <Adafruit_ADS1X15.h>
#include <RTClib.h>

// Constants
const int ADS1115_ADDRESS = 0x48; // I2C address of the ADS1115 ADC
const int RTC_ADDRESS = 0x68;    // I2C address of the DS3231 RTC

Adafruit_ADS1115 ads; // Remove the parameter from the constructor
RTC_DS3231 rtc;      // Use RTC_DS3231 from the RTClib library

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  // Initialize the ADS1115 ADC
  ads.begin(ADS1115_ADDRESS); // Initialize with the desired I2C address

  // Initialize the DS3231 RTC
  rtc.begin();

  // Adjust the time on the RTC
  //DateTime adjustedTime(2023, 7, 6, 8, 22, 00); // Set the desired date and time
  //rtc.adjust(adjustedTime); // Adjust the RTC time

}

void loop()
{
  // Read the current time from the DS3231 RTC
  DateTime now = rtc.now();

  // Convert hour, minute and second values to strings with leading zeros
  String hourString = now.hour() < 10 ? "0" + String(now.hour()) : String(now.hour());
  String minuteString = now.minute() < 10 ? "0" + String(now.minute()) : String(now.minute());
  String secondString = now.second() < 10 ? "0" + String(now.second()) : String(now.second());

  // Read the voltage from the ADS1115 ADC
  int16_t adcValue = ads.readADC_SingleEnded(0); // Read from channel 0
  float voltage = adcValue * 0.0001875; // Convert raw value to voltage (6.144V / (2^15bits))

  // Convert Voltage to Temperature
  float temperature = voltage * (1800 / 5);

  // Print the Current Time
  Serial.print("Current Time: ");
  Serial.print(hourString);
  Serial.print(":");
  Serial.print(minuteString);
  Serial.print(":");
  Serial.print(secondString);
  Serial.println();

  // Print the Voltage
  Serial.print("Voltage: ");
  Serial.print(voltage, 3);
  Serial.println(" V");

  // Print the Converted Temperature
  Serial.print("Temperature: ");
  Serial.print(temperature, 0);
  Serial.println(" °C");

  // Leave a Space between datapoints
  Serial.println("");

  delay(1000); // Wait for 1 second before reading again
}

By the way, I am open to hearing other ways of saving/writing the data. If you think I should go with an SD Card, for example, I would love to know why/how. I only initially went with the USB thumb drive because I figured it would provide users the best method for taking the data to their computers and downloading the data. I looked into doing it with an SD card, but I could not find anything better. Again, if you think I should switch to a different arduino board, I would love to know why, but I figured the Mega 2560 would be best because it allowed me to connect both the RTC and ADC.

Like I mentioned, I am in no way experienced writing lots of code. Learning about libraries and such was an experience for me. I have learned a lot over this past week or two, however, at this point, I really just want this project finished.

USB comes with many different protocols/classes, e.g. HID or Serial. You have to find a library that includes the mass storage class implemented in the thumb drive. Then you have to find a FAT32 library for accessing the files on the drive.

Even an Arduino Mega does not have enough memory for such a task. Better look at a full fledged external drive shield that makes access to your thumb drive as easy as to a SD card.

1 Like

Enough memory?

"USB_Host_Shield_Library_2.0" has a mass storage class.
"UsbFat-master" is a FAT32 library.
These are both libraries I called upon and utilized, however, I could never make them work.

I have an USB Thumb Drive that, when plugged into my computer, would have a little LED that stays lit which indicated it was plugged in. When I would plug it into my USB Host Shield, it would light up for only a split second. I am guessing the LED indicates whether there is some kind of connection happening between the thumb drive and computer. It didn't want to initialize properly using the arduino. I know there was always 5 volts at the connection, so I know that was not the issue.

I find it hard to believe that the Arduino Mega would not have enough memory to write to a USB thumb drive, especially because I have read that people have been able to accomplish such a task. It would only be sending 20 characters or so every minute, which I do not believe to be a lot of data.

Are you alluding to SD Cards being easier to write to in your final sentence?

On the USB thumb drive?
If so, yes.. there would be literal years worth of capacity from a single 8Gb thumb drive.

If you are asking about the Arduino's memory, my test trials only had it writing "A,B,C,D" to the USB thumb drive. I never even tried to implement the code I showed above into the trials of writing data to the USB thumb drive. I would be shocked if an Arduino Mega could not output 4 characters to a mass storage device. (I could very well be wrong about that, however, seeing as though people have said they have been able to write data to a mass storage device in the past, I can't imagine the Arduino's max output would be less than 4 characters.)

It's a matter of the folder structure. Writing to the root directory should be easy.

What do you mean exactly? Are you saying I would need to have the folder/document already made, and then have the Arduino output its results to that file?

On a mass storage device you have to open an existing or create a new file before you

What I am trying to ask is do you think that writing the data to an already created file is less memory consuming than creating a new file? Would that be enough to not allow my code to work?

I have no mass storage device USB shield and consequently can not find out any memory impact. You'll have to find out yourself.

#include <avr/pgmspace.h>

// Define USB host shield pins
#define CLK 10
#define INT 9

// USB host shield register addresses
#define USB_HOST_PINTL 0x45
#define USB_HOST_PSOFTH 0x4C

// USB host shield command codes
#define USB_HOST_CMD_RESET 0xF0
#define USB_HOST_CMD_SET_ADDRESS 0xD0
#define USB_HOST_CMD_SET_ENDPOINT 0xC3
#define USB_HOST_CMD_SETUP_TOKEN 0x10
#define USB_HOST_CMD_IN_TOKEN 0x18
#define USB_HOST_CMD_OUT_TOKEN 0x14

// USB host shield response codes
#define USB_HOST_RESP_SUCCESS 0x13

// Function prototypes
void usbReset();
void usbSetAddress(uint8_t address);
void usbSetEndpoint(uint8_t endpoint);
void usbSetupToken(uint8_t endpoint, uint8_t deviceAddress, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength);
void usbInToken(uint8_t endpoint, uint8_t deviceAddress, uint16_t wLength);
void usbOutToken(uint8_t endpoint, uint8_t deviceAddress, const uint8_t *data, uint16_t wLength);
void writeDataToUSB(const uint8_t *data, uint16_t length);
void writeStringToUSB(const char *str);
void stopProgram();

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ; // Wait for Serial port to initialize
  }

  // Initialize USB host shield
  pinMode(CLK, OUTPUT);
  pinMode(INT, INPUT_PULLUP);
  digitalWrite(CLK, LOW);

  // Reset USB host shield
  usbReset();

  // Check if a USB device is present
  while (digitalRead(INT) == HIGH) {
    Serial.println("USB device not found!");
    delay(1000);
  }

  // Set USB device address
  usbSetAddress(0x01);

  // Set USB device endpoint
  usbSetEndpoint(0x81);

  // Create a new file
  writeStringToUSB("data.csv");
  writeDataToUSB((const uint8_t *)"\r\nA,B,C,D", 10);

  Serial.println("Data written successfully!");

  // Stop the program
  stopProgram();
}

void loop() {
  // Nothing to do here as the program stops in the setup() function
}

void usbReset() {
  digitalWrite(CLK, LOW);
  delayMicroseconds(50);

  for (int i = 0; i < 10; i++) {
    digitalWrite(CLK, HIGH);
    delayMicroseconds(50);
    digitalWrite(CLK, LOW);
    delayMicroseconds(50);
  }
}

void usbSetAddress(uint8_t address) {
  usbSetupToken(0x00, 0x00, 0x00, USB_HOST_CMD_SET_ADDRESS, address, 0x00, 0x00);
  usbInToken(0x00, 0x00, 0x00);
}

void usbSetEndpoint(uint8_t endpoint) {
  usbSetupToken(0x00, 0x00, 0x00, USB_HOST_CMD_SET_ENDPOINT, endpoint, 0x00, 0x00);
  usbInToken(0x00, 0x00, 0x00);
}

void usbSetupToken(uint8_t endpoint, uint8_t deviceAddress, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) {
  digitalWrite(CLK, HIGH);
  delayMicroseconds(50);
  digitalWrite(CLK, LOW);
  delayMicroseconds(50);

  writeDataToUSB((const uint8_t *)&endpoint, 1);
  writeDataToUSB((const uint8_t *)&deviceAddress, 1);
  writeDataToUSB((const uint8_t *)&bmRequestType, 1);
  writeDataToUSB((const uint8_t *)&bRequest, 1);
  writeDataToUSB((const uint8_t *)&wValue, 2);
  writeDataToUSB((const uint8_t *)&wIndex, 2);
  writeDataToUSB((const uint8_t *)&wLength, 2);
}

void usbInToken(uint8_t endpoint, uint8_t deviceAddress, uint16_t wLength) {
  digitalWrite(CLK, HIGH);
  delayMicroseconds(50);
  digitalWrite(CLK, LOW);
  delayMicroseconds(50);

  uint8_t buffer[4];
  buffer[0] = endpoint;
  buffer[1] = deviceAddress;
  buffer[2] = (wLength & 0xFF);
  buffer[3] = ((wLength >> 9) & 0xFF);

  writeDataToUSB(buffer, 4);
}

void usbOutToken(uint8_t endpoint, uint8_t deviceAddress, const uint8_t *data, uint16_t wLength) {
  digitalWrite(CLK, HIGH);
  delayMicroseconds(50);
  digitalWrite(CLK, LOW);
  delayMicroseconds(50);

  uint8_t buffer[4];
  buffer[0] = endpoint;
  buffer[1] = deviceAddress;
  buffer[2] = (wLength & 0xFF);
  buffer[3] = ((wLength >> 9) & 0xFF);

  writeDataToUSB(buffer, 4);
  writeDataToUSB(data, wLength);
}

void writeDataToUSB(const uint8_t *data, uint16_t length) {
  for (uint16_t i = 0; i < length; i++) {
    while (digitalRead(INT) == LOW)
      ;

    uint8_t dataByte = pgm_read_byte(data + i);
    PORTB = dataByte;
    PORTB = dataByte | 0x80;
    PORTB = dataByte;

    delayMicroseconds(50);
  }
}

void writeStringToUSB(const char *str) {
  uint16_t length = strlen(str);
  writeDataToUSB((const uint8_t *)str, length);
}

void stopProgram() {
  while (1)
    ;
}

Do you see something inherently wrong with this code?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.