INTEL (Altera) USB Byte Blaster on STM32

Often, if a device has programmable logic, a processor / microcontroller is also present.





At some point, I got tired of wiring the JTAG connector on the boards, it takes up a lot of space on the board and, in fact, is only needed for development. In the final device, it is completely unnecessary.





Very often I use SignalTap II Logic Analyzer to check the correctness of the implementation of the Verilog code, or in general "to see how the signallers are running", the thing is convenient and intuitive, I think many will immediately recognize it from the image:





JTAG?





CPLD .





.





STM32F103RCT6 USB Byte Blaster. CPLD EPM3064.





, :





PC12->TDI





PC13->TMS





PC14->TCK





PC15->TDO





USB , :





USB Descriptor
/* USB Standard Device Descriptor */
const BYTE USB_DeviceDescriptor[] = {
  USB_DEVICE_DESC_SIZE,              /* bLength */
  USB_DEVICE_DESCRIPTOR_TYPE,        /* bDescriptorType */
  WBVAL(0x0110), /* 1.10 */          /* bcdUSB */
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_MAX_PACKET0,          // Max packet size for EP0, see usbcfg.h
  WBVAL(0x09FB),                     /* idVendor */
  WBVAL(0x6001),                     /* idProduct */
  WBVAL(0x0400), /* 1.00 */          /* bcdDevice */
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x03,                   // Device serial number string index
    0x01                    // Number of possible configurations	
};

/* USB Configuration Descriptor */
/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const BYTE USB_ConfigDescriptor[] = {
    /* Configuration Descriptor */
  USB_CONFIGUARTION_DESC_SIZE,       /* bLength */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
/* Configuration 1 */
  WBVAL(                            /* wTotalLength */
    (1*USB_CONFIGUARTION_DESC_SIZE) +
    (1*USB_INTERFACE_DESC_SIZE) +
    (2*USB_ENDPOINT_DESC_SIZE)
  ),
    1,                      // Number of interfaces in this cfg
    1,                      // Index value of this configuration
    0,                      // Configuration string index
  USB_CONFIG_SELF_POWERED, /*|*/       /* bmAttributes */
  USB_CONFIG_POWER_MA(80),          /* bMaxPower */

    /* Interface Descriptor */
  USB_INTERFACE_DESC_SIZE,           /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,     /* bDescriptorType */
/* Interface 0, Alternate Setting 0, MSC Class */
  0x00,                              /* bInterfaceNumber */
  0x00,                              /* bAlternateSetting */
  0x02,                              /* bNumEndpoints */
    0xFF,                   // Class code
    0xFF,                   // Subclass code
    0xFF,                   // Protocol code
    0,                      // Interface string index
    
    /* Endpoint Descriptor */
/* Bulk In Endpoint */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_IN(BLST_EP_IN & 0x0F),                /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(BLST_MAX_PACKET),                     /* wMaxPacketSize */
    10,                         //Interval
    
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_OUT(BLST_EP_OUT & 0x0F),               /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(BLST_MAX_PACKET),                     /* wMaxPacketSize */
    10                          //Interval	
/* Terminator */
  ,0                                  /* bLength */
};

//Language code string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[1];}sd000={
sizeof(sd000),USB_STRING_DESCRIPTOR_TYPE,{0x0409}};

//Manufacturer string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[6];}sd001={
sizeof(sd001),USB_STRING_DESCRIPTOR_TYPE,
{'A','l','t','e','r','a'}};

//Product string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[11];}sd002={
sizeof(sd002),USB_STRING_DESCRIPTOR_TYPE,
{'U','S','B','-','B','l','a','s','t','e','r'}};

//Serial string descriptor
ROM struct{BYTE bLength;BYTE bDscType;WORD string[8];}sd003={
sizeof(sd003),USB_STRING_DESCRIPTOR_TYPE,
{'0','0','0','0','0','0','0','0'}};

//Array of configuration descriptors
ROM BYTE *ROM USB_CD_Ptr[]=
{
    (ROM BYTE *)&USB_ConfigDescriptor
};
//Array of string descriptors
ROM BYTE *ROM USB_SD_Ptr[]=
{
    (ROM BYTE *)&sd000,
    (ROM BYTE *)&sd001,
    (ROM BYTE *)&sd002,
    (ROM BYTE *)&sd003
};

/* USB String Descriptor (optional) */
const BYTE *USB_StringDescriptor = (const BYTE *)USB_SD_Ptr;
      
      







"" Byte Blaster'a:





blaster.c
BYTE fifo_wp,fifo_rp;
BYTE InFIFO[256];

BYTE nCS = 0;

DWORD PacketPos = 0;
BYTE InPacket[64];
BYTE OutPacket[128];
BYTE ep1_ready = 1;

void EP2CallBack(void)
{
	ProcBlasterData();
}

