10: FPGA (DPL) controls Arduino

In this tutorial, we are going to develop a platform where FPGA DueProLogic communicates with Arduino Due.

Four tasks will be demonstrated.
(A) PC remotes FPGA DueProLogic
(B) FPGA DueProLogic controls the LED-13 on Arduino Due
(C) Arduino Due sends ultrasonic sensor data to FPGA DueProLogic
(D) FPGA DueProLogic transmits data to PC

Step 1: Build the electronic circuit



Step 2: Edit Verilog code as follow

   //Arduino Connections
   assign            LEDExt = XIO_5[5];                                 //XIO_5 -- UB59 -- D15 
   assign            XIO_1[3] = start_stop_cntrl;                     //XIO_1 -- UB3 -- D11       
   assign            c_enable = XIO_5[2];                                //XIO_5 -- UB57 -- D17
   assign            data_from_arduino[7] = XIO_6[18];         //XIO_6 -- UB40 -- D40
   assign            data_from_arduino[6] = XIO_6[17];         //XIO_6 -- UB39 -- D39
   assign            data_from_arduino[5] = XIO_6[16];         //XIO_6 -- UB38 -- D38
   assign            data_from_arduino[4] = XIO_6[15];         //XIO_6 -- UB37 -- D37
   assign            data_from_arduino[3] = XIO_6[14];         //XIO_6 -- UB36 -- D36
   assign            data_from_arduino[2] = XIO_6[13];         //XIO_6 -- UB35 -- D35
   assign            data_from_arduino[1] = XIO_6[12];         //XIO_6 -- UB34 -- D34
   assign            data_from_arduino[0] = XIO_6[11];         //XIO_6 -- UB33 -- D33


When you buy FPGA DueProLogic, you should receive a DVD. After you open "Projects_HDL", you should see verilog code



Step 3: Compile verilog code

Press "Start Compilation" in Quartus, no error message should be generated. If you receive error message about multiple pins. Go to Assignments -> Device -> Device and Pin Options -> Dual-Purpose Pins -> change the value of the appropriate pin to "Use as regular I/O".

After compilation, you should get pof output file directly. If you get sof output file only, click "File" in Quartus -> "convert programming files". Change the settings which are marked by red boxes.



Press "Programmer" in Quartus, update the pof file and then click "Start"



Step 4: Upload Arduino code


#define COMMANDDELAY  10  // ms to wait for the filling of Serial buffer

#define COMBUFFERSIZE 3 // Size of buffer for incoming numbers


  int startStopBit = 0;
  int count = 0;
  int echoPin = 2;         // Echo
  int trigPin = 3;           // Trigger
  long duration, cm, inches;
  int inPin11 = 11;       //Input
  int ledPin = 13;        //Due Output
  int LEDExt = 15;     //Output
  int C_Enable = 17;   //Output

  int new_value = 0x00000000;
  int data_top_2bits = 0;
  int data_bottom_6bits = 0;
  int data_to_DPL = 0;

  int newP = 500;

  char commandBuffer[COMBUFFERSIZE+1];

// Fills the given buffer with bufferSize chars from a Serial object
void fillBuffer( \
  char *buffer, \
  byte bufferSize, \
  HardwareSerial* serial = &Serial );

