Module 18

From Hamsterworks Wiki!

Jump to: navigation, search

Please make sure that you have completed the earlier modules of FPGA course.

Having problems with your code? Do I need to change something? Want a reference solution to the project? Email me at "nospam-hamster@snap.net.nz", after removing the "nospam-" bit. I'll try to get back to you in a day or so.

Contents

Aim of this module

  • Learn how to implement the PC side of Diligent's USB interface
  • Learn how to implement the FPGA side of Diligent's USB interface

This module is only applicable to Digilent boards, and assumes that you are using the Windows OS - but I'm sure that only minor changes are needed for it all to work under Linux too.

The Digilent Parallel Interface

Digilent boards have a port of the USB interface wired to the FPGA. I've used this to transfer data at up to 11 megabytes per second. The documentation is pretty terse, so here is a quick start guide.

The interface implements the long obsolete EPP protocol that was traditionally used to talk to parallel port scanners. It allows the connected device to address up to 256 8-bit registers that can be implemented within the FPGA.

These registers can either be read one byte at a time, or a "Repeat" function can be called to read multiple bytes from the register.

The most "make or break" shortcoming of this interface is that there is no interrupt signal going back to the host which would allow the FPGA it's attention. Unlike when using RS232 this forces the host software to poll the FPGA at regular intervals - which is not ideal for responsiveness or CPU usage.


Resources

The FPGA side of the interface

The following signals make up the interface:

Name Source Description
DB(7 downto 0) INOUT Data bus
WRITE IN Write Enable (active Low) - data will be written from the host during this cycle
ASTB IN Address strobe (active low) - data bus will be captured into the address register
DSTB IN Data Strobe (active low) - bus will be captured into the currently selected data register
WAIT OUT Asserted when FPGA read to accept data,
INT OUT Interrupt request - not used
RESET IN Reset - not used

Read Transaction

The steps in a read transaction are

  • Host lowers ASTB or DSTB to commence read of either the address register or the selected data register
  • FPGA presents data on data bus
  • FPGA raises WAIT indicating that the data is valid
  • Host captures the data
  • Host raises ASTB or DSTB
  • FPGA removes the data from the data bus
  • FPGA lowers WAIT to finish transaction

Write transaction

The steps in a write transaction are

  • Host presents data on data DB()
  • Host lowers Write Enable to 0
  • Host lowers either ASTB or DSTB to commence write of either the address register or the selected data register.
  • FPGA raises WAIT once data is captured
  • Host raises ASTB or DSTB, removes data from bus and raises Write Enable
  • FPGA lowers WAIT to finish transaction

FSM diagram

Epp fsm.png

Constraints for the BASYS2 board

The constraints required to implement the interface are:

NET "EppAstb" LOC = "F2"; # Bank = 3
NET "EppDstb" LOC = "F1"; # Bank = 3
NET "EppWR"   LOC = "C2"; # Bank = 3

NET "EppWait" LOC = "D2"; # Bank = 3

NET "EppDB<0>" LOC = "N2"; # Bank = 2
NET "EppDB<1>" LOC = "M2"; # Bank = 2
NET "EppDB<2>" LOC = "M1"; # Bank = 3
NET "EppDB<3>" LOC = "L1"; # Bank = 3
NET "EppDB<4>" LOC = "L2"; # Bank = 3
NET "EppDB<5>" LOC = "H2"; # Bank = 3
NET "EppDB<6>" LOC = "H1"; # Bank = 3
NET "EppDB<7>" LOC = "H3"; # Bank = 3

VHDL for the FPGA interface

This source allows you to set the LEDs and read the switches from the PCs. It has a few VHDL features that you won't have seen up to now:

  • The EppDB (EPP Data bus) is INOUT - a tristate bidirectional bus. When you assign "ZZZZZZZZ" (high impedance) to the signal it will then 'read' as the input from the outside world. This is only really useful on I/O pins - within the FPGA tristate logic is implemented using multiplexers
  • It uses an enumerated type to hold the FSM 'state'. This is only really useful if you don't want to use bits withing the state value to drive logic (which is usually a good way to get glitch free outputs).
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity epp_interface is
   port (Clk     : in    std_logic;      
         -- EPP interface
         EppAstb : in    std_logic;
         EppDstb : in    std_logic;
         EppWR   : in    std_logic;
         EppWait : out   std_logic;
         EppDB   : inout std_logic_vector(7 downto 0);
      
         -- Feedback
         switches: in    std_logic_vector(7 downto 0);
           leds    : out   std_logic_vector(7 downto 0)      
   );