void ProcBlasterData(void)
{
	int bufptr = 0;
	static BYTE jtag_byte = 0, read = 0, aser_byte = 0;
	DWORD recv_byte;
	BYTE acc0, acc1;
	
	recv_byte = USB_ReadEP(BLST_EP_OUT, OutPacket);

	bufptr = 0;
	
	if(!recv_byte) return;
	LED_RD_ON();
	
	do
	{
		if (jtag_byte)
		{
			if (!read)
			{
				do
				{

					acc0 = OutPacket[bufptr++];
					JTAG_Write(acc0);
					jtag_byte--;
					recv_byte--;
				} while (jtag_byte && recv_byte);
			}
			else
			{
				do
				{

					acc0 = OutPacket[bufptr++];
					acc1 = JTAG_RW(acc0);
					enqueue(acc1);
					jtag_byte--;
					recv_byte--;
				} while (jtag_byte&&recv_byte);
			}

		}
		else if (aser_byte)
		{
			if (!read)
			{

				do
				{

					acc0 = OutPacket[bufptr++];
					JTAG_Write(acc0);
					aser_byte--;
					recv_byte--;
				} while (aser_byte&&recv_byte);
			}
			else
			{
				do {
					acc0 = OutPacket[bufptr++];
					acc1 = ASer_RW(acc0);
					enqueue(acc1);
					aser_byte--;
					recv_byte--;
				} while (aser_byte&&recv_byte);
			}
		}
		else
		{
			do
			{
				acc0 = OutPacket[bufptr++];
				_bitcopy(bitmask(acc0, 6), read);
				if (bitmask(acc0, 7))
				{		//EnterSerialMode
					LTCK(0);		//bug fix
					
					if (nCS & 0x8) 
					{	//nCS=1:JTAG
						jtag_byte = acc0 & 0x3F;
					}
					else 
					{		//nCS=0:ActiveSerial
						aser_byte = acc0 & 0x3F;
					}
					/* Always JTAG Made */
					recv_byte--;
					break;
				}
				else
				{			//BitBangMode
					OUTP(acc0);
					if (read) {
						acc1 = 0;
						if (PADO) acc1 |= 0x02;
						if (PTDO) acc1 |= 0x01;
						enqueue(acc1);
					}
					recv_byte--;
				}
			} while (recv_byte);
		}
	} while (recv_byte);

	/* Disable RD LED */
	LED_RD_OFF();
	return;
}

void EP1CallBack(void)
{
	ep1_ready = 1;

	return;
}

void OUTP(BYTE b)
{
	unsigned int uiPortState = GPIOC->ODR;
	/* 	TCK - 0
			TMS - 1
			nCE - 2
			nCS - 3
	x - 5,6
			TDI - 4,7
	*/
	if(b & (1 << 3)) /* nCS */
		nCS = 0x08;
	else
		nCS = 0;
	
	if(b & (1 << 0)) /* TCK */
		uiPortState |= (1 << 14);
	else
		uiPortState &= ~(1 << 14);

	if(b & (1 << 1)) /* TMS */
		uiPortState |= (1 << 13);
	else
		uiPortState &= ~(1 << 13);

	if(b & (1 << 4)) /* TDI */
		uiPortState |= (1 << 12);
	else
		uiPortState &= ~(1 << 12);
	
	GPIOC->ODR = uiPortState;
	
//	Nop();
	
	return;
}

void JTAG_Write(BYTE a) 
{
	int i;
	
	for(i = 0;i < 8;i ++)
	{
		bitcopy(a & (0x01 << i),LTDI);
		tck();
	}
}

BYTE JTAG_RW(BYTE a)
{
	BYTE bRet=0;
	int i = 0;
	
	for(i = 0;i < 8;i++)
	{
		bitcopy(a & (0x01 << i),LTDI);
		if(PTDO) bRet |= (0x01 << i);
		tck();
	}
	
	return bRet;
}

BYTE ASer_RW(BYTE a) {
	BYTE bRet=0;
	int i = 0;
	
	for(i = 0;i < 8;i++)
	{
		bitcopy(a & (0x01 << 1),LTDI);
		if(PADO) bRet|= (0x01 << 1);
		tck();
	}		
	
	return bRet;
}

extern USB_EP_DATA EP0Data;
BYTE bBuffer[10];

void USB_EP0BlasterReq(USB_SETUP_PACKET *SetupPacket)
{
	BYTE bIndex;

	if (SetupPacket->bmRequestType.BM.Dir == 0)
	{	//0utput
		//Responce by sending zero-length packet
		//I don't know if this way is right, but working:)
		USB_WriteEP(0x80, NULL, 0);
		return;
	}

	if (SetupPacket->bRequest == 0x90)
	{
		bIndex = (SetupPacket->wIndex.WB.L << 1) & 0x7E;
		bBuffer[0] = eeprom_read(bIndex);
		bBuffer[1] = eeprom_read(bIndex + 1);
	}
	else
	{
		bBuffer[0] = 0x36;
		bBuffer[1] = 0x83;
	}

	EP0Data.pData = bBuffer;
	EP0Data.Count = 2;
	//		USB_WriteEP(0x80, bBuffer, 2);

	return;
}

      
      







. , main() .





:





main.c
  while (1) 
	{
		if(USB_Configuration)
		{
			if(ep1_ready)
			{
				acc0 = fifo_used();
				if (62 <= acc0) 
				{		//send full packet to host
					LED_WR_ON();
					ep1_ready = 0;
					dequeue(&InPacket[2], 62);
					USB_WriteEP(BLST_EP_IN, InPacket, 64);
					ChargeTimer_ms(10);
				}
				else if(acc0 || IsTimerArrived())
				{
					if(acc0)
						LED_WR_ON();
					else						
						LED_WR_OFF();
					ep1_ready = 0;
					if(acc0)
						dequeue(&InPacket[2], acc0);
					USB_WriteEP(BLST_EP_IN, InPacket, acc0 + 2);
					ChargeTimer_ms(10);
				}
			}
		}
  } // end while
      
      







, :





And we connect our device to USB.





And that certainly doesn't mean anything. Because the installation takes place only on the basis of the device descriptor, now let's check if this is really our "real" Byte Blaster.





We choose:





And launch the JTAG Chain Debugger:





Works!!! We can write CPLD directly on board our device.





By the way, if you connect this implementation to FPGA, recording in FPGA and SignalTap II will be available. That's all I wanted to say.









Thanks for attention! Good luck in business and good mood!








All Articles