Daß 2 Nibbles unterwegs sind, sagt man ihm im ersten Befehl:
Im meinen Code kannst du die Stellen zwischen

#ifdef VFD_INTERFACE_8BIT_PARALLEL
...
#endif /* VFD_INTERFACE_8BIT_PARALLEL */

überlesen, weil du das Display ja in 4 Bit-Modus betreiben willst.

Der erste Befehl den ich sende (in vfd_reset()) ist ein
Code:
// CLR () setzt das entsprechende Port-Pin auf 0
// SET () setzt das entsprechende Port-Pin auf 1
CLR (POTR_RS);

//  FUNCTION_SET_DATA4>>4 ist gleich 0x2
vfd_send_byte_or_nibble (FUNCTION_SET_DATA4>>4);
Die wichtigsten Funktionen später sind (#ifdef hab ich schon aufgelöst)
Code:
void vfd_send0 (byte b)
{
   CLR_FLAG (FLAG_VFD_RS);
   vfd_send_byte_or_nibble (b>>4);
   vfd_send_byte_or_nibble (b);
}

void vfd_send1 (byte b)
{
   SET_FLAG (FLAG_VFD_RS);
   vfd_send_byte_or_nibble (b>>4);
   vfd_send_byte_or_nibble (b);
}
Aus diesen Funktionen ist später der ganze Kommande/Datenstrom aufgebaut. In FLAG_VFD_RS merke ich mir wie der PORT_RS im moment der Ausgabe zu stehen hat. Wie ich das genu umgesetzt habe ist egal, nur zum Verständnis.

Das ist nun die vfd_send_byte, wieder hab ich das Zeug rausgeworfen,
das nur 8-Bit-parallel-Modus verwendet wird.
Da bei dir die Ports nebeneinander liegen, kannst du das besser machen als ich in meinem Code. Wie, brauch ich dir ja nicht mehr zu erklären
Code:
void vfd_send_byte_or_nibble (byte b)
{
   CLR (PORT_E);
   
    // Alle Datenports als Ausgang
   MAKE_OUT (PORT_DB0);
   MAKE_OUT (PORT_DB1);
   MAKE_OUT (PORT_DB2);
   MAKE_OUT (PORT_DB3);

   CLR (PORT_RW);

   // Setzt PORT_RS wie im Flag gemerkt   
   CLR (PORT_RS);
   if (IS_FLAG (FLAG_VFD_RS))
      SET (PORT_RS);

   // Alle Datenports auf 0      
   CLR (PORT_DB0);
   CLR (PORT_DB1);
   CLR (PORT_DB2);
   CLR (PORT_DB3);

   // Das Nibble ausgeben.
   // Bei mir ist das etwas komplizierter, weil die Ports nicht nebenein
   // ander liegen müssen. Wo PORT_DBx liegt wird zentral verwaltet,
   // der genaue Wert ist hier egal.
   if (b & (1<<0))    SET (PORT_DB0);
   if (b & (1<<1))    SET (PORT_DB1);
   if (b & (1<<2))    SET (PORT_DB2);
   if (b & (1<<3))    SET (PORT_DB3);

   // Daten raushauen
   SET (PORT_E);
   LOOP (100);
   CLR (PORT_E);

   // Wieder alle Daten-Ports als Eingang
   // Das brauch ich nur um Kollisionen auf dem Bus zu vermeiden
   MAKE_IN (PORT_DB0);
   MAKE_IN (PORT_DB1);
   MAKE_IN (PORT_DB2);
   MAKE_IN (PORT_DB3);
}
Das wichtigste ist, daß du beim Initialisieren für den 4bit-Modus nicht 2 Nibbles schickst, sonder nur eines!

Mit den Erläuterungen kannst du auch den Rest meines Codes gut verstehen.