end epp_interface;

architecture Behavioral of epp_interface is
   type   epp_state is (idle, data_read, data_write, addr_read, addr_write);
   signal state      : epp_state := idle;
   signal address    : std_logic_vector(7 downto 0) := (others => '0');
   signal port0data  : std_logic_vector(7 downto 0) := (others => '0');
begin   
   process(clk)
   begin
   
      if rising_edge(clk) then
         case state is 
            when data_read  =>
               EppWait <= '1';
               case address is
                  when "00000000" =>
                     EppDB <= not port0data;
                  when "00000001" =>
                     EppDB <= switches;
                  when others =>
               end case;

               if EppDstb = '1' then
                  state <= idle;
               end if;
            when data_write =>
               EppWait <= '1';
               case address is
                  when "00000000" =>
                     port0data <= EppDB;
                  when "00000001" =>
                     leds <= EppDB;
                  when others =>
               end case;

               if EppDstb = '1' then
                  state <= idle;
               end if;
   
            when addr_read  =>
               EppWait <= '1';
               EppDB   <= address;
               if EppAstb = '1' then
                  state <= idle;
               end if;
               
            when addr_write =>
               EppWait <= '1';
               address <= eppDB;
               if EppAstb = '1' then
                  state <= idle;
               end if;
               
            when others =>
               EppWait  <= '0';
               EppDB <= "ZZZZZZZZ";
               if EppWr = '0' then
                  if  EppAstb = '0' then
                     state <= addr_write;
                  elsif EppDstb = '0' then
                     state <= data_write;
                  end if;
               else
                  if EppDstb = '0' then
                     state <= data_read;
                  elsif EppAstb = '0' then
                     state <= addr_read;
                  end if;
               end if;
         end case;
      end if;
   end process;
end Behavioral;

The PC side of the interface

Header files and libraries

These are in the Adept SDK, which can be downloaded from http://www.digilentinc.com/Products/Detail.cfm?Prod=ADEPT2

The zip file includes all the files you need, including documentation, libraries and examples.

The following header files are needed in your C code:

  • gendefs.h
  • dpcdefs.h
  • dpcutil.h

You will also need to add the path to the libraries into your project's linking settings.

Connecting to a device

Connecting isn't that simple, but it's not that hard either. Three functions are needed:

  • DpcInit()
  • DvmgGetDefaultDev()
  • DvmgGetDevName()
	if (!DpcInit(&erc)) {
		printf("Unable to initialise\n");
		return 0;
	}

	id = DvmgGetDefaultDev(&erc);
	if (id == -1) {
		printf("No default device\n");
		goto error;
	}

	if(!DvmgGetDevName(id, device, &erc)) {
		printf("No device name\n");
		goto error;
	}

Note - the first time you make use of the interface you may need to call one more function once to present a dialogue box allowing you to select which FPGA board will be your default device:

  • DvmgStartConfigureDevices()

Connecting to the EPP port of that device

One function is used to connect to the device (vs connecting to the JTAG port):

  • DpcOpenData()
	if (!DpcOpenData(&hif, device, &erc, NULL)) {
		goto fail;
	}


Reading a port

Reading a port is achieved with either of these functions:

  • DpcGetReg() - Read a single byte from a register
  • DpcGetRegRepeat() - Read multiple bytes from a register

Here's an example function that opens the EPP port and reads a single register

static int GetReg(unsigned char r) {

	unsigned char b;
	ERC		erc;
	HANDLE	hif;

	if (!DpcOpenData(&hif, device, &erc, NULL)) {
		goto fail;
	}

	if (!DpcGetReg(hif, r, &b, &erc, NULL)) {
		DpcCloseData(hif,&erc);
		goto fail;
	}

	erc = DpcGetFirstError(hif);
	DpcCloseData(hif, &erc);

	if (erc == ercNoError) 
		return b;
fail:
	return -1;
}

Writing to a register

Reading a port is achieved with either of these functions:

  • DpcGetReg() - Read a single byte from a register
  • DpcGetRegRepeat() - Read multiple bytes from a register

Here's an example function that opens the EPP port and writes to a single register

static int PutReg(unsigned char r, unsigned char b) {

	ERC		erc;
	HANDLE	hif;
	printf("Put %i %i\n",r,b);
	if (!DpcOpenData(&hif, device, &erc, NULL)) {
		goto fail;
	}

		if(!DpcPutReg(hif, r, b, &erc, NULL)) {
			DpcCloseData(hif,&erc);
			goto fail;
		}

	erc = DpcGetFirstError(hif);
	DpcCloseData(hif, &erc);

	if (erc == ercNoError) 
		return 0;

fail:
	return -1;
}


