INTEL (Altera) USB Byte Blaster на STM32

от автора

Зачастую если в устройстве есть программируемая логика, присутствует и процессор/микроконтроллер.

В какой-то момент мне надоело разводить на платах разъем JTAG, он занимает много места на плате и по сути нужен только для разработки. В конечном устройстве он вообще без надобности.

Очень часто для проверки правильности реализации Verilog кода или вообще «посмотреть как сигнальчики бегают» я использую SignalTap II Logic Analizer, штука удобная и наглядная, я думаю многие сразу узнают по изображению:

Но как же отлаживать само устройство и в частности программируемую логику без 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

Собираем всё вместе и компилируем и прошиваем, используя вот такой игровой набор:

И подключаем наше устройство к USB.

И это же конечно ничего не значит. Потому что установка происходит только на основании дескриптора устройства, теперь проверим действительно ли это у нас «настоящий» Byte Blaster.

Выбираем:

И запускаем JTAG Chain Debugger:

Работает!!! Можем писать CPLD прям на борту нашего устройства.

К слову сказать если подключить эту реализацию к FPGA, будет доступна запись в FPGA и SignalTap II. У меня всё.

Спасибо за внимание! Успехов в делах и отличного настроения!

ссылка на оригинал статьи https://habr.com/ru/post/534358/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *