#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
namespace usb{
// 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 due to code bloat.
union 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
};
}//namespace
/****************************************
* 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!
Vorgefundene Kodierung: UTF-8 | 0
|