Closing the EPP port

One function is used to close the EPP port:

  • DpcCloseData()
	DpcCloseData(hif, &erc);

	if (erc == ercNoError) 
		return b;

Closing the interface

It is always good to clean up after yourself. Use the following function to do so:

  • DpcTerm()
	DpcTerm();

Project 18.1 - Using the PC end of the interface

M18s1.png

  • Create a C program that opens the interface and reads a single byte from registers 5 and 6 and displays the value to the screen.
  • Close of Adept and check that your C program also shows the state of the switches on the Basys2.
  • Expand you C program to write to the value of the switches to register 1 - this is the LEDs.

You now have the host side of bidirectional communication sorted!

Project 18.2 - Implementing the FPGA end of the interface

  • Create a new FPGA project
  • Create a module that implements the EPP protocol - or use the one above if Digilent's reference design if you want.
  • Connect writes of register 1 to the LEDs.
  • Connect reads of register 5 or 6 to the switches
  • Test that your design works just as well with your program as Digilent's reference design


Ready to carry on?

Click here to carry on to the next module.

Full source code for a more complex application

Here's a rough and ready terminal app I wrote to allow me to configure the flash on a Nexys2 using the "Onboard Memory controller reference design" from the Digilent web site. It might be of help to somebody:

/************************************************************************/
* Utility to access the memory configuration utility on a NEXYS2 FPGA
* over the USB interface
* Supplied as-is, where-is by hamster@snap.net.nz
/************************************************************************/

#include "StdAfx.h"
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>

#include "gendefs.h"

#include "dpcdefs.h"	/* holds error codes and data types for dpcutil	*/
#include "dpcutil.h"	/* holds declaration of DPCUTIL API calls		*/

static char			device[cchShortString+1];

/****************************************************************************/
static void printDpcError(char *whereTxt, ERC erc)
{
	printf("%s: ",whereTxt);
	switch(erc)
	{
	case 0:
		printf("No error\n");
		break;
	case 3006:
		printf("Internal Error %i\n",erc);
		break;
	default:
		printf("Unknown Error %i\n",erc);
		break;
	}
}

/****************************************************************************/
static int PutReg(unsigned char r, unsigned char b) {

	ERC		erc;
	HANDLE	hif;
	printf("Put %i %i\n",r,b);
	if (!DpcOpenData(&hif, device, &erc, NULL)) {
		goto fail;
	}

		if(!DpcPutReg(hif, r, b, &erc, NULL)) {
			DpcCloseData(hif,&erc);
			goto fail;
		}

	erc = DpcGetFirstError(hif);
	DpcCloseData(hif, &erc);

	if (erc == ercNoError) 
		return 0;

fail:
	return -1;
}

/****************************************************************************/
static int GetReg(unsigned char r) {

	unsigned char b;
	ERC		erc;
	HANDLE	hif;

	if (!DpcOpenData(&hif, device, &erc, NULL)) {
		goto fail;
	}

	if (!DpcGetReg(hif, r, &b, &erc, NULL)) {
		DpcCloseData(hif,&erc);
		goto fail;
	}

	erc = DpcGetFirstError(hif);
	DpcCloseData(hif, &erc);

	if (erc == ercNoError) 
		return b;
fail:
	return -1;
}

/****************************************************************************/
static int ReadFlash(unsigned address, unsigned short *words, unsigned len) {

	ERC		erc;
	HANDLE	hif;
	int i = 0;
	if (!DpcOpenData(&hif, device, &erc, NULL))
		goto failnoclose;

	// Double the address as we are working in word mode (a0 not used!)
	address *= 2;

	// Read array command
	if(!DpcPutReg(hif, 4, 0xFF, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x15, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x17, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x1F, &erc, NULL))	goto fail;
	// Turn flash off all devices 
	if(!DpcPutReg(hif, 0, 0x3F, &erc, NULL))	goto fail;

	// Set up the address
	if(!DpcPutReg(hif, 1,(unsigned char)((address>> 0) & 0xff), &erc, NULL)) goto fail;
	if(!DpcPutReg(hif, 2,(unsigned char)((address>> 8) & 0xff), &erc, NULL)) goto fail;
	if(!DpcPutReg(hif, 3,(unsigned char)((address>>16) & 0xff), &erc, NULL)) goto fail;

	// Get all the bytes in one hit
	int offset = 0;
	while(offset < len)
	{
		printf("Reading at Address %i\n",offset);
		int toRead = len - offset;
		if(toRead > 64*1024)
			toRead = 64*1024;
		if(!DpcGetRegRepeat(hif, 7, (unsigned char *)(words+offset), toRead*2, &erc, NULL))	goto fail;
		offset += toRead;
	}
	// Disable the controller
	if(!DpcPutReg(hif, 0,0x0F, &erc, NULL))
		goto fail;

	if(!DpcCloseData(hif, &erc))
		goto failnoclose;
	return 0;
fail:
	// Use a different error code holder
	{
		ERC erc2;
		DpcCloseData(hif,&erc2);
	}
failnoclose:
	printDpcError("FailError",erc);
	return -1;
}