void setup()
{

   int k ;
 
   //Set pins D33-D41 as outputs
     for( k = 33 ; k <= 41 ; k++ )
      pinMode( k, OUTPUT ) ; // Sets Port C2-C9 to output pins

    // Set the output pins in the Output Write Enable Register
    REG_PIOC_OWER =  0x0000037E ;

    // Disable writing to all other pins on the same port-
    REG_PIOC_OWDR = 0xFFFFFC81 ;
 
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(C_Enable, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(LEDExt, OUTPUT);
  pinMode(inPin11, INPUT);
  pinMode(motorPin, OUTPUT);

  //randomSeed(analogRead(1));

  Serial.begin(115200);
}

void loop ()
{

   int i ; 
   //Sample the Start/Stop switch
   //from the EPT-4CE6-AF 
   startStopBit = digitalRead(inPin11);
   Serial.println(startStopBit);
   delay(newP); //Delay in ms
   if(startStopBit==0)
   {
     digitalWrite(ledPin, LOW);
     delay(1000);
   }
   if(startStopBit==1)
   {
     digitalWrite(ledPin, HIGH);
     delay(1000);

     digitalWrite(trigPin, LOW);
     delayMicroseconds(5);
     digitalWrite(trigPin, HIGH);
     delayMicroseconds(10);
     digitalWrite(trigPin, LOW);
     pinMode(echoPin, INPUT);
     duration = pulseIn(echoPin, HIGH);
     cm = (duration/2) / 29.1;     // Divide by 29.1 or multiply by 0.0343, this is physics
 
     new_value = cm;
     delay(1000);
       
   
      //Map the the transfer byte to pins available on the DueProLogic
      data_top_2bits = (new_value & 0x000000c0)<<2;
      data_bottom_6bits = (new_value & 0x0000003F)<<1;
   
      //Or the re-mapped bits together and use the ODSR register to transmit the bits
      data_to_DPL = data_top_2bits | data_bottom_6bits;
      REG_PIOC_ODSR = data_to_DPL;
       
      //Set the Write Enable Pin High
       digitalWrite(C_Enable, HIGH);

      //Set the LED Pin High
      digitalWrite(LEDExt, HIGH);
   
      delay(newP); //Delay in ms

      //Set the LED Pin Low
      digitalWrite(LEDExt, LOW);
   
      //Set the Write Enable Pin Low
      digitalWrite(C_Enable, LOW);
   
   }
 
    if ( Serial.available() > 0 )
   {
      // Read the incoming byte
      char theChar = Serial.read();
      // Parse character
      switch (theChar) {
      case 's': // 's' for setting time between samples
      // Wait for COMMANDDELAY ms to be sure that the Serial buffer is filled
      delay(COMMANDDELAY);

      fillBuffer( commandBuffer, COMBUFFERSIZE );

      // Convert buffer to integer
      //commandBuffer = "32";
      newP = atoi( commandBuffer );

      // Display moving status indicator
      Serial.print("Setting the EPT prescaler to: ");
      Serial.println(newP);

      //Call set timing with newP
      //setIntervalTiming(newP);
      break;
      default:
      // Display error message
      Serial.print("ERROR: Command not found, it was: ");
      Serial.println(theChar);
      break;
      }
   }

}

//-----------------------------------------------------------------------------
// fillBuffer
//-----------------------------------------------------------------------------
// Fills the given buffer with bufferSize chars from a Serial object

void fillBuffer( char *buffer, byte bufferSize, HardwareSerial* serial )
{
  // Clean buffer
  memset( (void *)buffer, '\0', sizeof(char) * bufferSize );


  byte limit = ( bufferSize < serial->available() ) ? bufferSize : serial->available();


  // Fill buffer
  for ( byte i = 0; i < limit; i++ ) {

    buffer[i] = serial->read();
  }
}


Step 5: Connect FPGA to PC

You have to Install Visual Studio C#. Then open the C# file in Active_Host (DVD).

Create ON and OFF buttons in GUI interface with help of C# Toolbox.

//On button:
private void btnWriteByte_Click(object sender, EventArgs e)
{
            int address_to_device;
            address_to_device = Convert.ToInt32(tbAddress.Text);
            EPT_AH_SendTransferControlByte((char)2, (char)1);
}

//OFF button
private void btnTransferReset_Click(object sender, EventArgs e)
{
            int address_to_device;
            address_to_device = Convert.ToInt32(tbAddress.Text);
            EPT_AH_SendTransferControlByte((char)address_to_device, (char)0);
}

The char 0 and 1 determine the status of "start_stop_cntrl" in FPGA

When you compile and build the C# projects, exe file will be generated  in C:\Visual Studio 2019\Data_collector\bin\x64\Release.


When you click "On", your PC sends signals to the FGPA to light up LED-13 on Arduino Due. Meanwhile the ultrasonic sensor transfers the data to the FPGA and then the data will be appeared on your PC. 

Demo

Comments