Source file: /~heha/hsn/bl/bl.zip/usb.h

#pragma once
#ifndef __cplusplus
# error Must compile in C++ mode
#endif

#define elemof(x) (sizeof(x)/sizeof(*(x)))
typedef uint8_t byte;	// Handy Arduino type

// This setup packet definition splits all 16-bit quantities in handy bytes
// and concatenates bmRequestType + bRequest to a handy 16-bit wRequest
// to ease the switch statement at onSetup().
// However, wRequest is not recommended for 8-bit Arduino because of code bloat.
union USB_SetupPacket{
 struct{uint16_t wRequest,wValue,wIndex,wLength;};
 struct{byte bmRequestType,bRequest,wValueL,wValueH,wIndexL,wIndexH,wLengthL,wLengthH;};
 byte all[8];
 operator byte*() {return all;}	// access entire structure as byte array
};

/****************************************
 *	General registers		*
 ****************************************/
// As USB registers are all 16-bit with 16-bit gaps in between,
// all registers are defined as 32-bit. Software ignores high halfword.
// On ARM architecture, this will not lead to larger code.
// However, USB registers are not defined inside STM-CMSIS, so it would be done here.
// The misleading _TypeDef suffix is made by STM-CMSIS so I copied this, sorry.

struct USB_TypeDef{
 volatile uint32_t EPR[16];	// endpoint registers (8 used, 8 reserved)
 volatile uint32_t CNTR,ISTR,FNR,DADDR,BTABLE;	// offset 0x40: General registers
};
#define USB (*(USB_TypeDef*)0x40005C00)	// USB_IP Peripheral Registers base address
// According to modern C++ programming, pointers are avoided when replaceable by references.
// Therefore, in contrast to CMSIS _TypeDef structures, access USB.member, not USB->member.

// Important note: The USB registers MUST be accessed in 16-bit
// or 32-bit quantities with addresses divisable by four!
// Byte access won't work at all! stm32f103xx-rm0008.pdf Page 637/1136:
// “The peripheral registers can be accessed by half-words (16-bit) or words (32-bit).”

/****************************************
 *	ISTR interrupt events		*
 ****************************************/
// I removed all USB constant definitions as these are constants by USB.org
// and IMHO need no another symbolics.
// Here are only the useful register bit masks.
enum{
 ISTR_CTR	= 0x8000,	// [r] Correct TRansfer
 ISTR_DOVR	= 0x4000,	// [rw0] DMA OVeR/underrun
 ISTR_ERR	= 0x2000,	// [rw0] ERRor
 ISTR_WKUP	= 0x1000,	// [rw0] WaKe UP
 ISTR_SUSP	= 0x0800,	// [rw0] SUSPend
 ISTR_RESET	= 0x0400,	// [rw0] RESET
 ISTR_SOF	= 0x0200,	// [rw0] Start Of Frame
 ISTR_ESOF	= 0x0100,	// [rw0] Expected Start Of Frame
 ISTR_DIR	= 0x0010,	// [r] DIRection of transaction
 ISTR_EP_ID	= 0x000F,	// [r] EndPoint IDentifier
};

/****************************************
 *	CNTR control register bits	*
 ****************************************/
enum{
 CNTR_CTRM	= 0x8000,	// [rw] Correct TRansfer Mask
 CNTR_DOVRM	= 0x4000,	// [rw] DMA OVeR/underrun Mask
 CNTR_ERRM	= 0x2000,	// [rw] ERRor Mask
 CNTR_WKUPM	= 0x1000,	// [rw] WaKe UP Mask
 CNTR_SUSPM	= 0x0800,	// [rw] SUSPend Mask
 CNTR_RESETM	= 0x0400,	// [rw] RESET Mask  
 CNTR_SOFM	= 0x0200,	// [rw] Start Of Frame Mask
 CNTR_ESOFM	= 0x0100,	// [rw] Expected Start Of Frame Mask
 CNTR_RESUME	= 0x0010,	// [rw] RESUME request
 CNTR_FSUSP	= 0x0008,	// [rw] Force SUSPend
 CNTR_LPMODE	= 0x0004,	// [rw] Low-power MODE
 CNTR_PDWN	= 0x0002,	// [rw] Power DoWN
 CNTR_FRES	= 0x0001,	// [rw] Force USB RESet
};

/****************************************
 *	FNR Frame Number Register bits	*
 ****************************************/
