Added support for STM32 OTH_HS peripheral (not tested yet).

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4578 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
gdisirio 2012-08-18 13:17:03 +00:00
parent ebc792e58d
commit f50d9fb048
7 changed files with 455 additions and 236 deletions

View File

@ -30,15 +30,26 @@
#define _STM32_OTG_H_ #define _STM32_OTG_H_
/** /**
* @brief Number of the implemented endpoints. * @brief Number of the implemented endpoints in OTG_FS.
* @details This value does not include the endpoint 0 that is always present. * @details This value does not include the endpoint 0 that is always present.
*/ */
#define STM32_OTG_ENDOPOINTS_NUMBER 3 #define STM32_OTG1_ENDOPOINTS_NUMBER 3
/** /**
* @brief FIFO memory size in words. * @brief Number of the implemented endpoints in OTG_HS.
* @details This value does not include the endpoint 0 that is always present.
*/ */
#define STM32_OTG_FIFO_MEM_SIZE 384 #define STM32_OTG2_ENDOPOINTS_NUMBER 5
/**
* @brief OTG_FS FIFO memory size in words.
*/
#define STM32_OTG1_FIFO_MEM_SIZE 384
/**
* @brief OTG_HS FIFO memory size in words.
*/
#define STM32_OTG2_FIFO_MEM_SIZE 1024
/** /**
* @brief Host channel registers group. * @brief Host channel registers group.
@ -881,24 +892,24 @@ typedef struct {
/** @} */ /** @} */
/** /**
* @brief OTG registers block memory address. * @brief OTG_FS registers block memory address.
*/ */
#define OTG_FS_ADDR 0x50000000 #define OTG_FS_ADDR 0x50000000
/**
* @brief OTG_HS registers block memory address.
*/
#define OTG_HS_ADDR 0x40040000 #define OTG_HS_ADDR 0x40040000
/** /**
* @brief Accesses to the OTG registers block. * @brief Accesses to the OTG_FS registers block.
*/ */
#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR) #define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR)
#define OTG OTG_FS
#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR)
/** /**
* @brief Returns a FIFO address. * @brief Accesses to the OTG_HS registers block.
*/ */
/*#define OTG1_FIFO(addr, n) ((volatile uint32_t *)((addr) + \ #define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR)
0x1000 + \
(0x1000 * (n))))*/
#endif /* _STM32_OTG_H_ */ #endif /* _STM32_OTG_H_ */

View File