/****************************************************************************/
void dumpData(unsigned address, unsigned short *words, int len)
{
	int i = 0;
	printf("\n");
	while(len > 0)
	{
		// Output to the screen
		if( (i & 0x7) == 0)	printf("%06x:",address+i);
		printf(" %04x", (int)words[0]);
		if((i&0x7) == 0x7 || len == 0) printf("\n");

		words++; i++; len--;
	}
}

/****************************************************************************/
static int WriteFlash(unsigned address, unsigned short *words, unsigned len) {

	ERC		erc;
	HANDLE	hif;
	int i = 0;

	// Double the address as we are working in word mode (a0 not used!)
	address *= 2;

	if (!DpcOpenData(&hif, device, &erc, NULL))
		goto failnoclose;

	// Turn flash on
	if(!DpcPutReg(hif, 0, 0x3F, &erc, NULL))
		goto fail;

	// Address
	if(!DpcPutReg(hif, 1,(unsigned char)((address>> 0) & 0xff), &erc, NULL)) goto fail;
	if(!DpcPutReg(hif, 2,(unsigned char)((address>> 8) & 0xff), &erc, NULL)) goto fail;
	if(!DpcPutReg(hif, 3,(unsigned char)((address>>16) & 0xff), &erc, NULL)) goto fail;

	if (!DpcPutRegRepeat(hif, 7, (unsigned char *)words, len*2,&erc, NULL))	goto fail;

	// Disable the flash - write over
	if(!DpcPutReg(hif, 0,0x07, &erc, NULL))
		goto fail;

	if(!DpcCloseData(hif, &erc))
		goto failnoclose;
	return 0;
fail:
	// Use a different error code holder
	{
		ERC erc2;
		DpcCloseData(hif,&erc2);
	}
failnoclose:
	printDpcError("FailError",erc);
	return -1;
}

/****************************************************************************/
static int EraseFlash(unsigned address) {

	ERC		erc;
	HANDLE	hif;
	unsigned char res = 0;

	// Double the address as we are working in word mode (a0 not used!)
	address *= 2;

	int i = 0;
	if (!DpcOpenData(&hif, device, &erc, NULL))
		goto failnoclose;

	// Set Address
	if(!DpcPutReg(hif, 1,(unsigned char)((address>> 0) & 0xff), &erc, NULL)) goto fail;
	if(!DpcPutReg(hif, 2,(unsigned char)((address>> 8) & 0xff), &erc, NULL)) goto fail;
	if(!DpcPutReg(hif, 3,(unsigned char)((address>>16) & 0xff), &erc, NULL)) goto fail;

	// Load erase command
	if(!DpcPutReg(hif, 4, 0x20, &erc, NULL))	goto fail;

	// Generate Write seq
	if(!DpcPutReg(hif, 0, 0x15, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x17, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x1F, &erc, NULL))	goto fail;

	// Load confirm command
	if(!DpcPutReg(hif, 4, 0xD0, &erc, NULL))	goto fail;

	// Generate Write seq
	if(!DpcPutReg(hif, 0, 0x15, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x17, &erc, NULL))	goto fail;
	if(!DpcPutReg(hif, 0, 0x1F, &erc, NULL))	goto fail;

	printf("Erasing data at %i",address);
	while((res&0x80) == 0)
	{
		if(!DpcGetReg(hif, 7, &res, &erc, NULL)) goto fail;
		printf(".");
		Sleep(100);
	}
	printf("\n");

	// Disable the flash - erase over
	if(!DpcPutReg(hif, 0,0x0F, &erc, NULL))
		goto fail;

	if(!DpcCloseData(hif, &erc))
		goto failnoclose;

	return 0;
fail:
	// Use a different error code holder
	{
		ERC erc2;
		DpcCloseData(hif,&erc2);
	}
failnoclose:
	printDpcError("FailError",erc);
	return -1;
}

