git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8531 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
Giovanni Di Sirio 2015-11-26 14:30:16 +00:00
parent 88247bf5e9
commit ec59801695
2 changed files with 82 additions and 15 deletions

View File

@ -34,6 +34,8 @@
#define BTABLE_ADDR 0x0000
#define EPR_EP_TYPE_IS_ISO(epr) ((epr & EPR_EP_TYPE_MASK) == EPR_EP_TYPE_ISO)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@ -211,7 +213,6 @@ static void usb_packet_write_from_buffer(stm32_usb_descriptor_t *udp,
stm32_usb_pma_t *pmap;
pmap = USB_ADDR2PTR(udp->TXADDR0);
udp->TXCOUNT0 = (stm32_usb_pma_t)n;
/* Pushing all complete words.*/
i = 0;
@ -251,7 +252,6 @@ static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp,
syssts_t sts;
stm32_usb_pma_t *pmap = USB_ADDR2PTR(udp->TXADDR0);
udp->TXCOUNT0 = (stm32_usb_pma_t)n;
nhw = n / 2;
while (nhw > 0) {
stm32_usb_pma_t w;
@ -368,7 +368,17 @@ OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
/* IN endpoint, transmission.*/
EPR_CLEAR_CTR_TX(ep);
/* Double buffering is always enabled for isochronous endpoints, and
although we overlap the two buffers for simplicity, we still need
to read from the right counter. The DTOG_TX bit indicates the buffer
that is currently in use by the USB peripheral, that is, the buffer
from which the next packet will be sent, so we need to read the
transmitted bytes from the counter of the OTHER buffer, which is
where we stored the last transmitted packet.*/
transmitted = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT0;
if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_TX))
transmitted = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT1;
epcp->in_state->txcnt += transmitted;
n = epcp->in_state->txsize - epcp->in_state->txcnt;
if (n > 0) {
@ -376,6 +386,16 @@ OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
if (n > epcp->in_maxsize)
n = epcp->in_maxsize;
/* Double buffering is always enabled for isochronous endpoints, and
although we overlap the two buffers for simplicity, we still need
to write to the right counter. The DTOG_TX bit indicates the buffer
that is currently in use by the USB peripheral, that is, the buffer
from which the next packet will be sent, so we need to write the
counter of that buffer.*/
USB_GET_DESCRIPTOR(ep)->TXCOUNT0 = (stm32_usb_pma_t)n;
if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX))
USB_GET_DESCRIPTOR(ep)->TXCOUNT1 = (stm32_usb_pma_t)n;
if (epcp->in_state->txqueued)
usb_packet_write_from_queue(USB_GET_DESCRIPTOR(ep),
epcp->in_state->mode.queue.txqueue,
@ -405,7 +425,17 @@ OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
}
else {
stm32_usb_descriptor_t *udp = USB_GET_DESCRIPTOR(ep);
/* Double buffering is always enabled for isochronous endpoints, and
although we overlap the two buffers for simplicity, we still need
to read from the right counter. The DTOG_RX bit indicates the buffer
that is currently in use by the USB peripheral, that is, the buffer
in which the next received packet will be stored, so we need to
read the counter of the OTHER buffer, which is where the last
received packet was stored.*/
n = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK;
if (EPR_EP_TYPE_IS_ISO(epr) && !(epr & EPR_DTOG_RX))
n = (size_t)udp->RXCOUNT1 & RXCOUNT_COUNT_MASK;
/* Reads the packet into the defined buffer.*/
if (epcp->out_state->rxqueued)
@ -418,6 +448,7 @@ OSAL_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
n);
epcp->out_state->mode.linear.rxbuf += n;
}
/* Transaction data updated.*/
epcp->out_state->rxcnt += n;
epcp->out_state->rxsize -= n;
@ -569,9 +600,13 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
stm32_usb_descriptor_t *dp;
const USBEndpointConfig *epcp = usbp->epc[ep];
/* Setting the endpoint type.*/
/* Setting the endpoint type. Note that isochronous endpoints cannot be
bidirectional because it uses double buffering and both transmit and
receive descriptor fields are used for either direction.*/
switch (epcp->ep_mode & USB_EP_MODE_TYPE) {
case USB_EP_MODE_TYPE_ISOC:
osalDbgAssert((epcp->in_cb == NULL) || (epcp->out_cb == NULL),
"isochronous EP cannot be IN and OUT");
epr = EPR_EP_TYPE_ISO;
break;
case USB_EP_MODE_TYPE_BULK:
@ -584,29 +619,48 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
epr = EPR_EP_TYPE_CONTROL;
}
/* IN endpoint initially in NAK mode.*/
if (epcp->in_cb != NULL)
epr |= EPR_STAT_TX_NAK;
/* OUT endpoint initially in NAK mode.*/
if (epcp->out_cb != NULL)
epr |= EPR_STAT_RX_NAK;
/* EPxR register setup.*/
EPR_SET(ep, epr | ep);
EPR_TOGGLE(ep, epr);
/* Endpoint size and address initialization.*/
if (epcp->out_maxsize > 62)
nblocks = (((((epcp->out_maxsize - 1) | 0x1f) + 1) / 32) << 10) |
0x8000;
else
nblocks = ((((epcp->out_maxsize - 1) | 1) + 1) / 2) << 10;
dp = USB_GET_DESCRIPTOR(ep);
dp->TXCOUNT0 = 0;
dp->RXCOUNT0 = nblocks;
dp->TXADDR0 = usb_pm_alloc(usbp, epcp->in_maxsize);
dp->RXADDR0 = usb_pm_alloc(usbp, epcp->out_maxsize);
/* Initial status for isochronous enpoints is valid because disabled and
valid are the only legal values. Also since double buffering is used
we need to initialize both count/address sets depending on the direction,
but since we are not taking advantage of the double buffering, we set both
addresses to point to the same PMA.*/
if ((epcp->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) {
if (epcp->in_cb != NULL) {
epr |= EPR_STAT_TX_VALID;
dp->TXCOUNT1 = dp->TXCOUNT0;
dp->TXADDR1 = dp->TXADDR0; /* Both buffers overlapped.*/
}
if (epcp->out_cb != NULL) {
epr |= EPR_STAT_RX_VALID;
dp->RXCOUNT1 = dp->RXCOUNT0;
dp->RXADDR1 = dp->RXADDR0; /* Both buffers overlapped.*/
}
}
else {
/* Initial status for other endpoint types is NAK.*/
if (epcp->in_cb != NULL)
epr |= EPR_STAT_TX_NAK;
if (epcp->out_cb != NULL)
epr |= EPR_STAT_RX_NAK;
}
/* EPxR register setup.*/
EPR_SET(ep, epr | ep);
EPR_TOGGLE(ep, epr);
}
/**
@ -737,12 +791,23 @@ void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep) {
void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) {
size_t n;
USBInEndpointState *isp = usbp->epc[ep]->in_state;
uint32_t epr = STM32_USB->EPR[ep];
/* Transfer initialization.*/
n = isp->txsize;
if (n > (size_t)usbp->epc[ep]->in_maxsize)
n = (size_t)usbp->epc[ep]->in_maxsize;
/* Double buffering is always enabled for isochronous endpoints, and
although we overlap the two buffers for simplicity, we still need
to write to the right counter. The DTOG_TX bit indicates the buffer
that is currently in use by the USB peripheral, that is, the buffer
from which the next packet will be sent, so we need to write the
counter of that buffer.*/
USB_GET_DESCRIPTOR(ep)->TXCOUNT0 = (stm32_usb_pma_t)n;
if (EPR_EP_TYPE_IS_ISO(epr) && (epr & EPR_DTOG_TX))
USB_GET_DESCRIPTOR(ep)->TXCOUNT1 = (stm32_usb_pma_t)n;
if (isp->txqueued)
usb_packet_write_from_queue(USB_GET_DESCRIPTOR(ep),
isp->mode.queue.txqueue, n);

View File

@ -144,6 +144,8 @@
(backported to 3.0.3).
- HAL: Fixed RTC module loses day of week when converting (bug #664)
(backported to 3.0.3).
- HAL: Fixed STM32 USBv1 broken isochronous endpoints (bug #662)
(backported to 3.0.4).
- HAL: Fixed STM32 USBv1 wrong multiplier when calculating descriptor address
in BTABLE (bug #661)(backported to 3.0.4 and 2.6.10).
- HAL: Fixed STM32 USBv1 does not make use of BTABLE_ADDR define (bug #660)