Merge pull request #289 from elfmimi/nuc123-usb-workaround

NUMICRO: Workaround for NUC123 USB Endpoint 6 problem
This commit is contained in:
Alex Lewontin 2021-09-03 19:41:08 -07:00 committed by GitHub
commit 5935e97262
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 21 deletions

View File

@ -1,5 +1,6 @@
/* /*
Copyright (C) 2020 Alex Lewontin Copyright (C) 2020 Alex Lewontin
Copyright (C) 2021 Ein Terakawa
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -47,6 +48,13 @@
* abandoned, and some more sophisticated scheme for allocating hardware * abandoned, and some more sophisticated scheme for allocating hardware
* endpoints adopted. * endpoints adopted.
*/ */
/*
* Solution to overcome the above mentioned shortcoming has been found.
* That is to map Control-IN to endpoint 5 and Control-OUT to endpoint 6.
* It is safe to assume interrupts for Control-IN and Control-OUT are not going
* to occur at the same time. Because control transfers do not overwrap.
* Other endpoints 0 1 2 3 4 and 7 can be assigned in whatever combination.
*/
#if HAL_USE_USB || defined(__DOXYGEN__) #if HAL_USE_USB || defined(__DOXYGEN__)
@ -54,7 +62,7 @@
/* Driver local definitions. */ /* Driver local definitions. */
/*===========================================================================*/ /*===========================================================================*/
#define NUC123_USB_HW_ENDPOINTS 6 #define NUC123_USB_HW_ENDPOINTS 8
#define NUC123_USBD_CFG_OUT (1UL << USBD_CFG_STATE_Pos) #define NUC123_USBD_CFG_OUT (1UL << USBD_CFG_STATE_Pos)
#define NUC123_USBD_CFG_IN (2UL << USBD_CFG_STATE_Pos) #define NUC123_USBD_CFG_IN (2UL << USBD_CFG_STATE_Pos)
@ -136,12 +144,27 @@ static uint32_t sram_free_dword_offset = 1UL;
* @name Endpoint number convenience macros * @name Endpoint number convenience macros
* @{ * @{
*/ */
#define HW_OUT_EPN(lepn) (2 * (lepn)) #if NUC123_USB_WORKAROUND
#define HW_IN_EPN(lepn) (HW_OUT_EPN(lepn) + 1) // As work-around we map Control-OUT to EP6 and Control-IN to EP5 .
#define HW_EP(hwepn) ((USBD->EP) + (hwepn)) #define _HW_OUT_EPN(lepn) (2 * (((lepn)+3)%4))
#define HW_OUT_EP(lepn) (HW_EP(HW_OUT_EPN(lepn))) #define _HW_IN_EPN(lepn) ((2 * (((lepn)+2)%4))+1)
#define HW_IN_EP(lepn) (HW_EP(HW_IN_EPN(lepn))) #define LOGICAL_EPN(hwepn) ((((hwepn) + 3) / 2) % 4)
#else
#if defined(NUC123xxxANx)
// without workaround we use EP0 EP1 EP2 EP3 EP4 and EP7 for NUC123(AN)
#define _HW_OUT_EPN(lepn) (2 * (lepn))
#define _HW_IN_EPN(lepn) (2 * (((lepn)+3)%4) + 1)
#define LOGICAL_EPN(hwepn) (((hwepn)+1)%8 / 2)
#else
#define _HW_OUT_EPN(lepn) (2 * (lepn))
#define _HW_IN_EPN(lepn) (2 * (lepn) + 1)
#define LOGICAL_EPN(hwepn) ((hwepn) / 2) #define LOGICAL_EPN(hwepn) ((hwepn) / 2)
#endif
#endif
#define _HW_EP(hwepn) ((USBD->EP) + (hwepn))
#define HW_OUT_EP(lepn) (_HW_EP(_HW_OUT_EPN(lepn)))
#define HW_IN_EP(lepn) (_HW_EP(_HW_IN_EPN(lepn)))
/** @} */ /** @} */
/** /**
@ -322,53 +345,60 @@ static void usb_lld_serve_interrupt(USBDriver* usbp)
if (intsts & USBD_INTSTS_EPEVT0_Msk) { if (intsts & USBD_INTSTS_EPEVT0_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = USBD_INTSTS_EPEVT0_Msk; USBD->INTSTS = USBD_INTSTS_EPEVT0_Msk;
usb_serve_out_endpoint(LOGICAL_EPN(0));
usb_serve_out_endpoint(0);
} }
if (intsts & USBD_INTSTS_EPEVT1_Msk) { if (intsts & USBD_INTSTS_EPEVT1_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT1_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT1_Msk);
usb_serve_in_endpoint(LOGICAL_EPN(1));
usb_serve_in_endpoint(0);
} }
if (intsts & USBD_INTSTS_EPEVT2_Msk) { if (intsts & USBD_INTSTS_EPEVT2_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT2_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT2_Msk);
usb_serve_out_endpoint(1); usb_serve_out_endpoint(LOGICAL_EPN(2));
} }
if (intsts & USBD_INTSTS_EPEVT3_Msk) { if (intsts & USBD_INTSTS_EPEVT3_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT3_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT3_Msk);
usb_serve_in_endpoint(1); usb_serve_in_endpoint(LOGICAL_EPN(3));
} }
if (intsts & USBD_INTSTS_EPEVT4_Msk) { if (intsts & USBD_INTSTS_EPEVT4_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT4_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT4_Msk);
usb_serve_out_endpoint(2); usb_serve_out_endpoint(LOGICAL_EPN(4));
} }
#if NUC123_USB_WORKAROUND
if (intsts & USBD_INTSTS_EPEVT5_Msk) { if (intsts & USBD_INTSTS_EPEVT5_Msk) {
/* Clear event flag */ /* Clear event flag */
/* TODO: when the EP5/6 confusion bug is resolved, remove the EP6 mask here */ /* in NUC123(AN) EP5-IN event also false triggers EP6 */
USBD->INTSTS = (USBD_INTSTS_EPEVT5_Msk | USBD_INTSTS_EPEVT6_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT5_Msk | USBD_INTSTS_EPEVT6_Msk);
usb_serve_in_endpoint(2); usb_serve_in_endpoint(LOGICAL_EPN(5));
intsts &= ~USBD_INTSTS_EPEVT6_Msk;
} }
#else
if (intsts & USBD_INTSTS_EPEVT5_Msk) {
/* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT5_Msk);
usb_serve_in_endpoint(LOGICAL_EPN(5));
}
#endif
#if 0 #if NUC123_USB_HW_ENDPOINTS > 6
if (intsts & USBD_INTSTS_EPEVT6_Msk) { if (intsts & USBD_INTSTS_EPEVT6_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT6_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT6_Msk);
usb_serve_out_endpoint(3); usb_serve_out_endpoint(LOGICAL_EPN(6));
} }
if (intsts & USBD_INTSTS_EPEVT7_Msk) { if (intsts & USBD_INTSTS_EPEVT7_Msk) {
/* Clear event flag */ /* Clear event flag */
USBD->INTSTS = (USBD_INTSTS_EPEVT7_Msk); USBD->INTSTS = (USBD_INTSTS_EPEVT7_Msk);
usb_serve_in_endpoint(3); usb_serve_in_endpoint(LOGICAL_EPN(7));
} }
#endif #endif
} }
@ -605,9 +635,11 @@ void usb_lld_init_endpoint(USBDriver* usbp, usbep_t ep)
*/ */
void usb_lld_disable_endpoints(USBDriver* usbp) void usb_lld_disable_endpoints(USBDriver* usbp)
{ {
for (uint8_t i = 2; i < NUC123_USB_HW_ENDPOINTS; ++i) { for (uint8_t i = 0; i < NUC123_USB_HW_ENDPOINTS; ++i) {
USBD->EP[i].CFGP |= USBD_CFGP_CLRRDY_Msk; if (LOGICAL_EPN(i) != 0) {
USBD->EP[i].CFG &= ~USBD_CFG_STATE_Msk; USBD->EP[i].CFGP |= USBD_CFGP_CLRRDY_Msk;
USBD->EP[i].CFG &= ~USBD_CFG_STATE_Msk;
}
} }
sram_free_dword_offset = 1UL + sram_free_dword_offset = 1UL +

View File

@ -1,5 +1,6 @@
/* /*
Copyright (C) 2020 Alex Lewontin Copyright (C) 2020 Alex Lewontin
Copyright (C) 2021 Ein Terakawa
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -35,7 +36,15 @@
* @brief Maximum endpoint address. * @brief Maximum endpoint address.
* @details This value does not include the endpoint 0 which is always present. * @details This value does not include the endpoint 0 which is always present.
*/ */
#if defined(NUC123xxxANx)
#if NUC123_USB_WORKAROUND
#define USB_MAX_ENDPOINTS 3
#else
#define USB_MAX_ENDPOINTS 2 #define USB_MAX_ENDPOINTS 2
#endif
#else
#define USB_MAX_ENDPOINTS 3
#endif
/** /**
* @brief Status stage handling method. * @brief Status stage handling method.