/****************************************************************************/
int UploadFile(char *fname, unsigned address)
{
	unsigned short *buffer;
	FILE *f;
	int len;
	int offset = 0;

	f = fopen(fname,"rb");
	if(f == NULL)
	{
		printf("ERROR: Unable to open '%s'\n",fname);
		return -1;
	}
	fseek(f,0,SEEK_END);
	len = ftell(f);
	printf("File is %i bytes\n",len);
	if(len & 1)
	{
		printf("ERROR: File '%s' is not an even number of words\n",fname);
		fclose(f);
		return -1;
	}
	fseek(f,0,SEEK_SET);
	buffer = (unsigned short *)malloc(len);
	if(buffer == NULL)
	{
		printf("ERROR: Out of memory\n");
		fclose(f);
		return -1;
	}
	if(fread(buffer,len,1,f) != 1)
	{
		printf("ERROR: Unable to read file '%s'\n",fname);
		free(buffer);
		fclose(f);
	}
	fclose(f);

	// From here on down, offset is in short words.
	len /= 2;
	while(offset < len)
	{
		int toflash;

		printf("Writing at offset %x\n",offset*2);
		toflash = len - offset;
		if(toflash > 32*1024)
		  toflash = 32*1024;

		if(WriteFlash(address+offset, buffer+offset, toflash) < 0) 
		{
			printf("Write to flash failed\b\b\n");
			free(buffer);
			return -1;
		}
		offset+=toflash;
	}
	free(buffer);
	return len;
}


/****************************************************************************/
int VerifyFile(char *fname, unsigned address)
{
	unsigned short *buffer1, *buffer2;
	FILE *f;
	int len;

	f = fopen(fname,"rb");
	if(f == NULL)
	{
		printf("ERROR: Unable to open '%s'\n",fname);
		return -1;
	}
	fseek(f,0,SEEK_END);
	len = ftell(f);
	printf("File is %i bytes\n",len);
	if(len & 1)
	{
		printf("ERROR: File '%s' is not an even number of words\n",fname);
		fclose(f);
		return -1;
	}
	fseek(f,0,SEEK_SET);
	buffer1 = (unsigned short *)malloc(len);
	if(buffer1 == NULL)
	{
		printf("ERROR: Out of memory\n");
		fclose(f);
		return -1;
	}
	buffer2 = (unsigned short *)malloc(len);
	if(buffer2 == NULL)
	{
		printf("ERROR: Out of memory\n");
		fclose(f);
		free(buffer1);
		return -1;
	}
	if(fread(buffer1,len,1,f) != 1)
	{
		printf("ERROR: Unable to read file '%s'\n",fname);
		free(buffer1);
		free(buffer2);
		fclose(f);
	}
	fclose(f);

	if(ReadFlash(address,buffer2,len/sizeof(unsigned short)) < 0) 
	{
		printf("Read of flash failed\n");
		free(buffer1);
		free(buffer2);
		return -1;
	}

	if(memcmp(buffer1,buffer2,len) == 0)
		printf("Verified OK\n");
	else
	{
		int i;
		printf("Verify failed!!\n");
		for(i = 0; i < len; i++)
			if(buffer1[i] != buffer2[i])
			{
				printf("Match failed at %x\n",i);
				break;
			}
	}
		
	free(buffer1);
	free(buffer2);

	return len;
}


/****************************************************************************/
int CheckEmpty(void)
{
	unsigned short *buffer;
	FILE *f;
	int len = 16*1024*1024;

	buffer = (unsigned short *)malloc(len);
	if(buffer == NULL)
	{
		printf("ERROR: Out of memory\n");
		fclose(f);
		return -1;
	}
	if(ReadFlash(0,buffer,len/sizeof(unsigned short)) < 0) 
	{
		printf("Read of flash failed\n");
		free(buffer);
		return -1;
	}

	int i;
	for(i = 0; i < len/sizeof(unsigned short); i++)
	{
		if(buffer[i] != 0xffff)
		{
			printf("Not empty at %i!\n",i);
			break;
		}
	}
	printf("Empty!\n");	
	free(buffer);

	return len;
}