enum{
 FNR_RXDP	= 0x8000,	// [r] status of D+ data line
 FNR_RXDM	= 0x4000,	// [r] status of D- data line
 FNR_LCK	= 0x2000,	// [r] LoCKed
 FNR_LSOF	= 0x1800,	// [r] Lost SOF
 FNR_FN		= 0x07FF,	// [r] Frame Number
};
/****************************************
 *	DADDR Device ADDRess bits	*
 ****************************************/
enum{
 DADDR_EF	= 0x80,		// [rw] Enable Function
};
/****************************************
 *	Endpoint register		*
 ****************************************/
enum{
 EP_CTR_RX	= 0x8000,	// [rw0] EndPoint Correct TRansfer RX
 EP_DTOG_RX	= 0x4000,	// [t] EndPoint Data TOGGLE RX
 EPRX_STAT	= 0x3000,	// [t] EndPoint RX STATus bit field
 EP_RX_DIS	= 0x0000,	//	EndPoint RX DISabled
 EP_RX_STALL	= 0x1000,	//	EndPoint RX STALLed
 EP_RX_NAK	= 0x2000,	//	EndPoint RX NAKed
 EP_RX_VALID	= 0x3000,	//	EndPoint RX VALID
 EP_SETUP	= 0x0800,	// [r] EndPoint SETUP
 EP_T_FIELD	= 0x0600,	// [rw] EndPoint TYPE
 EP_BULK	= 0x0000,	//	EndPoint BULK
 EP_CONTROL	= 0x0200,	//	EndPoint CONTROL
 EP_ISOCHRONOUS	= 0x0400,	//	EndPoint ISOCHRONOUS
 EP_INTERRUPT	= 0x0600,	//	EndPoint INTERRUPT
 EP_KIND	= 0x0100,	// [rw] EndPoint KIND
				//	BULK: Double-buffer using data-toggle bit
				//	CONTROL: Expect Status Out (STALL on OUT with more than 0 byte data)
				//	ISOCHRONOUS, INTERRUPT: Not used
 EP_CTR_TX	= 0x0080,	// [rw0] EndPoint Correct TRansfer TX
 EP_DTOG_TX	= 0x0040,	// [t] EndPoint Data TOGGLE TX
 EPTX_STAT	= 0x0030,	// [t] EndPoint TX STATus bit field
 EP_TX_DIS	= 0x0000,	//	EndPoint TX DISabled
 EP_TX_STALL	= 0x0010,	//	EndPoint TX STALLed
 EP_TX_NAK	= 0x0020,	//	EndPoint TX NAKed
 EP_TX_VALID	= 0x0030,	//	EndPoint TX VALID
 EPADDR_FIELD	= 0x000F,	// [rw] EndPoint ADDRess FIELD
};

// MOD_REG is still needed for convenient USB.EPR[n] toggle-bit handling
#define MOD_REG(REG, NAND, XOR)	REG = (REG) & ~(NAND) ^ (XOR)
#define SET_RX_STATUS(bEpNum,wStatus)	MOD_REG(USB.EPR[bEpNum], 0xC070, wStatus)
#define SET_TX_STATUS(bEpNum,wStatus)	MOD_REG(USB.EPR[bEpNum], 0x70C0, wStatus)

/****************************************
 *	Buffer Table			*
 ****************************************/
// BTABLE should be at address 0 of PMAAddr (which is reset default).
// So BTABLE has a fixed address, and is indexed by endpoint number.
// All BTABLE locations are 16-bit with 16-bit gaps in between,
// so all registers are defined as 32-bit; software ignores high halfword.
union BTABLE_TypeDef{
 struct{volatile uint32_t ADDR_TX,COUNT_TX,ADDR_RX,COUNT_RX;};	// single-buffer
 struct{volatile uint32_t ADDR,COUNT;}TX[2],RX[2];		// double-buffer, either TX or RX
 void setRxBufSize(unsigned sz) {COUNT_RX=sz>=32?0x8000|sz-32<<5:sz<<9;}
};
#define PMAAddr  (0x40006000L)  // USB_IP Packet Memory Area base address
#define BTABLE ((BTABLE_TypeDef*)PMAAddr)
// Important note: The Packet Memory Area (PMA) MUST be accessed in 16-bit
// or 32-bit quantities with addresses divisable by four!
Detected encoding: UTF-80