@ -43,11 +43,16 @@
/* Driver exported variables. */ /* Driver exported variables. */
/*===========================================================================*/ /*===========================================================================*/
/** @brief OTG1 driver identifier.*/ /** @brief OTG_FS driver identifier.*/
#if STM32_USB_USE_OTG1 || defined(__DOXYGEN__) #if STM32_USB_USE_OTG1 || defined(__DOXYGEN__)
USBDriver USBD1; USBDriver USBD1;
#endif #endif
/** @brief OTG_HS driver identifier.*/
#if STM32_USB_USE_OTG2 || defined(__DOXYGEN__)
USBDriver USBD2;
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Driver local variables. */ /* Driver local variables. */
/*===========================================================================*/ /*===========================================================================*/
@ -93,67 +98,67 @@ static const USBEndpointConfig ep0config = {
/* Driver local functions. */ /* Driver local functions. */
/*===========================================================================*/ /*===========================================================================*/
static void otg_core_reset(void) { static void otg_core_reset(stm32_otg_t *otgp) {
/* Wait AHB idle condition.*/ /* Wait AHB idle condition.*/
while ((OTG->GRSTCTL & GRSTCTL_AHBIDL) == 0) while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0)
; ;
/* Core reset and delay of at least 3 PHY cycles.*/ /* Core reset and delay of at least 3 PHY cycles.*/
OTG->GRSTCTL = GRSTCTL_CSRST; otgp->GRSTCTL = GRSTCTL_CSRST;
while ((OTG->GRSTCTL & GRSTCTL_CSRST) != 0) while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0)
; ;
halPolledDelay(12); halPolledDelay(12);
} }
static void otg_disable_ep(void) { static void otg_disable_ep(stm32_otg_t *otgp) {
unsigned i; unsigned i;
for (i = 0; i <= USB_MAX_ENDPOINTS; i++) { for (i = 0; i <= USB_MAX_ENDPOINTS; i++) {
/* Disable only if enabled because this sentence in the manual: /* Disable only if enabled because this sentence in the manual:
"The application must set this bit only if Endpoint Enable is "The application must set this bit only if Endpoint Enable is
already set for this endpoint".*/ already set for this endpoint".*/
if ((OTG->ie[i].DIEPCTL & DIEPCTL_EPENA) != 0) { if ((otgp->ie[i].DIEPCTL & DIEPCTL_EPENA) != 0) {
OTG->ie[i].DIEPCTL = DIEPCTL_EPDIS; otgp->ie[i].DIEPCTL = DIEPCTL_EPDIS;
/* Wait for endpoint disable.*/ /* Wait for endpoint disable.*/
while (!(OTG->ie[i].DIEPINT & DIEPINT_EPDISD)) while (!(otgp->ie[i].DIEPINT & DIEPINT_EPDISD))
; ;
} }
else else
OTG->ie[i].DIEPCTL = 0; otgp->ie[i].DIEPCTL = 0;
OTG->ie[i].DIEPTSIZ = 0; otgp->ie[i].DIEPTSIZ = 0;
OTG->ie[i].DIEPINT = 0xFFFFFFFF; otgp->ie[i].DIEPINT = 0xFFFFFFFF;
/* Disable only if enabled because this sentence in the manual: /* Disable only if enabled because this sentence in the manual:
"The application must set this bit only if Endpoint Enable is "The application must set this bit only if Endpoint Enable is
already set for this endpoint". already set for this endpoint".
Note that the attempt to disable the OUT EP0 is ignored by the Note that the attempt to disable the OUT EP0 is ignored by the
hardware but the code is simpler this way.*/ hardware but the code is simpler this way.*/
if ((OTG->oe[i].DOEPCTL & DOEPCTL_EPENA) != 0) { if ((otgp->oe[i].DOEPCTL & DOEPCTL_EPENA) != 0) {
OTG->oe[i].DOEPCTL = DOEPCTL_EPDIS; otgp->oe[i].DOEPCTL = DOEPCTL_EPDIS;
/* Wait for endpoint disable.*/ /* Wait for endpoint disable.*/
while (!(OTG->oe[i].DOEPINT & DOEPINT_OTEPDIS)) while (!(otgp->oe[i].DOEPINT & DOEPINT_OTEPDIS))
; ;
} }
else else
OTG->oe[i].DOEPCTL = 0; otgp->oe[i].DOEPCTL = 0;
OTG->oe[i].DOEPTSIZ = 0; otgp->oe[i].DOEPTSIZ = 0;
OTG->oe[i].DOEPINT = 0xFFFFFFFF; otgp->oe[i].DOEPINT = 0xFFFFFFFF;
} }
OTG->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0); otgp->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0);
} }
static void otg_rxfifo_flush(void) { static void otg_rxfifo_flush(stm32_otg_t *otgp) {
OTG->GRSTCTL = GRSTCTL_RXFFLSH; otgp->GRSTCTL = GRSTCTL_RXFFLSH;
while ((OTG->GRSTCTL & GRSTCTL_RXFFLSH) != 0) while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0)
; ;
/* Wait for 3 PHY Clocks.*/ /* Wait for 3 PHY Clocks.*/
halPolledDelay(12); halPolledDelay(12);
} }
static void otg_txfifo_flush(uint32_t fifo) { static void otg_txfifo_flush(stm32_otg_t *otgp, uint32_t fifo) {
OTG->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH; otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH;
while ((OTG->GRSTCTL & GRSTCTL_TXFFLSH) != 0) while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0)
; ;
/* Wait for 3 PHY Clocks.*/ /* Wait for 3 PHY Clocks.*/
halPolledDelay(12); halPolledDelay(12);
@ -184,8 +189,14 @@ static uint32_t otg_ram_alloc(USBDriver *usbp, size_t size) {
next = usbp->pmnext; next = usbp->pmnext;
usbp->pmnext += size; usbp->pmnext += size;
chDbgAssert(usbp->pmnext <= STM32_OTG_FIFO_MEM_SIZE, #if STM32_USB_USE_OTG1
"otg_fifo_alloc(), #1", "FIFO memory overflow"); chDbgAssert((usbp != &USBD1) || (usbp->pmnext <= STM32_OTG1_FIFO_MEM_SIZE),
"otg_fifo_alloc(), #1", "OTG1 FIFO memory overflow");
#endif
#if STM32_USB_USE_OTG2
chDbgAssert((usbp != &USBD2) || (usbp->pmnext <= STM32_OTG2_FIFO_MEM_SIZE),
"otg_fifo_alloc(), #2", "OTG2 FIFO memory overflow");
#endif
return next; return next;
} }
@ -216,35 +227,32 @@ static uint8_t *otg_do_push(volatile uint32_t *fifop, uint8_t *buf, size_t n) {
/** /**
* @brief Writes to a TX FIFO. * @brief Writes to a TX FIFO.
* *
* @param[in] ep endpoint number * @param[in] fifop pointer to the FIFO register
* @param[in] buf buffer where to copy the endpoint data * @param[in] buf buffer where to copy the endpoint data
* @param[in] n maximum number of bytes to copy * @param[in] n maximum number of bytes to copy
* *
* @notapi * @notapi
*/ */
static void otg_fifo_write_from_buffer(usbep_t ep, static void otg_fifo_write_from_buffer(volatile uint32_t *fifop,
const uint8_t *buf, const uint8_t *buf,
size_t n) { size_t n) {
otg_do_push(OTG->FIFO[ep], (uint8_t *)buf, (n + 3) / 4); otg_do_push(fifop, (uint8_t *)buf, (n + 3) / 4);
} }
/** /**
* @brief Writes to a TX FIFO fetching data from a queue. * @brief Writes to a TX FIFO fetching data from a queue.
* *
* @param[in] ep endpoint number * @param[in] fifop pointer to the FIFO register
* @param[in] oqp pointer to an @p OutputQueue object * @param[in] oqp pointer to an @p OutputQueue object
* @param[in] n maximum number of bytes to copy * @param[in] n maximum number of bytes to copy
* *
* @notapi * @notapi
*/ */
static void otg_fifo_write_from_queue(usbep_t ep, static void otg_fifo_write_from_queue(volatile uint32_t *fifop,
OutputQueue *oqp, OutputQueue *oqp,
size_t n) { size_t n) {
size_t ntogo; size_t ntogo;
volatile uint32_t *fifop;
fifop = OTG->FIFO[ep];
ntogo = n; ntogo = n;
while (ntogo > 0) { while (ntogo > 0) {
@ -318,16 +326,18 @@ static uint8_t *otg_do_pop(volatile uint32_t *fifop, uint8_t *buf, size_t n) {
/** /**
* @brief Reads a packet from the RXFIFO. * @brief Reads a packet from the RXFIFO.
* *
* @param[in] fifop pointer to the FIFO register
* @param[out] buf buffer where to copy the endpoint data * @param[out] buf buffer where to copy the endpoint data
* @param[in] n number of bytes to pull from the FIFO * @param[in] n number of bytes to pull from the FIFO
* @param[in] max number of bytes to copy into the buffer * @param[in] max number of bytes to copy into the buffer
* *
* @notapi * @notapi
*/ */
static void otg_fifo_read_to_buffer(uint8_t *buf, size_t n, size_t max) { static void otg_fifo_read_to_buffer(volatile uint32_t *fifop,
volatile uint32_t *fifop; uint8_t *buf,
size_t n,
size_t max) {
fifop = OTG->FIFO[0];
n = (n + 3) / 4; n = (n + 3) / 4;
max = (max + 3) / 4; max = (max + 3) / 4;
while (n) { while (n) {
@ -346,16 +356,16 @@ static void otg_fifo_read_to_buffer(uint8_t *buf, size_t n, size_t max) {
/** /**
* @brief Reads a packet from the RXFIFO. * @brief Reads a packet from the RXFIFO.
* *
* @param[in] fifop pointer to the FIFO register
* @param[in] iqp pointer to an @p InputQueue object * @param[in] iqp pointer to an @p InputQueue object
* @param[in] n number of bytes to pull from the FIFO * @param[in] n number of bytes to pull from the FIFO
* *
* @notapi * @notapi
*/ */
static void otg_fifo_read_to_queue(InputQueue *iqp, size_t n) { static void otg_fifo_read_to_queue(volatile uint32_t *fifop,
InputQueue *iqp,
size_t n) {
size_t ntogo; size_t ntogo;
volatile uint32_t *fifop;
fifop = OTG->FIFO[0];
ntogo = n; ntogo = n;
while (ntogo > 0) { while (ntogo > 0) {
@ -410,25 +420,28 @@ static void otg_fifo_read_to_queue(InputQueue *iqp, size_t n) {
static void otg_rxfifo_handler(USBDriver *usbp) { static void otg_rxfifo_handler(USBDriver *usbp) {
uint32_t sts, cnt, ep; uint32_t sts, cnt, ep;
sts = OTG->GRXSTSP; sts = usbp->otg->GRXSTSP;
switch (sts & GRXSTSP_PKTSTS_MASK) { switch (sts & GRXSTSP_PKTSTS_MASK) {
case GRXSTSP_SETUP_COMP: case GRXSTSP_SETUP_COMP:
break; break;
case GRXSTSP_SETUP_DATA: case GRXSTSP_SETUP_DATA:
cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF;
ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF; ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF;
otg_fifo_read_to_buffer(usbp->epc[ep]->setup_buf, cnt, 8); otg_fifo_read_to_buffer(usbp->otg->FIFO[0], usbp->epc[ep]->setup_buf,
cnt, 8);
break; break;
case GRXSTSP_OUT_DATA: case GRXSTSP_OUT_DATA:
cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF;
ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF; ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF;
if (usbp->epc[ep]->out_state->rxqueued) { if (usbp->epc[ep]->out_state->rxqueued) {
/* Queue associated.*/ /* Queue associated.*/
otg_fifo_read_to_queue(usbp->epc[ep]->out_state->mode.queue.rxqueue, otg_fifo_read_to_queue(usbp->otg->FIFO[0],
usbp->epc[ep]->out_state->mode.queue.rxqueue,
cnt); cnt);
} }
else { else {
otg_fifo_read_to_buffer(usbp->epc[ep]->out_state->mode.linear.rxbuf, otg_fifo_read_to_buffer(usbp->otg->FIFO[0],
usbp->epc[ep]->out_state->mode.linear.rxbuf,
cnt, cnt,
usbp->epc[ep]->out_state->rxsize - usbp->epc[ep]->out_state->rxsize -
usbp->epc[ep]->out_state->rxcnt); usbp->epc[ep]->out_state->rxcnt);
@ -468,7 +481,7 @@ static bool_t otg_txfifo_handler(USBDriver *usbp, usbep_t ep) {
/* Checks if in the TXFIFO there is enough space to accommodate the /* Checks if in the TXFIFO there is enough space to accommodate the
next packet.*/ next packet.*/
if (((OTG->ie[ep].DTXFSTS & DTXFSTS_INEPTFSAV_MASK) * 4) < n) if (((usbp->otg->ie[ep].DTXFSTS & DTXFSTS_INEPTFSAV_MASK) * 4) < n)
return FALSE; return FALSE;
#if STM32_USB_FIFO_FILL_PRIORITY_MASK #if STM32_USB_FIFO_FILL_PRIORITY_MASK
@ -477,13 +490,13 @@ static bool_t otg_txfifo_handler(USBDriver *usbp, usbep_t ep) {
/* Handles the two cases: linear buffer or queue.*/ /* Handles the two cases: linear buffer or queue.*/
if (usbp->epc[ep]->in_state->txqueued) { if (usbp->epc[ep]->in_state->txqueued) {
/* Queue associated.*/ /* Queue associated.*/
otg_fifo_write_from_queue(ep, otg_fifo_write_from_queue(usbp->otg->FIFO[ep],
usbp->epc[ep]->in_state->mode.queue.txqueue, usbp->epc[ep]->in_state->mode.queue.txqueue,
n); n);
} }
else { else {
/* Linear buffer associated.*/ /* Linear buffer associated.*/
otg_fifo_write_from_buffer(ep, otg_fifo_write_from_buffer(usbp->otg->FIFO[ep],
usbp->epc[ep]->in_state->mode.linear.txbuf, usbp->epc[ep]->in_state->mode.linear.txbuf,
n); n);
usbp->epc[ep]->in_state->mode.linear.txbuf += n; usbp->epc[ep]->in_state->mode.linear.txbuf += n;
@ -504,22 +517,24 @@ static bool_t otg_txfifo_handler(USBDriver *usbp, usbep_t ep) {
* @notapi * @notapi
*/ */
static void otg_epin_handler(USBDriver *usbp, usbep_t ep) { static void otg_epin_handler(USBDriver *usbp, usbep_t ep) {
uint32_t epint = OTG->ie[ep].DIEPINT; stm32_otg_t *otgp = usbp->otg;
uint32_t epint = otgp->ie[ep].DIEPINT;
OTG->ie[ep].DIEPINT = 0xFFFFFFFF; otgp->ie[ep].DIEPINT = 0xFFFFFFFF;
if (epint & DIEPINT_TOC) { if (epint & DIEPINT_TOC) {
/* Timeouts not handled yet, not sure how to handle.*/ /* Timeouts not handled yet, not sure how to handle.*/
} }
if ((epint & DIEPINT_XFRC) && (OTG->DIEPMSK & DIEPMSK_XFRCM)) { if ((epint & DIEPINT_XFRC) && (otgp->DIEPMSK & DIEPMSK_XFRCM)) {
/* Transmit transfer complete.*/ /* Transmit transfer complete.*/
_usb_isr_invoke_in_cb(usbp, ep); _usb_isr_invoke_in_cb(usbp, ep);
} }
if ((epint & DIEPINT_TXFE) && (OTG->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) { if ((epint & DIEPINT_TXFE) &&
(otgp->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) {
/* The thread is made ready, it will be scheduled on ISR exit.*/ /* The thread is made ready, it will be scheduled on ISR exit.*/
chSysLockFromIsr(); chSysLockFromIsr();
usbp->txpending |= (1 << ep); usbp->txpending |= (1 << ep);
OTG->DIEPEMPMSK &= ~(1 << ep); otgp->DIEPEMPMSK &= ~(1 << ep);
if (usbp->thd_wait != NULL) { if (usbp->thd_wait != NULL) {
chThdResumeI(usbp->thd_wait); chThdResumeI(usbp->thd_wait);
usbp->thd_wait = NULL; usbp->thd_wait = NULL;
@ -537,29 +552,112 @@ static void otg_epin_handler(USBDriver *usbp, usbep_t ep) {
* @notapi * @notapi
*/ */
static void otg_epout_handler(USBDriver *usbp, usbep_t ep) { static void otg_epout_handler(USBDriver *usbp, usbep_t ep) {
uint32_t epint = OTG->oe[ep].DOEPINT; stm32_otg_t *otgp = usbp->otg;
uint32_t epint = otgp->oe[ep].DOEPINT;
/* Resets all EP IRQ sources.*/ /* Resets all EP IRQ sources.*/
OTG->oe[ep].DOEPINT = 0xFFFFFFFF; otgp->oe[ep].DOEPINT = 0xFFFFFFFF;
if ((epint & DOEPINT_STUP) && (OTG->DOEPMSK & DOEPMSK_STUPM)) { if ((epint & DOEPINT_STUP) && (otgp->DOEPMSK & DOEPMSK_STUPM)) {
/* Setup packets handling, setup packets are handled using a /* Setup packets handling, setup packets are handled using a
specific callback.*/ specific callback.*/
_usb_isr_invoke_setup_cb(usbp, ep); _usb_isr_invoke_setup_cb(usbp, ep);
} }
if ((epint & DOEPINT_XFRC) && (OTG->DOEPMSK & DOEPMSK_XFRCM)) { if ((epint & DOEPINT_XFRC) && (otgp->DOEPMSK & DOEPMSK_XFRCM)) {
/* Receive transfer complete.*/ /* Receive transfer complete.*/
_usb_isr_invoke_out_cb(usbp, ep); _usb_isr_invoke_out_cb(usbp, ep);
} }
} }
/**
* @brief OTG shared ISR.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
static void usb_lld_serve_interrupt(USBDriver *usbp) {
stm32_otg_t *otgp = usbp->otg;
uint32_t sts, src;
sts = otgp->GINTSTS & otgp->GINTMSK;
otgp->GINTSTS = sts;
/* Reset interrupt handling.*/
if (sts & GINTSTS_USBRST) {
_usb_reset(usbp);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET);
}
/* Enumeration done.*/
if (sts & GINTSTS_ENUMDNE) {
(void)otgp->DSTS;
}
/* SOF interrupt handling.*/
if (sts & GINTSTS_SOF) {
_usb_isr_invoke_sof_cb(usbp);
}
/* RX FIFO not empty handling.*/
if (sts & GINTSTS_RXFLVL) {
/* The interrupt is masked while the thread has control or it would
be triggered again.*/
otgp->GINTMSK &= ~GINTMSK_RXFLVLM;
/* Checks if the thread is waiting for an event.*/
if (usbp->thd_wait != NULL) {
/* The thread is made ready, it will be scheduled on ISR exit.*/
chSysLockFromIsr();
chThdResumeI(usbp->thd_wait);
usbp->thd_wait = NULL;
chSysUnlockFromIsr();
}
}
/* IN/OUT endpoints event handling.*/
src = otgp->DAINT;
if (sts & GINTSTS_IEPINT) {
if (src & (1 << 0))
otg_epin_handler(usbp, 0);
if (src & (1 << 1))
otg_epin_handler(usbp, 1);
if (src & (1 << 2))
otg_epin_handler(usbp, 2);
if (src & (1 << 3))
otg_epin_handler(usbp, 3);
#if STM32_USB_USE_OTG2
if (src & (1 << 4))
otg_epin_handler(usbp, 4);
if (src & (1 << 5))
otg_epin_handler(usbp, 5);
#endif
}
if (sts & GINTSTS_OEPINT) {
if (src & (1 << 16))
otg_epout_handler(usbp, 0);
if (src & (1 << 17))
otg_epout_handler(usbp, 1);
if (src & (1 << 18))
otg_epout_handler(usbp, 2);
if (src & (1 << 19))
otg_epout_handler(usbp, 3);
#if STM32_USB_USE_OTG2
if (src & (1 << 20))
otg_epout_handler(usbp, 4);
if (src & (1 << 21))
otg_epout_handler(usbp, 5);
#endif
}
}
/*===========================================================================*/ /*===========================================================================*/
/* Driver interrupt handlers and threads. */ /* Driver interrupt handlers and threads. */
/*===========================================================================*/ /*===========================================================================*/
static msg_t usb_lld_pump(void *p) { static msg_t usb_lld_pump(void *p) {
USBDriver *usbp = (USBDriver *)p; USBDriver *usbp = (USBDriver *)p;
stm32_otg_t *otgp = usbp->otg;
chRegSetThreadName("usb_lld_pump"); chRegSetThreadName("usb_lld_pump");
chSysLock(); chSysLock();
@ -569,8 +667,8 @@ static msg_t usb_lld_pump(void *p) {
/* Nothing to do, going to sleep.*/ /* Nothing to do, going to sleep.*/
if ((usbp->state == USB_STOP) || if ((usbp->state == USB_STOP) ||
((usbp->txpending == 0) && !(OTG->GINTSTS & GINTSTS_RXFLVL))) { ((usbp->txpending == 0) && !(otgp->GINTSTS & GINTSTS_RXFLVL))) {
OTG->GINTMSK |= GINTMSK_RXFLVLM; otgp->GINTMSK |= GINTMSK_RXFLVLM;
usbp->thd_wait = chThdSelf(); usbp->thd_wait = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED); chSchGoSleepS(THD_STATE_SUSPENDED);
} }
@ -580,7 +678,7 @@ static msg_t usb_lld_pump(void *p) {
for (ep = 0; ep <= USB_MAX_ENDPOINTS; ep++) { for (ep = 0; ep <= USB_MAX_ENDPOINTS; ep++) {
/* Empties the RX FIFO.*/ /* Empties the RX FIFO.*/
while (OTG->GINTSTS & GINTSTS_RXFLVL) { while (otgp->GINTSTS & GINTSTS_RXFLVL) {
otg_rxfifo_handler(usbp); otg_rxfifo_handler(usbp);
} }
@ -594,16 +692,16 @@ static msg_t usb_lld_pump(void *p) {
"The application has to finish writing one complete packet before "The application has to finish writing one complete packet before
switching to a different channel/endpoint FIFO. Violating this switching to a different channel/endpoint FIFO. Violating this
rule results in an error.".*/ rule results in an error.".*/
OTG->GAHBCFG &= ~GAHBCFG_GINTMSK; otgp->GAHBCFG &= ~GAHBCFG_GINTMSK;
usbp->txpending &= ~epmask; usbp->txpending &= ~epmask;
chSysUnlock(); chSysUnlock();
bool_t done = otg_txfifo_handler(usbp, ep); bool_t done = otg_txfifo_handler(usbp, ep);
chSysLock(); chSysLock();
OTG->GAHBCFG |= GAHBCFG_GINTMSK; otgp->GAHBCFG |= GAHBCFG_GINTMSK;
if (!done) if (!done)
OTG->DIEPEMPMSK |= epmask; otgp->DIEPEMPMSK |= epmask;
chSysUnlock(); chSysUnlock();
} }
} }
@ -623,66 +721,29 @@ static msg_t usb_lld_pump(void *p) {
* @isr * @isr
*/ */
CH_IRQ_HANDLER(STM32_OTG1_HANDLER) { CH_IRQ_HANDLER(STM32_OTG1_HANDLER) {
USBDriver *usbp = &USBD1;
uint32_t sts;
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
sts = OTG->GINTSTS & OTG->GINTMSK; usb_lld_serve_interrupt(&USBD1);
OTG->GINTSTS = sts;
/* Reset interrupt handling.*/ CH_IRQ_EPILOGUE();
if (sts & GINTSTS_USBRST) {
_usb_reset(usbp);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET);
} }
#endif
/* Enumeration done.*/ #if STM32_USB_USE_OTG2 || defined(__DOXYGEN__)
if (sts & GINTSTS_ENUMDNE) { #if !defined(STM32_OTG2_HANDLER)
(void)OTG->DSTS; #error "STM32_OTG2_HANDLER not defined"
} #endif
/**
* @brief OTG2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(STM32_OTG2_HANDLER) {
/* SOF interrupt handling.*/ CH_IRQ_PROLOGUE();
if (sts & GINTSTS_SOF) {
_usb_isr_invoke_sof_cb(usbp);
}
/* RX FIFO not empty handling.*/ usb_lld_serve_interrupt(&USBD2);
if (sts & GINTSTS_RXFLVL) {
/* The interrupt is masked while the thread has control or it would
be triggered again.*/
OTG->GINTMSK &= ~GINTMSK_RXFLVLM;
/* Checks if the thread is waiting for an event.*/
if (usbp->thd_wait != NULL) {
/* The thread is made ready, it will be scheduled on ISR exit.*/
chSysLockFromIsr();
chThdResumeI(usbp->thd_wait);
usbp->thd_wait = NULL;
chSysUnlockFromIsr();
}
}
/* IN/OUT endpoints event handling, timeout and transfer complete events
are handled.*/
if (sts & (GINTSTS_IEPINT | GINTSTS_OEPINT)) {
uint32_t src = OTG->DAINT;
if (src & (1 << 0))
otg_epin_handler(usbp, 0);
if (src & (1 << 1))
otg_epin_handler(usbp, 1);
if (src & (1 << 2))
otg_epin_handler(usbp, 2);
if (src & (1 << 3))
otg_epin_handler(usbp, 3);
if (src & (1 << 16))
otg_epout_handler(usbp, 0);
if (src & (1 << 17))
otg_epout_handler(usbp, 1);
if (src & (1 << 18))
otg_epout_handler(usbp, 2);
if (src & (1 << 19))
otg_epout_handler(usbp, 3);
}
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -702,8 +763,10 @@ void usb_lld_init(void) {
/* Driver initialization.*/ /* Driver initialization.*/
usbObjectInit(&USBD1); usbObjectInit(&USBD1);
#if STM32_USB_USE_OTG1
USBD1.thd_ptr = NULL; USBD1.thd_ptr = NULL;
USBD1.thd_wait = NULL; USBD1.thd_wait = NULL;
USBD1.otg = OTG_FS;
/* Filling the thread working area here because the function /* Filling the thread working area here because the function
@p chThdCreateI() does not do it.*/ @p chThdCreateI() does not do it.*/
@ -718,6 +781,27 @@ void usb_lld_init(void) {
CH_STACK_FILL_VALUE); CH_STACK_FILL_VALUE);
} }
#endif #endif
#endif
#if STM32_USB_USE_OTG2
USBD2.thd_ptr = NULL;
USBD2.thd_wait = NULL;
USBD2.otg = OTG_HS;
/* Filling the thread working area here because the function
@p chThdCreateI() does not do it.*/
#if CH_DBG_FILL_THREADS
{
void *wsp = USBD2.wa_pump;
_thread_memfill((uint8_t *)wsp,
(uint8_t *)wsp + sizeof(Thread),
CH_THREAD_FILL_VALUE);
_thread_memfill((uint8_t *)wsp + sizeof(Thread),
(uint8_t *)wsp + sizeof(USBD1.wa_pump) - sizeof(Thread),
CH_STACK_FILL_VALUE);
}
#endif
#endif
} }
/** /**
@ -731,6 +815,9 @@ void usb_lld_init(void) {
* @notapi * @notapi
*/ */
void usb_lld_start(USBDriver *usbp) { void usb_lld_start(USBDriver *usbp) {
stm32_otg_t *otgp = usbp->otg;
usbp->txpending = 0;
if (usbp->state == USB_STOP) { if (usbp->state == USB_STOP) {
/* Clock activation.*/ /* Clock activation.*/
@ -746,7 +833,26 @@ void usb_lld_start(USBDriver *usbp) {
/* Creates the hauler threads in a suspended state. Note, it is /* Creates the hauler threads in a suspended state. Note, it is
created only once, the first time @p usbStart() is invoked.*/ created only once, the first time @p usbStart() is invoked.*/
usbp->txpending = 0; if (usbp->thd_ptr == NULL)
usbp->thd_ptr = usbp->thd_wait = chThdCreateI(usbp->wa_pump,
sizeof usbp->wa_pump,
STM32_USB_THREAD_PRIORITY,
usb_lld_pump,
usbp);
}
#endif
#if STM32_USB_USE_OTG2
if (&USBD2 == usbp) {
/* OTG HS clock enable and reset.*/
rccEnableOTG_HS(FALSE);
rccResetOTG_HS();
/* Enables IRQ vector.*/
nvicEnableVector(STM32_OTG2_NUMBER,
CORTEX_PRIORITY_MASK(STM32_USB_OTG2_IRQ_PRIORITY));
/* Creates the hauler threads in a suspended state. Note, it is
created only once, the first time @p usbStart() is invoked.*/
if (usbp->thd_ptr == NULL) if (usbp->thd_ptr == NULL)
usbp->thd_ptr = usbp->thd_wait = chThdCreateI(usbp->wa_pump, usbp->thd_ptr = usbp->thd_wait = chThdCreateI(usbp->wa_pump,
sizeof usbp->wa_pump, sizeof usbp->wa_pump,
@ -757,43 +863,43 @@ void usb_lld_start(USBDriver *usbp) {
#endif #endif
/* Soft core reset.*/ /* Soft core reset.*/
otg_core_reset(); otg_core_reset(otgp);
/* Internal FS PHY activation.*/ /* Internal FS PHY activation.*/
OTG->GCCFG = GCCFG_PWRDWN; otgp->GCCFG = GCCFG_PWRDWN;
/* - Forced device mode. /* - Forced device mode.
- USB turn-around time = TRDT_VALUE. - USB turn-around time = TRDT_VALUE.
- Full Speed 1.1 PHY.*/ - Full Speed 1.1 PHY.*/
OTG->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE) | GUSBCFG_PHYSEL; otgp->GUSBCFG = GUSBCFG_FDMOD | GUSBCFG_TRDT(TRDT_VALUE) | GUSBCFG_PHYSEL;
/* Interrupts on TXFIFOs half empty.*/ /* Interrupts on TXFIFOs half empty.*/
OTG->GAHBCFG = 0; otgp->GAHBCFG = 0;
/* 48MHz 1.1 PHY.*/ /* 48MHz 1.1 PHY.*/
OTG->DCFG = 0x02200000 | DCFG_PFIVL(0) | DCFG_DSPD_FS11; otgp->DCFG = 0x02200000 | DCFG_PFIVL(0) | DCFG_DSPD_FS11;
/* PHY enabled.*/ /* PHY enabled.*/
OTG->PCGCCTL = 0; otgp->PCGCCTL = 0;
/* Endpoints re-initialization.*/ /* Endpoints re-initialization.*/
otg_disable_ep(); otg_disable_ep(otgp);
/* Clear all pending Device Interrupts, only the USB Reset interrupt /* Clear all pending Device Interrupts, only the USB Reset interrupt
is required initially.*/ is required initially.*/
OTG->DIEPMSK = 0; otgp->DIEPMSK = 0;
OTG->DOEPMSK = 0; otgp->DOEPMSK = 0;
OTG->DAINTMSK = 0; otgp->DAINTMSK = 0;
if (usbp->config->sof_cb == NULL) if (usbp->config->sof_cb == NULL)
OTG->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM /*| GINTMSK_USBSUSPM | otgp->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM /*| GINTMSK_USBSUSPM |
GINTMSK_ESUSPM |*/; GINTMSK_ESUSPM |*/;
else else
OTG->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM /*| GINTMSK_USBSUSPM | otgp->GINTMSK = GINTMSK_ENUMDNEM | GINTMSK_USBRSTM /*| GINTMSK_USBSUSPM |
GINTMSK_ESUSPM */ | GINTMSK_SOFM; GINTMSK_ESUSPM */ | GINTMSK_SOFM;
OTG->GINTSTS = 0xFFFFFFFF; /* Clears all pending IRQs, if any. */ otgp->GINTSTS = 0xFFFFFFFF; /* Clears all pending IRQs, if any. */
/* Global interrupts enable.*/ /* Global interrupts enable.*/
OTG->GAHBCFG |= GAHBCFG_GINTMSK; otgp->GAHBCFG |= GAHBCFG_GINTMSK;
} }
} }
@ -805,15 +911,16 @@ void usb_lld_start(USBDriver *usbp) {
* @notapi * @notapi
*/ */
void usb_lld_stop(USBDriver *usbp) { void usb_lld_stop(USBDriver *usbp) {
stm32_otg_t *otgp = usbp->otg;
/* If in ready state then disables the USB clock.*/ /* If in ready state then disables the USB clock.*/
if (usbp->state != USB_STOP) { if (usbp->state != USB_STOP) {
usbp->txpending = 0; usbp->txpending = 0;
OTG->DAINTMSK = 0; otgp->DAINTMSK = 0;
OTG->GAHBCFG = 0; otgp->GAHBCFG = 0;
OTG->GCCFG = 0; otgp->GCCFG = 0;
#if STM32_USB_USE_USB1 #if STM32_USB_USE_USB1
if (&USBD1 == usbp) { if (&USBD1 == usbp) {
@ -821,6 +928,13 @@ void usb_lld_stop(USBDriver *usbp) {
rccDisableOTG1(FALSE); rccDisableOTG1(FALSE);
} }
#endif #endif
#if STM32_USB_USE_USB2
if (&USBD2 == usbp) {
nvicDisableVector(STM32_OTG2_NUMBER);
rccDisableOTG2(FALSE);
}
#endif
} }
} }
@ -833,49 +947,50 @@ void usb_lld_stop(USBDriver *usbp) {
*/ */
void usb_lld_reset(USBDriver *usbp) { void usb_lld_reset(USBDriver *usbp) {
unsigned i; unsigned i;
stm32_otg_t *otgp = usbp->otg;
/* Clear the Remote Wake-up Signaling */ /* Clear the Remote Wake-up Signaling */
OTG->DCTL &= ~DCTL_RWUSIG; otgp->DCTL &= ~DCTL_RWUSIG;
/* Flush the Tx FIFO */ /* Flush the Tx FIFO */
otg_txfifo_flush(0); otg_txfifo_flush(otgp, 0);
/* All endpoints in NAK mode, interrupts cleared.*/ /* All endpoints in NAK mode, interrupts cleared.*/
for (i = 0; i <= USB_MAX_ENDPOINTS; i++) { for (i = 0; i <= USB_MAX_ENDPOINTS; i++) {
OTG->ie[i].DIEPCTL = DIEPCTL_SNAK; otgp->ie[i].DIEPCTL = DIEPCTL_SNAK;
OTG->oe[i].DOEPCTL = DOEPCTL_SNAK; otgp->oe[i].DOEPCTL = DOEPCTL_SNAK;
OTG->ie[i].DIEPINT = 0xFF; otgp->ie[i].DIEPINT = 0xFF;
OTG->oe[i].DOEPINT = 0xFF; otgp->oe[i].DOEPINT = 0xFF;
} }
/* Endpoint interrupts all disabled and cleared.*/ /* Endpoint interrupts all disabled and cleared.*/
OTG->DAINT = 0xFFFFFFFF; otgp->DAINT = 0xFFFFFFFF;
OTG->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0); otgp->DAINTMSK = DAINTMSK_OEPM(0) | DAINTMSK_IEPM(0);
/* Resets the FIFO memory allocator.*/ /* Resets the FIFO memory allocator.*/
otg_ram_reset(usbp); otg_ram_reset(usbp);
/* Receive FIFO size initialization, the address is always zero.*/ /* Receive FIFO size initialization, the address is always zero.*/
OTG->GRXFSIZ = STM32_USB_OTG1_RX_FIFO_SIZE / 4; otgp->GRXFSIZ = STM32_USB_OTG1_RX_FIFO_SIZE / 4;
otg_rxfifo_flush(); otg_rxfifo_flush(otgp);
/* Resets the device address to zero.*/ /* Resets the device address to zero.*/
OTG->DCFG = (OTG->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(0); otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(0);
/* Enables also EP-related interrupt sources.*/ /* Enables also EP-related interrupt sources.*/
OTG->GINTMSK |= GINTMSK_RXFLVLM | GINTMSK_OEPM | GINTMSK_IEPM; otgp->GINTMSK |= GINTMSK_RXFLVLM | GINTMSK_OEPM | GINTMSK_IEPM;
OTG->DIEPMSK = DIEPMSK_TOCM | DIEPMSK_XFRCM; otgp->DIEPMSK = DIEPMSK_TOCM | DIEPMSK_XFRCM;
OTG->DOEPMSK = DOEPMSK_STUPM | DOEPMSK_XFRCM; otgp->DOEPMSK = DOEPMSK_STUPM | DOEPMSK_XFRCM;
/* EP0 initialization, it is a special case.*/ /* EP0 initialization, it is a special case.*/
usbp->epc[0] = &ep0config; usbp->epc[0] = &ep0config;
OTG->oe[0].DOEPTSIZ = 0; otgp->oe[0].DOEPTSIZ = 0;
OTG->oe[0].DOEPCTL = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL | otgp->oe[0].DOEPCTL = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL |
DOEPCTL_MPSIZ(ep0config.out_maxsize); DOEPCTL_MPSIZ(ep0config.out_maxsize);
OTG->ie[0].DIEPTSIZ = 0; otgp->ie[0].DIEPTSIZ = 0;
OTG->ie[0].DIEPCTL = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL | otgp->ie[0].DIEPCTL = DIEPCTL_SD0PID | DIEPCTL_USBAEP | DIEPCTL_EPTYP_CTRL |
DIEPCTL_TXFNUM(0) | DIEPCTL_MPSIZ(ep0config.in_maxsize); DIEPCTL_TXFNUM(0) | DIEPCTL_MPSIZ(ep0config.in_maxsize);
OTG->DIEPTXF0 = DIEPTXF_INEPTXFD(ep0config.in_maxsize / 4) | otgp->DIEPTXF0 = DIEPTXF_INEPTXFD(ep0config.in_maxsize / 4) |
DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, DIEPTXF_INEPTXSA(otg_ram_alloc(usbp,
ep0config.in_maxsize / 4)); ep0config.in_maxsize / 4));
} }
@ -888,8 +1003,9 @@ void usb_lld_reset(USBDriver *usbp) {
* @notapi * @notapi
*/ */
void usb_lld_set_address(USBDriver *usbp) { void usb_lld_set_address(USBDriver *usbp) {
stm32_otg_t *otgp = usbp->otg;
OTG->DCFG = (OTG->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(usbp->address); otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(usbp->address);
} }
/** /**
@ -902,6 +1018,7 @@ void usb_lld_set_address(USBDriver *usbp) {
*/ */
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
uint32_t ctl, fsize; uint32_t ctl, fsize;
stm32_otg_t *otgp = usbp->otg;
/* IN and OUT common parameters.*/ /* IN and OUT common parameters.*/
switch (usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) { switch (usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) {
@ -922,37 +1039,37 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
} }
/* OUT endpoint activation or deactivation.*/ /* OUT endpoint activation or deactivation.*/
OTG->oe[ep].DOEPTSIZ = 0; otgp->oe[ep].DOEPTSIZ = 0;
if (usbp->epc[ep]->out_cb != NULL) { if (usbp->epc[ep]->out_cb != NULL) {
OTG->oe[ep].DOEPCTL = ctl | DOEPCTL_MPSIZ(usbp->epc[ep]->out_maxsize); otgp->oe[ep].DOEPCTL = ctl | DOEPCTL_MPSIZ(usbp->epc[ep]->out_maxsize);
OTG->DAINTMSK |= DAINTMSK_OEPM(ep); otgp->DAINTMSK |= DAINTMSK_OEPM(ep);
} }
else { else {
OTG->oe[ep].DOEPCTL &= ~DOEPCTL_USBAEP; otgp->oe[ep].DOEPCTL &= ~DOEPCTL_USBAEP;
OTG->DAINTMSK &= ~DAINTMSK_OEPM(ep); otgp->DAINTMSK &= ~DAINTMSK_OEPM(ep);
} }
/* IN endpoint activation or deactivation.*/ /* IN endpoint activation or deactivation.*/
OTG->ie[ep].DIEPTSIZ = 0; otgp->ie[ep].DIEPTSIZ = 0;
if (usbp->epc[ep]->in_cb != NULL) { if (usbp->epc[ep]->in_cb != NULL) {
/* FIFO allocation for the IN endpoint.*/ /* FIFO allocation for the IN endpoint.*/
fsize = usbp->epc[ep]->in_maxsize / 4; fsize = usbp->epc[ep]->in_maxsize / 4;
if (usbp->epc[ep]->in_multiplier > 1) if (usbp->epc[ep]->in_multiplier > 1)
fsize *= usbp->epc[ep]->in_multiplier; fsize *= usbp->epc[ep]->in_multiplier;
OTG->DIEPTXF[ep - 1] = DIEPTXF_INEPTXFD(fsize) | otgp->DIEPTXF[ep - 1] = DIEPTXF_INEPTXFD(fsize) |
DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, fsize)); DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, fsize));
otg_txfifo_flush(ep); otg_txfifo_flush(otgp, ep);
OTG->ie[ep].DIEPCTL = ctl | otgp->ie[ep].DIEPCTL = ctl |
DIEPCTL_TXFNUM(ep) | DIEPCTL_TXFNUM(ep) |
DIEPCTL_MPSIZ(usbp->epc[ep]->in_maxsize); DIEPCTL_MPSIZ(usbp->epc[ep]->in_maxsize);
OTG->DAINTMSK |= DAINTMSK_IEPM(ep); otgp->DAINTMSK |= DAINTMSK_IEPM(ep);
} }
else { else {
OTG->DIEPTXF[ep - 1] = 0x02000400; /* Reset value.*/ otgp->DIEPTXF[ep - 1] = 0x02000400; /* Reset value.*/
otg_txfifo_flush(ep); otg_txfifo_flush(otgp, ep);
OTG->ie[ep].DIEPCTL &= ~DIEPCTL_USBAEP; otgp->ie[ep].DIEPCTL &= ~DIEPCTL_USBAEP;
OTG->DAINTMSK &= ~DAINTMSK_IEPM(ep); otgp->DAINTMSK &= ~DAINTMSK_IEPM(ep);
} }
} }
@ -969,7 +1086,7 @@ void usb_lld_disable_endpoints(USBDriver *usbp) {
otg_ram_reset(usbp); otg_ram_reset(usbp);
/* Disabling all endpoints.*/ /* Disabling all endpoints.*/
otg_disable_ep(); otg_disable_ep(usbp->otg);
} }
/** /**
@ -989,7 +1106,7 @@ usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
(void)usbp; (void)usbp;
ctl = OTG->oe[ep].DOEPCTL; ctl = usbp->otg->oe[ep].DOEPCTL;
if (!(ctl & DOEPCTL_USBAEP)) if (!(ctl & DOEPCTL_USBAEP))
return EP_STATUS_DISABLED; return EP_STATUS_DISABLED;
if (ctl & DOEPCTL_STALL) if (ctl & DOEPCTL_STALL)
@ -1014,7 +1131,7 @@ usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
(void)usbp; (void)usbp;
ctl = OTG->ie[ep].DIEPCTL; ctl = usbp->otg->ie[ep].DIEPCTL;
if (!(ctl & DIEPCTL_USBAEP)) if (!(ctl & DIEPCTL_USBAEP))
return EP_STATUS_DISABLED; return EP_STATUS_DISABLED;
if (ctl & DIEPCTL_STALL) if (ctl & DIEPCTL_STALL)
@ -1056,7 +1173,7 @@ void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep) {
/* Transfer initialization.*/ /* Transfer initialization.*/
pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / pcnt = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1) /
usbp->epc[ep]->out_maxsize; usbp->epc[ep]->out_maxsize;
OTG->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) | usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) |
DOEPTSIZ_XFRSIZ(usbp->epc[ep]->out_maxsize); DOEPTSIZ_XFRSIZ(usbp->epc[ep]->out_maxsize);
} }
@ -1075,13 +1192,13 @@ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) {
/* Transfer initialization.*/ /* Transfer initialization.*/
if (isp->txsize == 0) { if (isp->txsize == 0) {
/* Special case, sending zero size packet.*/ /* Special case, sending zero size packet.*/
OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0); usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
} }
else { else {
/* Normal case.*/ /* Normal case.*/
uint32_t pcnt = (isp->txsize + usbp->epc[ep]->in_maxsize - 1) / uint32_t pcnt = (isp->txsize + usbp->epc[ep]->in_maxsize - 1) /
usbp->epc[ep]->in_maxsize; usbp->epc[ep]->in_maxsize;
OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(pcnt) | usbp->otg->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(pcnt) |
DIEPTSIZ_XFRSIZ(usbp->epc[ep]->in_state->txsize); DIEPTSIZ_XFRSIZ(usbp->epc[ep]->in_state->txsize);
} }
@ -1097,9 +1214,7 @@ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) {
*/ */
void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
(void)usbp; usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_CNAK;
OTG->oe[ep].DOEPCTL |= DOEPCTL_CNAK;
} }
/** /**
@ -1112,10 +1227,8 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
*/ */
void usb_lld_start_in(USBDriver *usbp, usbep_t ep) { void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
(void)usbp; usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK;
usbp->otg->DIEPEMPMSK |= DIEPEMPMSK_INEPTXFEM(ep);
OTG->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK;
OTG->DIEPEMPMSK |= DIEPEMPMSK_INEPTXFEM(ep);
} }
/** /**
@ -1128,9 +1241,7 @@ void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
*/ */
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) { void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
(void)usbp; usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_STALL;
OTG->oe[ep].DOEPCTL |= DOEPCTL_STALL;
} }
/** /**
@ -1143,9 +1254,7 @@ void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
*/ */
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) { void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
(void)usbp; usbp->otg->ie[ep].DIEPCTL |= DIEPCTL_STALL;
OTG->ie[ep].DIEPCTL |= DIEPCTL_STALL;
} }
/** /**
@ -1158,9 +1267,7 @@ void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
*/ */
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) { void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
(void)usbp; usbp->otg->oe[ep].DOEPCTL &= ~DOEPCTL_STALL;
OTG->oe[ep].DOEPCTL &= ~DOEPCTL_STALL;
} }
/** /**
@ -1173,9 +1280,7 @@ void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
*/ */
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) { void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
(void)usbp; usbp->otg->ie[ep].DIEPCTL &= ~DIEPCTL_STALL;
OTG->ie[ep].DIEPCTL &= ~DIEPCTL_STALL;
} }
#endif /* HAL_USE_USB */ #endif /* HAL_USE_USB */

View File

@ -40,7 +40,11 @@
/** /**
* @brief Maximum endpoint address. * @brief Maximum endpoint address.
*/ */
#if !STM32_USB_USE_OTG2 || defined(__DOXYGEN__)
#define USB_MAX_ENDPOINTS 3 #define USB_MAX_ENDPOINTS 3
#else
#define USB_MAX_ENDPOINTS 5
#endif
/** /**
* @brief The address can be changed immediately upon packet reception. * @brief The address can be changed immediately upon packet reception.
@ -53,13 +57,22 @@
/** /**
* @brief OTG1 driver enable switch. * @brief OTG1 driver enable switch.
* @details If set to @p TRUE the support for USB1 is included. * @details If set to @p TRUE the support for OTG_FS is included.
* @note The default is @p TRUE. * @note The default is @p TRUE.
*/ */
#if !defined(STM32_USB_USE_OTG1) || defined(__DOXYGEN__) #if !defined(STM32_USB_USE_OTG1) || defined(__DOXYGEN__)
#define STM32_USB_USE_OTG1 TRUE #define STM32_USB_USE_OTG1 TRUE
#endif #endif
/**
* @brief OTG2 driver enable switch.
* @details If set to @p TRUE the support for OTG_HS is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_USB_USE_OTG2) || defined(__DOXYGEN__)
#define STM32_USB_USE_OTG2 TRUE
#endif
/** /**
* @brief OTG1 interrupt priority level setting. * @brief OTG1 interrupt priority level setting.
*/ */
@ -67,6 +80,13 @@
#define STM32_USB_OTG1_IRQ_PRIORITY 14 #define STM32_USB_OTG1_IRQ_PRIORITY 14
#endif #endif
/**
* @brief OTG2 interrupt priority level setting.
*/
#if !defined(STM32_USB_OTG2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_USB_OTG2_IRQ_PRIORITY 14
#endif
/** /**
* @brief OTG1 RX shared FIFO size. * @brief OTG1 RX shared FIFO size.
* @note Must be a multiple of 4. * @note Must be a multiple of 4.
@ -76,14 +96,22 @@
#endif #endif
/** /**
* @brief Dedicated data pump thread priority. * @brief OTG2 RX shared FIFO size.
* @note Must be a multiple of 4.
*/
#if !defined(STM32_USB_OTG2_RX_FIFO_SIZE) || defined(__DOXYGEN__)
#define STM32_USB_OTG2_RX_FIFO_SIZE 512
#endif
/**
* @brief Dedicated data pump threads priority.
*/ */
#if !defined(STM32_USB_THREAD_PRIORITY) || defined(__DOXYGEN__) #if !defined(STM32_USB_THREAD_PRIORITY) || defined(__DOXYGEN__)
#define STM32_USB_THREAD_PRIORITY LOWPRIO #define STM32_USB_THREAD_PRIORITY LOWPRIO
#endif #endif
/** /**
* @brief Dedicated data pump thread stack size. * @brief Dedicated data pump threads stack size.
*/ */
#if !defined(STM32_USB_THREAD_STACK_SIZE) || defined(__DOXYGEN__) #if !defined(STM32_USB_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
#define STM32_USB_THREAD_STACK_SIZE 128 #define STM32_USB_THREAD_STACK_SIZE 128
@ -116,7 +144,11 @@
#error "OTG1 not present in the selected device" #error "OTG1 not present in the selected device"
#endif #endif
#if !STM32_USB_USE_OTG1 #if STM32_USB_USE_OTG2 && !STM32_HAS_OTG2
#error "OTG2 not present in the selected device"
#endif
#if !STM32_USB_USE_OTG1 && !STM32_USB_USE_OTG2
#error "USB driver activated but no USB peripheral assigned" #error "USB driver activated but no USB peripheral assigned"
#endif #endif
@ -125,8 +157,17 @@
#error "Invalid IRQ priority assigned to OTG1" #error "Invalid IRQ priority assigned to OTG1"
#endif #endif
#if STM32_USB_USE_OTG2 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_USB_OTG2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to OTG2"
#endif
#if (STM32_USB_OTG1_RX_FIFO_SIZE & 3) != 0 #if (STM32_USB_OTG1_RX_FIFO_SIZE & 3) != 0
#error "RX FIFO size must be a multiple of 4" #error "OTG1 RX FIFO size must be a multiple of 4"
#endif
#if (STM32_USB_OTG2_RX_FIFO_SIZE & 3) != 0
#error "OTG2 RX FIFO size must be a multiple of 4"
#endif #endif
#if defined(STM32F4XX) || defined(STM32F2XX) #if defined(STM32F4XX) || defined(STM32F2XX)
@ -370,6 +411,10 @@ struct USBDriver {
USB_DRIVER_EXT_FIELDS USB_DRIVER_EXT_FIELDS
#endif #endif
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
/**
* @brief Pointer to the OTG peripheral associated to this driver.
*/
stm32_otg_t *otg;
/** /**
* @brief Pointer to the next address in the packet memory. * @brief Pointer to the next address in the packet memory.
*/ */
@ -418,14 +463,14 @@ struct USBDriver {
* *
* @api * @api
*/ */
#define usb_lld_connect_bus(usbp) (OTG->GCCFG |= GCCFG_VBUSBSEN) #define usb_lld_connect_bus(usbp) (usbp->otg->GCCFG |= GCCFG_VBUSBSEN)
/** /**
* @brief Disconnect the USB device. * @brief Disconnect the USB device.
* *
* @api * @api
*/ */
#define usb_lld_disconnect_bus(usbp) (OTG->GCCFG &= ~GCCFG_VBUSBSEN) #define usb_lld_disconnect_bus(usbp) (usbp->otg->GCCFG &= ~GCCFG_VBUSBSEN)
/*===========================================================================*/ /*===========================================================================*/
/* External declarations. */ /* External declarations. */
@ -435,6 +480,10 @@ struct USBDriver {
extern USBDriver USBD1; extern USBDriver USBD1;
#endif #endif
#if STM32_USB_USE_OTG2 && !defined(__DOXYGEN__)
extern USBDriver USBD2;
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -603,7 +603,7 @@
* *
* @api * @api
*/ */
#define rccEnableOTG_FS(lp) rccEnableAHB2(RCC_AHB2LPENR_OTGFSLPEN, lp) #define rccEnableOTG_FS(lp) rccEnableAHB2(RCC_AHB2ENR_OTGFSEN, lp)
/** /**
* @brief Disables the OTG_FS peripheral clock. * @brief Disables the OTG_FS peripheral clock.
@ -612,7 +612,7 @@
* *
* @api * @api
*/ */
#define rccDisableOTG_FS(lp) rccEnableAHB2(RCC_AHB2LPENR_OTGFSLPEN, lp) #define rccDisableOTG_FS(lp) rccEnableAHB2(RCC_AHB2ENR_OTGFSEN, lp)
/** /**
* @brief Resets the OTG_FS peripheral. * @brief Resets the OTG_FS peripheral.
@ -620,6 +620,31 @@
* @api * @api
*/ */
#define rccResetOTG_FS() rccResetAHB2(RCC_AHB2RSTR_OTGFSRST) #define rccResetOTG_FS() rccResetAHB2(RCC_AHB2RSTR_OTGFSRST)
/**
* @brief Enables the OTG_HS peripheral clock.
*
* @param[in] lp low power enable flag
*
* @api
*/
#define rccEnableOTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_OTGHSEN, lp)
/**
* @brief Disables the OTG_HS peripheral clock.
*
* @param[in] lp low power enable flag
*
* @api
*/
#define rccDisableOTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_OTGHSEN, lp)
/**
* @brief Resets the OTG_HS peripheral.
*
* @api
*/
#define rccResetOTG_HS() rccResetAHB1(RCC_AHB1RSTR_OTGHSRST)
/** @} */ /** @} */
/** /**

View File

@ -12,15 +12,15 @@
* is using in the C source code, usually in main.c. This file contains: * is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select: * - Configuration section that allows to select:
* - The device used in the target application * - The device used in the target application
* - To use or not the peripherals drivers in application code(i.e. * - To use or not the peripheral<EFBFBD>s drivers in application code(i.e.
* code will be based on direct access to peripherals registers * code will be based on direct access to peripheral<EFBFBD>s registers
* rather than drivers API), this option is controlled by * rather than drivers API), this option is controlled by
* "#define USE_STDPERIPH_DRIVER" * "#define USE_STDPERIPH_DRIVER"
* - To change few application-specific parameters such as the HSE * - To change few application-specific parameters such as the HSE
* crystal frequency * crystal frequency
* - Data structures and the address mapping for all peripherals * - Data structures and the address mapping for all peripherals
* - Peripheral's registers declarations and bits definition * - Peripheral's registers declarations and bits definition
* - Macros to access peripherals registers hardware * - Macros to access peripheral<EFBFBD>s registers hardware
* *
****************************************************************************** ******************************************************************************
* @attention * @attention
@ -4897,7 +4897,9 @@ typedef struct
#define RCC_AHB2RSTR_CRYPRST ((uint32_t)0x00000010) #define RCC_AHB2RSTR_CRYPRST ((uint32_t)0x00000010)
#define RCC_AHB2RSTR_HSAHRST ((uint32_t)0x00000020) #define RCC_AHB2RSTR_HSAHRST ((uint32_t)0x00000020)
#define RCC_AHB2RSTR_RNGRST ((uint32_t)0x00000040) #define RCC_AHB2RSTR_RNGRST ((uint32_t)0x00000040)
#define RCC_AHB2RSTR_OTGFSRST ((uint32_t)0x00000080) /* CHIBIOS FIX */
/*#define RCC_AHB1RSTR_OTGHRST ((uint32_t)0x10000000)*/
#define RCC_AHB1RSTR_OTGHSRST ((uint32_t)0x10000000)
/******************** Bit definition for RCC_AHB3RSTR register **************/ /******************** Bit definition for RCC_AHB3RSTR register **************/
#define RCC_AHB3RSTR_FSMCRST ((uint32_t)0x00000001) #define RCC_AHB3RSTR_FSMCRST ((uint32_t)0x00000001)

View File

@ -603,7 +603,7 @@
* *
* @api * @api
*/ */
#define rccEnableOTG_FS(lp) rccEnableAHB2(RCC_AHB2LPENR_OTGFSLPEN, lp) #define rccEnableOTG_FS(lp) rccEnableAHB2(RCC_AHB2ENR_OTGFSEN, lp)
/** /**
* @brief Disables the OTG_FS peripheral clock. * @brief Disables the OTG_FS peripheral clock.
@ -612,7 +612,7 @@
* *
* @api * @api
*/ */
#define rccDisableOTG_FS(lp) rccEnableAHB2(RCC_AHB2LPENR_OTGFSLPEN, lp) #define rccDisableOTG_FS(lp) rccEnableAHB2(RCC_AHB2ENR_OTGFSEN, lp)
/** /**
* @brief Resets the OTG_FS peripheral. * @brief Resets the OTG_FS peripheral.
@ -620,6 +620,31 @@
* @api * @api
*/ */
#define rccResetOTG_FS() rccResetAHB2(RCC_AHB2RSTR_OTGFSRST) #define rccResetOTG_FS() rccResetAHB2(RCC_AHB2RSTR_OTGFSRST)
/**
* @brief Enables the OTG_HS peripheral clock.
*
* @param[in] lp low power enable flag
*
* @api
*/
#define rccEnableOTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_OTGHSEN, lp)
/**
* @brief Disables the OTG_HS peripheral clock.
*
* @param[in] lp low power enable flag
*
* @api
*/
#define rccDisableOTG_HS(lp) rccEnableAHB1(RCC_AHB1ENR_OTGHSEN, lp)
/**
* @brief Resets the OTG_HS peripheral.
*
* @api
*/
#define rccResetOTG_HS() rccResetAHB1(RCC_AHB1RSTR_OTGHSRST)
/** @} */ /** @} */
/** /**

View File

@ -12,15 +12,15 @@
* is using in the C source code, usually in main.c. This file contains: * is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select: * - Configuration section that allows to select:
* - The device used in the target application * - The device used in the target application
* - To use or not the peripherals drivers in application code(i.e. * - To use or not the peripheral<EFBFBD>s drivers in application code(i.e.
* code will be based on direct access to peripherals registers * code will be based on direct access to peripheral<EFBFBD>s registers
* rather than drivers API), this option is controlled by * rather than drivers API), this option is controlled by
* "#define USE_STDPERIPH_DRIVER" * "#define USE_STDPERIPH_DRIVER"
* - To change few application-specific parameters such as the HSE * - To change few application-specific parameters such as the HSE
* crystal frequency * crystal frequency
* - Data structures and the address mapping for all peripherals * - Data structures and the address mapping for all peripherals
* - Peripheral's registers declarations and bits definition * - Peripheral's registers declarations and bits definition
* - Macros to access peripherals registers hardware * - Macros to access peripheral<EFBFBD>s registers hardware
* *
****************************************************************************** ******************************************************************************
* @attention * @attention
@ -4953,7 +4953,9 @@ typedef struct
#define RCC_AHB1RSTR_DMA1RST ((uint32_t)0x00200000) #define RCC_AHB1RSTR_DMA1RST ((uint32_t)0x00200000)
#define RCC_AHB1RSTR_DMA2RST ((uint32_t)0x00400000) #define RCC_AHB1RSTR_DMA2RST ((uint32_t)0x00400000)
#define RCC_AHB1RSTR_ETHMACRST ((uint32_t)0x02000000) #define RCC_AHB1RSTR_ETHMACRST ((uint32_t)0x02000000)
#define RCC_AHB1RSTR_OTGHRST ((uint32_t)0x10000000) /* CHIBIOS FIX */
/*#define RCC_AHB1RSTR_OTGHRST ((uint32_t)0x10000000)*/
#define RCC_AHB1RSTR_OTGHSRST ((uint32_t)0x10000000)
/******************** Bit definition for RCC_AHB2RSTR register **************/ /******************** Bit definition for RCC_AHB2RSTR register **************/
#define RCC_AHB2RSTR_DCMIRST ((uint32_t)0x00000001) #define RCC_AHB2RSTR_DCMIRST ((uint32_t)0x00000001)