/****************************************************************************/
static unsigned int GetAddress(void)
{
	unsigned int a = 0; 
	int i = 0,c;
	printf("Enter address: ");
	c = getch();
	while(c != 13 && c != 10)
	{
		if(c == 27)
		{
			putchar('\n');
			return 0;
		}
		if(c == '\b' && i > 0)
		{
			a=a/16;
			printf("\b \b");
		}
		else if(c >= '0' && c <= '9')
		{
			a = a*16+c-'0';
			putchar(c);
		}
		else if(c >= 'A' && c <= 'Z')
		{
			a = a*16+c-'A'+10;
			putchar(c);
		}
		else if(c >= 'a' && c <= 'f')
		{
			a = a*16+c-'a'+10;
			putchar(c);
		}
		c = getch();
	}
	putchar('\n');
	return a;
}
/****************************************************************************/
static int GetFilename(char *buffer, int size)
{
	int i = 0,c;
	printf("Enter filename: ");
	c = getch();
	while(c != 13 && c != 10)
	{
		if(c == 27)
		{
			putchar('\n');
			return 0;
		}
		if(c == '\b' && i > 0)
		{
			i--;
			printf("\b \b");
		}
		else if(i < size-1 && (c >=32 || c < 127))
		{
			buffer[i++] = c;
			putchar(c);
		}
		c = getch();
	}
	buffer[i] = 0;
	// Default
	if(i == 0)
		strcpy(buffer,"test.bin");
	putchar('\n');
	return 1;
}
/****************************************************************************/
int main(int argc, char * argv[]) {
	int erc = 0;
	int id;
	int finish;
	int show;
	unsigned int address;
	char filename[128];
	/* initialize application
	*/
	strcpy(filename,"c:\\temp\\data");

	if (!DpcInit(&erc)) {
		printf("Unable to initialise\n");
		return 0;
	}

	id = DvmgGetDefaultDev(&erc);
	if (id == -1) {
		printf("No default device\n");
		goto error;
	}

	if(!DvmgGetDevName(id, device, &erc)) {
		printf("No device name\n");
		goto error;
	}

	finish = 0;
	show = 1;
	address = 0x000000;
	while(!finish)
	{
		int c;

		if(show)
		{
			printf("\n");
			printf("Menu            Address = %06x\n",address);
			printf("====            Filename = %s\n",filename);
			printf("A. Set address\n");
			printf("R. Read a block\n");
			printf("E. Erase a 128K page\n");
			printf("N. Nuke all pages\n");
			printf("E. Erase a 128K page\n");
			printf("U. Upload file\n");
			printf("V. Verify file\n");
			printf("C. Check empty\n");
			printf("\n");
			printf("Q. Quit\n");
			printf("\nEnter option:");
			show = 0;
		}

		c = _getch();
		putchar(c);
		putchar('\n');

		if(c >= 'a' && c <= 'z')
			c =  c - 'a' + 'A';

		switch(c)
		{
		case 'A':
			address = GetAddress();
			show = 1;
			break;
		case 'R':
			{
				unsigned short data[256];
				if(ReadFlash(address,data,sizeof(data)/sizeof(unsigned short)) < 0) 
					printf("Read failed\n");
				else
					dumpData(address,data,sizeof(data)/sizeof(unsigned short));
				show = 1;
			}
			break;
		case 'E':
			{
				char a;
				printf("\nThis will erase a 128KB page of flash (%06x-%06x).\nAre you sure? ", (address&~0xFFFF), (address&~0xFFFF)+0xFFFF);
				a = _getch();
				putchar(a);
				putchar('\n');

				if(a == 'Y' || a == 'y')
				{
					if(EraseFlash(address) < 0) 
						printf("Erase failed\n");
				}
				show = 1;
			}
			break;
		case 'N':
			{
				char a;
				printf("\nThis will erase all fLash. Are you sure? ");
				a = _getch();
				putchar(a);
				putchar('\n');

				if(a == 'Y' || a == 'y')
				{
					for(address = 0; address < 8*1024*1024; address+=64*1024)
					{

						if(EraseFlash(address) < 0) 
							printf("Erase failed\n");
					}
				}
				show = 1;
			}
			break;
		case 'F':
			GetFilename(filename,sizeof(filename));
			show = 1;
			break;
		case 'U':
			show = 1;
			UploadFile(filename, address);
			break;
		case 'C':
			show = 1;
			CheckEmpty();
			break;
		case 'V':
			show = 1;
			VerifyFile(filename, address);
			break;
		case 'Q':
			finish = 1;
			break;
		case 10:
		case 13:
			break;
		default:
			printf("Invalid option\n");
			break;
		}
	}
error:
	DpcTerm();
	return 0;
}



Personal tools