diff options
| -rw-r--r-- | usb/SConscript | 9 | ||||
| -rw-r--r-- | usb/f1_usb.h | 174 | ||||
| -rw-r--r-- | usb/f1_usb_def.h | 35 | ||||
| -rw-r--r-- | usb/l0_usb.h | 174 | ||||
| -rw-r--r-- | usb/l0_usb_def.h | 37 | ||||
| -rw-r--r-- | usb/stm32_usb.h | 212 | ||||
| -rw-r--r-- | usb/stm32_usb_def.h | 71 | 
7 files changed, 292 insertions, 420 deletions
| diff --git a/usb/SConscript b/usb/SConscript index 81d84d4..d000a82 100644 --- a/usb/SConscript +++ b/usb/SConscript @@ -14,6 +14,15 @@ if 'dwc_otg' in periph:              'args': [data['offset']],          }) +if 'stm32_usb' in periph: +    headers.append('stm32_usb.h') +    for name, data in periph['stm32_usb'].items(): +        instances.append({ +            'type': 'STM32_USB_t<STM32_USB_reg_%s_t>' % data['type'], +            'name': name, +            'args': [data['offset'], data['buf_offset']], +        }) +  env.Jinja2('usb.h', '../templates/periph_instances.h.j2', headers = headers, instances = instances)  Return() diff --git a/usb/f1_usb.h b/usb/f1_usb.h deleted file mode 100644 index 8510bb9..0000000 --- a/usb/f1_usb.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef F1_USB_H -#define F1_USB_H - -#include "generic.h" -#include "f1_usb_def.h" - -class USB_f1 : public USB_generic { -	private: -		F1_USB_t& usb; -		 -		uint32_t setupbuf[16]; -		 -		uint32_t buf_end; -		 -		uint8_t pending_addr; -	 -	protected: -		virtual void hw_set_address(uint8_t addr) { -			usb_rblog.log("SetAddress: %d", addr); -			 -			pending_addr = addr; -		} -		 -		virtual void hw_conf_ep(uint8_t ep, EPType type, uint32_t size) { -			usb_rblog.log("Configuring EP%02x: size=%d", ep, size); -			 -			uint8_t in = ep & 0x80; -			ep &= 0x7f; -			 -			uint32_t old_epr = usb.reg.EPR[ep]; -			//uint32_t new_epr = 0x3220; -			uint32_t new_epr = 0x8080 | ((type == EPType::Bulk ? 0 : type == EPType::Control ? 1 : type == EPType::Isochronous ? 2 : 3) << 9) | ep; -			 -			if(in || ep == 0) { -				usb.bufd[ep].ADDR_TX = buf_end; -				buf_end += size; -				 -				new_epr |= (old_epr & 0x0070) ^ 0x0020; -			} -			 -			if(!in) { -				usb.bufd[ep].ADDR_RX = buf_end; -				buf_end += size; -				usb.bufd[ep].COUNT_RX = 0x8000 | (1 << 10); -				 -				new_epr |= (old_epr & 0x7000) ^ 0x3000; -			} -			 -			usb.reg.EPR[ep] = new_epr; -			 -			usb_rblog.log("EPR: old=%04x, new=%04x", old_epr, usb.reg.EPR[ep]); -		} -		 -		virtual void hw_set_stall(uint8_t ep) { -			usb_rblog.log("Setting stall on EP %d", ep); -			 -			usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x878f) | 0x2030; -			 -			//otg.dev_iep_reg[ep].DIEPCTL |= (1 << 21); -		} -	 -	public: -		USB_f1(F1_USB_t& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {} -		 -		void init() { -			usb.reg.CNTR = 3; -			Time::sleep(10); -			usb.reg.CNTR = 1; -			Time::sleep(10); -			// Exit power down mode. -			usb.reg.CNTR = 0; -		} -		 -		void process() { -			uint32_t istr = usb.reg.ISTR; -			 -			if(istr & (1 << 10)) { -				usb_rblog.log("USB Reset"); -				 -				buf_end = 0x40; -				 -				usb.reg.DADDR = 0x80; -				 -				handle_reset(); -				 -				usb.reg.ISTR = ~(1 << 10); -				 -				return; -			} -			 -			if(istr & (1 << 15)) { -				usb_rblog.log("USB Transfer: %02x", istr & 0x1f); -				 -				uint32_t ep = istr & 0xf; -				uint32_t dir = istr & 0x10; -				 -				usb_rblog.log("EPR%d: %04x", ep, usb.reg.EPR[ep]); -				 -				if(dir) { -					// RX. -					 -					usb_rblog.log("RXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_RX, usb.bufd[ep].COUNT_RX); -					 -					uint32_t len = usb.bufd[ep].COUNT_RX & 0x03ff; -					 -					if(usb.reg.EPR[ep] & (1 << 11)) { -						usb_rblog.log("SETUP packet received"); -						 -						read(0, setupbuf, 8); -						 -						handle_setup(setupbuf); -						 -					} else { -						usb_rblog.log("OUT packet received"); -						 -						handle_out(ep, len); -					} -					 -					//usb.reg.EPR[ep] = 0x9280; -					//usb.reg.EPR[ep] &= 0x078f; -					 -					usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x078f) | 0x1000; -				} else { -					// TX. -					 -					usb_rblog.log("TXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_TX, usb.bufd[ep].COUNT_TX); -					 -					if(pending_addr) { -						usb_rblog.log("Actually changing addr to: %d", pending_addr); -						 -						usb.reg.DADDR = 0x80 | pending_addr; -						 -						pending_addr = 0; -					} -					 -					usb.reg.EPR[ep] &= 0x870f; -				} -				usb_rblog.log("Leaving: EPR%d: %04x", ep, usb.reg.EPR[ep]); -			} -		} -		 -		virtual bool ep_ready(uint32_t ep) { -			return (usb.reg.EPR[ep] & 0x30) == 0x20; -		} -		 -		virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { -			usb_rblog.log("Writing, ep=%d, len=%d", ep, len); -			 -			uint16_t* p = (uint16_t*)bufp; -			uint32_t base = usb.bufd[ep].ADDR_TX >> 1; -			 -			for(uint32_t i = 0; i < len; i += 2) { -				usb.buf[base + (i >> 1)] = *p++; -			} -			 -			usb.bufd[ep].COUNT_TX = len; -			usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x870f) | 0x0010; -		} -		 -		virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { -			usb_rblog.log("Reading, ep=%d, len=%d", ep, len); -			 -			uint16_t* p = (uint16_t*)bufp; -			uint32_t base = usb.bufd[ep].ADDR_RX >> 1; -			 -			for(uint32_t i = 0; i < len; i += 2) { -				*p++ = uint16_t(usb.buf[base + (i >> 1)]); -			} -			 -			return len; -		} -}; - -#endif diff --git a/usb/f1_usb_def.h b/usb/f1_usb_def.h deleted file mode 100644 index 0e42f6f..0000000 --- a/usb/f1_usb_def.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef F1_USB_DEF_H -#define F1_USB_DEF_H - -#include <stdint.h> - -class F1_USB_t { -	private: -		struct F1_USB_reg_t { -			volatile uint32_t EPR[16]; -			volatile uint32_t CNTR; -			volatile uint32_t ISTR; -			volatile uint32_t FNR; -			volatile uint32_t DADDR; -			volatile uint32_t BTABLE; -		}; -		 -		struct F1_USB_bufd_t { -			volatile uint32_t ADDR_TX; -			volatile uint32_t COUNT_TX; -			volatile uint32_t ADDR_RX; -			volatile uint32_t COUNT_RX; -		}; -		 -	public: -		F1_USB_reg_t& reg; -		F1_USB_bufd_t* bufd; -		volatile uint32_t* buf; -		 -		F1_USB_t(uint32_t reg_addr, uint32_t buf_addr) : -			reg(*(F1_USB_reg_t*)reg_addr), -			bufd((F1_USB_bufd_t*)buf_addr), -			buf((volatile uint32_t*)buf_addr) {} -}; - -#endif diff --git a/usb/l0_usb.h b/usb/l0_usb.h deleted file mode 100644 index 243f19b..0000000 --- a/usb/l0_usb.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef L0_USB_H -#define L0_USB_H - -#include "generic.h" -#include "l0_usb_def.h" - -class USB_l0 : public USB_generic { -	private: -		L0_USB_t& usb; -		 -		uint32_t setupbuf[16]; -		 -		uint32_t buf_end; -		 -		uint8_t pending_addr; -	 -	protected: -		virtual void hw_set_address(uint8_t addr) { -			usb_rblog.log("SetAddress: %d", addr); -			 -			pending_addr = addr; -		} -		 -		virtual void hw_conf_ep(uint8_t ep, EPType type, uint32_t size) { -			usb_rblog.log("Configuring EP%02x: size=%d", ep, size); -			 -			uint8_t in = ep & 0x80; -			ep &= 0x7f; -			 -			uint32_t old_epr = usb.reg.EPR[ep]; -			//uint32_t new_epr = 0x3220; -			uint32_t new_epr = 0x8080 | ((type == EPType::Bulk ? 0 : type == EPType::Control ? 1 : type == EPType::Isochronous ? 2 : 3) << 9) | ep; -			 -			if(in || ep == 0) { -				usb.bufd[ep].ADDR_TX = buf_end; -				buf_end += size; -				 -				new_epr |= (old_epr & 0x0070) ^ 0x0020; -			} -			 -			if(!in) { -				usb.bufd[ep].ADDR_RX = buf_end; -				buf_end += size; -				usb.bufd[ep].COUNT_RX = 0x8000 | (1 << 10); -				 -				new_epr |= (old_epr & 0x7000) ^ 0x3000; -			} -			 -			usb.reg.EPR[ep] = new_epr; -			 -			usb_rblog.log("EPR: old=%04x, new=%04x", old_epr, usb.reg.EPR[ep]); -		} -		 -		virtual void hw_set_stall(uint8_t ep) { -			usb_rblog.log("Setting stall on EP %d", ep); -			 -			usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x878f) | 0x2030; -			 -			//otg.dev_iep_reg[ep].DIEPCTL |= (1 << 21); -		} -	 -	public: -		USB_l0(L0_USB_t& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {} -		 -		void init() { -			usb.reg.CNTR = 3; -			Time::sleep(10); -			usb.reg.CNTR = 1; -			Time::sleep(10); -			// Exit power down mode. -			usb.reg.CNTR = 0; -		} -		 -		void process() { -			uint32_t istr = usb.reg.ISTR; -			 -			if(istr & (1 << 10)) { -				usb_rblog.log("USB Reset"); -				 -				buf_end = 0x40; -				 -				usb.reg.DADDR = 0x80; -				 -				handle_reset(); -				 -				usb.reg.ISTR = ~(1 << 10); -				 -				return; -			} -			 -			if(istr & (1 << 15)) { -				usb_rblog.log("USB Transfer: %02x", istr & 0x1f); -				 -				uint32_t ep = istr & 0xf; -				uint32_t dir = istr & 0x10; -				 -				usb_rblog.log("EPR%d: %04x", ep, usb.reg.EPR[ep]); -				 -				if(dir) { -					// RX. -					 -					usb_rblog.log("RXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_RX, usb.bufd[ep].COUNT_RX); -					 -					uint32_t len = usb.bufd[ep].COUNT_RX & 0x03ff; -					 -					if(usb.reg.EPR[ep] & (1 << 11)) { -						usb_rblog.log("SETUP packet received"); -						 -						read(0, setupbuf, 8); -						 -						handle_setup(setupbuf); -						 -					} else { -						usb_rblog.log("OUT packet received"); -						 -						handle_out(ep, len); -					} -					 -					//usb.reg.EPR[ep] = 0x9280; -					//usb.reg.EPR[ep] &= 0x078f; -					 -					usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x078f) | 0x1000; -				} else { -					// TX. -					 -					usb_rblog.log("TXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_TX, usb.bufd[ep].COUNT_TX); -					 -					if(pending_addr) { -						usb_rblog.log("Actually changing addr to: %d", pending_addr); -						 -						usb.reg.DADDR = 0x80 | pending_addr; -						 -						pending_addr = 0; -					} -					 -					usb.reg.EPR[ep] &= 0x870f; -				} -				usb_rblog.log("Leaving: EPR%d: %04x", ep, usb.reg.EPR[ep]); -			} -		} -		 -		virtual bool ep_ready(uint32_t ep) { -			return (usb.reg.EPR[ep] & 0x30) == 0x20; -		} -		 -		virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { -			usb_rblog.log("Writing, ep=%d, len=%d", ep, len); -			 -			uint16_t* p = (uint16_t*)bufp; -			uint32_t base = usb.bufd[ep].ADDR_TX >> 1; -			 -			for(uint32_t i = 0; i < len; i += 2) { -				usb.buf[base + (i >> 1)] = *p++; -			} -			 -			usb.bufd[ep].COUNT_TX = len; -			usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x870f) | 0x0010; -		} -		 -		virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { -			usb_rblog.log("Reading, ep=%d, len=%d", ep, len); -			 -			uint16_t* p = (uint16_t*)bufp; -			uint32_t base = usb.bufd[ep].ADDR_RX >> 1; -			 -			for(uint32_t i = 0; i < len; i += 2) { -				*p++ = uint16_t(usb.buf[base + (i >> 1)]); -			} -			 -			return len; -		} -}; - -#endif diff --git a/usb/l0_usb_def.h b/usb/l0_usb_def.h deleted file mode 100644 index b9d8d10..0000000 --- a/usb/l0_usb_def.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef L0_USB_DEF_H -#define L0_USB_DEF_H - -#include <stdint.h> - -class L0_USB_t { -	private: -		struct L0_USB_reg_t { -			volatile uint32_t EPR[16]; -			volatile uint32_t CNTR; -			volatile uint32_t ISTR; -			volatile uint32_t FNR; -			volatile uint32_t DADDR; -			volatile uint32_t BTABLE; -			volatile uint32_t LPMCSR; -			volatile uint32_t BCDR; -		}; -		 -		struct L0_USB_bufd_t { -			volatile uint16_t ADDR_TX; -			volatile uint16_t COUNT_TX; -			volatile uint16_t ADDR_RX; -			volatile uint16_t COUNT_RX; -		}; -		 -	public: -		L0_USB_reg_t& reg; -		L0_USB_bufd_t* bufd; -		volatile uint16_t* buf; -		 -		L0_USB_t(uint32_t reg_addr, uint32_t buf_addr) : -			reg(*(L0_USB_reg_t*)reg_addr), -			bufd((L0_USB_bufd_t*)buf_addr), -			buf((volatile uint16_t*)buf_addr) {} -}; - -#endif diff --git a/usb/stm32_usb.h b/usb/stm32_usb.h new file mode 100644 index 0000000..7be6a7c --- /dev/null +++ b/usb/stm32_usb.h @@ -0,0 +1,212 @@ +#pragma once + +#include "generic.h" +#include "stm32_usb_def.h" + +#include <type_traits> + +template <typename T> +class STM32_USB_drv : public USB_generic { +	private: +		const STM32_USB_t<T>& usb; +		 +		uint32_t setupbuf[16]; +		 +		uint32_t buf_end; +		 +		uint8_t pending_addr; +	 +	protected: +		virtual void hw_set_address(uint8_t addr) { +			usb_rblog.log("SetAddress: %d", addr); +			 +			pending_addr = addr; +		} +		 +		virtual void hw_conf_ep(uint8_t ep, EPType type, uint32_t size) { +			usb_rblog.log("Configuring EP%02x: size=%d", ep, size); +			 +			uint8_t in = ep & 0x80; +			ep &= 0x7f; +			 +			uint32_t old_epr = usb->EPR[ep]; +			//uint32_t new_epr = 0x3220; +			uint32_t new_epr = 0x8080 | ((type == EPType::Bulk ? 0 : type == EPType::Control ? 1 : type == EPType::Isochronous ? 2 : 3) << 9) | ep; +			 +			if(in || ep == 0) { +				if constexpr (std::is_same_v<T, STM32_USB_reg_v3_t>) { +					usb.bufd[ep].TXRXBD = buf_end; +				} else { +					usb.bufd[ep].ADDR_TX = buf_end; +				} +				buf_end += size; +				 +				new_epr |= (old_epr & 0x0070) ^ 0x0020; +			} +			 +			if(!in) { +				if constexpr (std::is_same_v<T, STM32_USB_reg_v3_t>) { +					usb.bufd[ep].RXTXBD = (1 << 31) | (1 << 26) | buf_end; +				} else { +					usb.bufd[ep].ADDR_RX = buf_end; +					usb.bufd[ep].COUNT_RX = (1 << 15) | (1 << 10); +				} +				buf_end += size; +				 +				new_epr |= (old_epr & 0x7000) ^ 0x3000; +			} +			 +			usb->EPR[ep] = new_epr; +			 +			usb_rblog.log("EPR: old=%04x, new=%04x", old_epr, usb->EPR[ep]); +		} +		 +		virtual void hw_set_stall(uint8_t ep) { +			usb_rblog.log("Setting stall on EP %d", ep); +			 +			usb->EPR[ep] = (usb->EPR[ep] & 0x878f) | 0x2030; +			 +			//otg.dev_iep_reg[ep].DIEPCTL |= (1 << 21); +		} +	 +	public: +		STM32_USB_drv(const STM32_USB_t<T>& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {} +		 +		void init() { +			usb->CNTR = 3; +			//Time::sleep(10); +			usb->CNTR = 1; +			//Time::sleep(10); +			// Exit power down mode. +			usb->CNTR = 0; +		} +		 +		void process() { +			uint32_t istr = usb->ISTR; +			 +			if(istr & (1 << 10)) { +				usb_rblog.log("USB Reset"); +				 +				buf_end = 0x40; +				 +				usb->DADDR = 0x80; +				 +				handle_reset(); +				 +				usb->ISTR = ~(1 << 10); +				 +				return; +			} +			 +			if(istr & (1 << 15)) { +				usb_rblog.log("USB Transfer: %02x", istr & 0x1f); +				 +				uint32_t ep = istr & 0xf; +				uint32_t dir = istr & 0x10; +				 +				usb_rblog.log("EPR%d: %04x", ep, usb->EPR[ep]); +				 +				if(dir) { +					// RX. +					 +					uint32_t len; +					if constexpr (std::is_same_v<T, STM32_USB_reg_v3_t>) { +						usb_rblog.log("RXBUF: RXTXBD: %08x", usb.bufd[ep].RXTXBD); +						len = (usb.bufd[ep].RXTXBD >> 16) & 0x03ff; +					} else { +						usb_rblog.log("RXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_RX, usb.bufd[ep].COUNT_RX); +						len = usb.bufd[ep].COUNT_RX & 0x03ff; +					} + +					if(usb->EPR[ep] & (1 << 11)) { +						usb_rblog.log("SETUP packet received"); +						 +						read(0, setupbuf, 8); +						 +						handle_setup(setupbuf); +						 +					} else { +						usb_rblog.log("OUT packet received"); +						 +						handle_out(ep, len); +					} +					 +					//usb->EPR[ep] = 0x9280; +					//usb->EPR[ep] &= 0x078f; +					 +					usb->EPR[ep] = (usb->EPR[ep] & 0x078f) | 0x1000; +				} else { +					// TX. +					 +					if constexpr (std::is_same_v<T, STM32_USB_reg_v3_t>) { +						usb_rblog.log("TXBUF: TXRXBD: %08x", usb.bufd[ep].TXRXBD); +					} else { +						usb_rblog.log("TXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_TX, usb.bufd[ep].COUNT_TX); +					} +					 +					if(pending_addr) { +						usb_rblog.log("Actually changing addr to: %d", pending_addr); +						 +						usb->DADDR = 0x80 | pending_addr; +						 +						pending_addr = 0; +					} +					 +					usb->EPR[ep] &= 0x870f; +				} +				usb_rblog.log("Leaving: EPR%d: %04x", ep, usb->EPR[ep]); +			} +		} +		 +		virtual bool ep_ready(uint32_t ep) { +			return (usb->EPR[ep] & 0x30) == 0x20; +		} +		 +		virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { +			usb_rblog.log("Writing, ep=%d, len=%d", ep, len); +			 +			if constexpr (std::is_same_v<T, STM32_USB_reg_v3_t>) { +				uint32_t base = (usb.bufd[ep].TXRXBD & 0xffff) >> 2; +				 +				for(uint32_t i = 0; i < len; i += 4) { +					usb.buf[base + (i >> 2)] = *bufp++; +				} +				 +				usb.bufd[ep].TXRXBD = (len << 16) | (usb.bufd[ep].TXRXBD & 0xffff); + +			} else { +				uint16_t* p = (uint16_t*)bufp; +				uint32_t base = usb.bufd[ep].ADDR_TX >> 1; +				 +				for(uint32_t i = 0; i < len; i += 2) { +					usb.buf[base + (i >> 1)] = *p++; +				} +				 +				usb.bufd[ep].COUNT_TX = len; +			} + +			usb->EPR[ep] = (usb->EPR[ep] & 0x870f) | 0x0010; +		} +		 +		virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { +			usb_rblog.log("Reading, ep=%d, len=%d", ep, len); +			 +			if constexpr (std::is_same_v<T, STM32_USB_reg_v3_t>) { +				uint32_t base = (usb.bufd[ep].RXTXBD & 0xffff) >> 2; +				 +				for(uint32_t i = 0; i < len; i += 4) { +					*bufp++ = usb.buf[base + (i >> 2)]; +				} + +			} else { +				uint16_t* p = (uint16_t*)bufp; +				uint32_t base = usb.bufd[ep].ADDR_RX >> 1; +				 +				for(uint32_t i = 0; i < len; i += 2) { +					*p++ = uint16_t(usb.buf[base + (i >> 1)]); +				} +			} +			 +			return len; +		} +}; diff --git a/usb/stm32_usb_def.h b/usb/stm32_usb_def.h new file mode 100644 index 0000000..5fdd2ff --- /dev/null +++ b/usb/stm32_usb_def.h @@ -0,0 +1,71 @@ +#pragma once + +#include <mmio/mmio.h> + +struct STM32_USB_reg_v1_t { +    volatile uint32_t EPR[16]; +    volatile uint32_t CNTR; +    volatile uint32_t ISTR; +    volatile uint32_t FNR; +    volatile uint32_t DADDR; +    volatile uint32_t BTABLE; + +    struct bufd_t { +        volatile uint32_t ADDR_TX; +        volatile uint32_t COUNT_TX; +        volatile uint32_t ADDR_RX; +        volatile uint32_t COUNT_RX; +    }; + +    using buf_t = volatile uint32_t; +}; + +struct STM32_USB_reg_v2_t { +    volatile uint32_t EPR[16]; +    volatile uint32_t CNTR; +    volatile uint32_t ISTR; +    volatile uint32_t FNR; +    volatile uint32_t DADDR; +    volatile uint32_t BTABLE; +    volatile uint32_t LPMCSR; +    volatile uint32_t BCDR; + +    struct bufd_t { +        volatile uint16_t ADDR_TX; +        volatile uint16_t COUNT_TX; +        volatile uint16_t ADDR_RX; +        volatile uint16_t COUNT_RX; +    }; + +    using buf_t = volatile uint16_t; +}; + +struct STM32_USB_reg_v3_t { +    volatile uint32_t EPR[16]; +    volatile uint32_t CNTR; +    volatile uint32_t ISTR; +    volatile uint32_t FNR; +    volatile uint32_t DADDR; +    uint32_t _reserved; +    volatile uint32_t LPMCSR; +    volatile uint32_t BCDR; + +    struct bufd_t { +        volatile uint32_t TXRXBD; +        volatile uint32_t RXTXBD; +    }; + +    using buf_t = volatile uint32_t; +}; + +template <typename T> +class STM32_USB_t : public mmio_ptr<T> { +	public: +		mmio_ptr<typename T::bufd_t> bufd; +		mmio_ptr<typename T::buf_t> buf; +		 +		constexpr STM32_USB_t(uint32_t reg_addr, uint32_t buf_addr) : +			mmio_ptr<T>(reg_addr), +			bufd(buf_addr), +            buf(buf_addr) {} +}; | 
