Can I skip the USB Host Shield and just use the ATMEGA328P's digital pins?

I have Hex data I'd like to send via USB. Can I just use the chip's built in I/O pins?

No. The 328P isn't connected to the USB. There's a 16U2 chip on the Arduino Uno board which does this.

Some people have hacked the 16U2 chip but it's not recommended. The Uno no longer works as an Arduino after that.

Choose a different Arduino, such as a Micro or a Teensy. They do connect direct to USB. The Teensy has good libraries to act as a joystick, keyboard, mouse or whatever.

I realize that it's not connected to it's own USB port, but what I mean to say is, can I use the digitial I/O on the chip to wire to a USB cable's serial pair and after this is complete also provide the 5V and GND for the other two wires in the cable? I'd like to skip the host shield if this is possible.

To send data back to the host PC, you use the "Serial" library to send it via the USB to serial interface which works in both directions. The PC then needs to have software running on it to process that data.

A "host shield" is used to interface other USB peripherals, such as mice, keyboards and flash drives.

You could maybe just use an FTDI adaptor (cheaper versions on eBay) connected to RX/TX pins on arduino. If you want to build your own USB interface then you would need to knock up some hardware anyway, easier to use FTDI as you just use Serial like you would on a UNO/MEGA etc.

Thanks! I'm looking to just output some Hex data to the USB. Something similar to the output from this code but WAY simpler. I'd like to just have a set of pre-chosen hex digits dumped when a set input is given to the Arduino's pins. It'd sure be nice to use only one chip and also keep the wiring minimal.

//
//   ZOOM G3 Patch Change using MIDI over USB
//           (c)2013, Antonis Maglaras
//              maglaras@gmail.com
//
// Library Used:
// https://github.com/YuuichiAkagawa/USBH_MIDI
//
//
// To Do:
// - Too bored to write down my TO-DO list... :)
//
// Please, when you copy & paste the code and share it on the internet,
// just say a thank you :-)
//

#include <Usb.h>
#include <usbhub.h>
#include <usbh_midi.h>
#include <LiquidCrystal.h>

// I had to modify the LCD Shield, due to pin conflict with the USB Host Shield.
//
// Solution:
// I totally removed the pins D8, D9, D10 (unsoldered) from the LCD Shield.
// I jumper the pin D3 to D8 and D2 to D9.
// The D10 was used for controlling the backlit (?). I left it unconnected.

LiquidCrystal lcd(3, 2, 4, 5, 6, 7);

int KeyboardInput = 0;
#define KbdPin     A0
#define btnRIGHT    0
#define btnUP       1
#define btnDOWN     2
#define btnLEFT     3
#define btnSELECT   4
#define btnNONE     5

USB  Usb;
MIDI  Midi(&Usb);

byte Preset;

void setup()
{
  lcd.begin(16, 2);                  // start the library
  if (Usb.Init() == -1) 
  {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("USB Host Shield ");
    lcd.setCursor(0,1);
    lcd.print(" ** FAILED! **  ");
    while(1);               // Halt
  }
  delay(200);
  Preset = 1; 
  lcd.setCursor(0,0);
  lcd.print("     MAGLA     ");
  lcd.setCursor(0,1);
  lcd.print(" MIDI over USB ");
  delay(1500);
  SendMIDI(0);
  lcd.setCursor(0,0);
  lcd.print("Current Patch   ");
  lcd.setCursor(0,1);
  lcd.print("Go to patch     ");
  DisplayAtLine(Preset,0);
  DisplayAtLine(Preset,1);
}


void loop()
{
  switch (read_LCD_buttons())        // Read if a button is pressed
  {
    case btnLEFT:                    // LEFT: Choose the previous patch
      Preset-=1;
      if (Preset<1)
        Preset=100;
      DisplayAtLine(Preset,1);
      delay(100);
      break;
    case btnRIGHT:                   // RIGHT: Choose the next patch
      Preset+=1;
      if (Preset>100)
        Preset=1;
      DisplayAtLine(Preset,1);
      delay(100);
      break;
    case btnSELECT:                  // SELECT: Activate the current patch
      SendMIDI(Preset);
      DisplayAtLine(Preset,0);
      delay(100);
      break;
    case btnDOWN:                    // DOWN: Activate the previous patch
      Preset-=1;
      if (Preset<1)
        Preset=100;
      SendMIDI(Preset);
      DisplayAtLine(Preset,0);
      DisplayAtLine(Preset,1);
      delay(100);   
      break;
    case btnUP:                       // UP: Activate the next patch
      Preset+=1;
      if (Preset>100)
        Preset=1;
      SendMIDI(Preset);
      DisplayAtLine(Preset,0);
      DisplayAtLine(Preset,1);
      delay(100);   
      break;
  }
}


// Send "Program Change" MIDI Message

void SendMIDI(byte number)
{
  number-=1;                         // Change 1 to 0, 100 to 99.
  Usb.Task();
  if( Usb.getUsbTaskState() == USB_STATE_RUNNING )
  { 
    byte Message[2];                 // Construct the midi message (2 bytes)
    Message[0]=0xC0;                 // 0xC0 is for Program Change (Change to MIDI channel 0)
    Message[1]=number;               // Number is the program/patch (Only 0 to 99 is valid for ZOOM G3)
    Midi.SendData(Message);          // Send the message
    delay(10); 
  } 
}


void DisplayAtLine(byte number, byte line)
{
  number-=1;                         // Change 1 to 0, 100 to 99.  
  byte first = number/10;            // Get the first digit
  byte second = number % 10;         // Get the second digit
  lcd.setCursor(14,line);
  lcd.print(char(65+first));         // Print the char (A to J for 0-9)
  lcd.print(second);                 // Print the second digit
}



int read_LCD_buttons()
{
 KeyboardInput = analogRead(KbdPin); // Read the value from the keyboard
                                     // Buttons when read are centered at these valies: 0, 131, 306, 478, 720
                                     // We add approx 50 to those values and check to see if we are close
 if (KeyboardInput > 1000) return btnNONE;     // We make this the 1st option for speed reasons since it will be the most likely result
 if (KeyboardInput < 50)   return btnRIGHT; 
 if (KeyboardInput < 185)  return btnUP;
 if (KeyboardInput < 360)  return btnDOWN;
 if (KeyboardInput < 530)  return btnLEFT;
 if (KeyboardInput < 770)  return btnSELECT;  
 return btnNONE;                     // When all others fail, return this...
}

Use an Arduino with built-in native USB like the Micro or Leonardo (for sticking with the AVR's) or the Teensy.

It is important to recognize that over USB, you don't just "send bytes down USB" - there's a whole USB protocol running underneath that, whereby the USB device is telling the computer what kind of device it is, with vendor and part ID codes - and while it may "look" like you're just sending a couple of bytes, those libraries are doing a good deal of work under the hood to achieve that.

If your specific use case is MIDI, there's code somewhere that can be used with an Uno/Mega, but you have to reprogram the 16u2. I forget the details though.

Thanks! I'm looking to just output some Hex data to the USB.

To what USB device?

Sending data to a USB printer is different from sending data to a USB thumb drive and that's different from sending data to a MIDI instrument, etc. Usually it requires a driver for the particular device. (I assume <usbh_midi.h> is a driver.)

I'd recommend you test your concept and your software with a USB shield before attempting to build/configure your own USB hardware.

Thanks DVDdoug. I am not necessarily interested in building existing hardware. More curious if I can skip the USB shield since I'm sending MIDI CC commands (simple Hex dumps).