2
2
3
3
/* Copyright (c) 2010, Peter Barrett
4
4
**
5
+ ** Sleep/Wakeup/SystemControl support added by Michael Dreher
6
+ **
5
7
** Permission to use, copy, modify, and/or distribute this software for
6
8
** any purpose with or without fee is hereby granted, provided that the
7
9
** above copyright notice and this permission notice appear in all copies.
20
22
21
23
#if defined(USBCON)
22
24
23
- #define EP_TYPE_CONTROL 0x00
24
- #define EP_TYPE_BULK_IN 0x81
25
- #define EP_TYPE_BULK_OUT 0x80
26
- #define EP_TYPE_INTERRUPT_IN 0xC1
27
- #define EP_TYPE_INTERRUPT_OUT 0xC0
28
- #define EP_TYPE_ISOCHRONOUS_IN 0x41
29
- #define EP_TYPE_ISOCHRONOUS_OUT 0x40
25
+ #define EP_TYPE_CONTROL ( 0x00 )
26
+ #define EP_TYPE_BULK_IN (( 1 <<EPTYPE1) | ( 1 <<EPDIR))
27
+ #define EP_TYPE_BULK_OUT ( 1 <<EPTYPE1)
28
+ #define EP_TYPE_INTERRUPT_IN (( 1 <<EPTYPE1) | ( 1 <<EPTYPE0) | ( 1 <<EPDIR))
29
+ #define EP_TYPE_INTERRUPT_OUT (( 1 <<EPTYPE1) | ( 1 <<EPTYPE0))
30
+ #define EP_TYPE_ISOCHRONOUS_IN (( 1 <<EPTYPE0) | ( 1 <<EPDIR))
31
+ #define EP_TYPE_ISOCHRONOUS_OUT ( 1 <<EPTYPE0)
30
32
31
33
/* * Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
32
34
#define TX_RX_LED_PULSE_MS 100
@@ -89,6 +91,8 @@ const DeviceDescriptor USB_DeviceDescriptorA =
89
91
// ==================================================================
90
92
91
93
volatile u8 _usbConfiguration = 0 ;
94
+ volatile u8 _usbCurrentStatus = 0 ; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device
95
+ volatile u8 _usbSuspendState = 0 ; // copy of UDINT to check SUSPI and WAKEUPI bits
92
96
93
97
static inline void WaitIN (void )
94
98
{
@@ -340,7 +344,7 @@ static
340
344
void InitEP (u8 index, u8 type, u8 size)
341
345
{
342
346
UENUM = index ;
343
- UECONX = 1 ;
347
+ UECONX = ( 1 <<EPEN) ;
344
348
UECFG0X = type;
345
349
UECFG1X = size;
346
350
}
@@ -351,7 +355,7 @@ void InitEndpoints()
351
355
for (u8 i = 1 ; i < sizeof (_initEndpoints); i++)
352
356
{
353
357
UENUM = i;
354
- UECONX = 1 ;
358
+ UECONX = ( 1 <<EPEN) ;
355
359
UECFG0X = pgm_read_byte (_initEndpoints+i);
356
360
UECFG1X = EP_DOUBLE_64;
357
361
}
@@ -544,16 +548,37 @@ ISR(USB_COM_vect)
544
548
{
545
549
// Standard Requests
546
550
u8 r = setup.bRequest ;
551
+ u16 wValue = setup.wValueL | (setup.wValueH << 8 );
547
552
if (GET_STATUS == r)
548
553
{
549
- Send8 (0 ); // TODO
550
- Send8 (0 );
554
+ if (requestType == (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_DEVICE))
555
+ {
556
+ Send8 (_usbCurrentStatus);
557
+ Send8 (0 );
558
+ }
559
+ else
560
+ {
561
+ // TODO: handle the HALT state of an endpoint here
562
+ // see "Figure 9-6. Information Returned by a GetStatus() Request to an Endpoint" in usb_20.pdf for more information
563
+ Send8 (0 );
564
+ Send8 (0 );
565
+ }
551
566
}
552
567
else if (CLEAR_FEATURE == r)
553
568
{
569
+ if ((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE))
570
+ && (wValue == DEVICE_REMOTE_WAKEUP))
571
+ {
572
+ _usbCurrentStatus &= ~FEATURE_REMOTE_WAKEUP_ENABLED;
573
+ }
554
574
}
555
575
else if (SET_FEATURE == r)
556
576
{
577
+ if ((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE))
578
+ && (wValue == DEVICE_REMOTE_WAKEUP))
579
+ {
580
+ _usbCurrentStatus |= FEATURE_REMOTE_WAKEUP_ENABLED;
581
+ }
557
582
}
558
583
else if (SET_ADDRESS == r)
559
584
{
@@ -609,11 +634,74 @@ void USB_Flush(u8 ep)
609
634
ReleaseTX ();
610
635
}
611
636
637
+ static inline void USB_ClockDisable ()
638
+ {
639
+ USBCON = (USBCON & ~(1 <<OTGPADE)) | (1 <<FRZCLK); // freeze clock and disable VBUS Pad
640
+ PLLCSR &= ~(1 <<PLLE); // stop PLL
641
+ }
642
+
643
+ static inline void USB_ClockEnable ()
644
+ {
645
+ UHWCON |= (1 <<UVREGE); // power internal reg
646
+ USBCON = (1 <<USBE) | (1 <<FRZCLK); // clock frozen, usb enabled
647
+
648
+ // ATmega32U4
649
+ #if defined(PINDIV)
650
+ #if F_CPU == 16000000UL
651
+ PLLCSR |= (1 <<PINDIV); // Need 16 MHz xtal
652
+ #elif F_CPU == 8000000UL
653
+ PLLCSR &= ~(1 <<PINDIV); // Need 8 MHz xtal
654
+ #else
655
+ #error "Clock rate of F_CPU not supported"
656
+ #endif
657
+
658
+ // AT90USB646, AT90USB647, AT90USB1286, AT90USB1287
659
+ #elif defined(PLLP2)
660
+ #if F_CPU == 16000000UL
661
+ #if defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
662
+ // For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x.
663
+ PLLCSR = (PLLCSR & ~(1 <<PLLP1)) | ((1 <<PLLP2) | (1 <<PLLP0)); // Need 16 MHz xtal
664
+ #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
665
+ // For AT90USB64x only. Do not use with AT90USB128x.
666
+ PLLCSR = (PLLCSR & ~(1 <<PLLP0)) | ((1 <<PLLP2) | (1 <<PLLP1)); // Need 16 MHz xtal
667
+ #else
668
+ #error "USB Chip not supported, please defined method of USB PLL initialization"
669
+ #endif
670
+ #elif F_CPU == 8000000UL
671
+ // for Atmel AT90USB128x and AT90USB64x
672
+ PLLCSR = (PLLCSR & ~(1 <<PLLP2)) | ((1 <<PLLP1) | (1 <<PLLP0)); // Need 8 MHz xtal
673
+ #else
674
+ #error "Clock rate of F_CPU not supported"
675
+ #endif
676
+ #else
677
+ #error "USB Chip not supported, please defined method of USB PLL initialization"
678
+ #endif
679
+
680
+ PLLCSR |= (1 <<PLLE);
681
+ while (!(PLLCSR & (1 <<PLOCK))) // wait for lock pll
682
+ {
683
+ }
684
+
685
+ // Some tests on specific versions of macosx (10.7.3), reported some
686
+ // strange behaviuors when the board is reset using the serial
687
+ // port touch at 1200 bps. This delay fixes this behaviour.
688
+ delay (1 );
689
+ USBCON = (USBCON & ~(1 <<FRZCLK)) | (1 <<OTGPADE); // start USB clock, enable VBUS Pad
690
+
691
+ #if defined(RSTCPU)
692
+ UDCON &= ~((1 <<RSTCPU) | (1 <<LSM) | (1 <<RMWKUP) | (1 <<DETACH)); // enable attach resistor, set full speed mode
693
+ #else
694
+ // AT90USB64x and AT90USB128x don't have RSTCPU
695
+ UDCON &= ~((1 <<LSM) | (1 <<RMWKUP) | (1 <<DETACH)); // enable attach resistor, set full speed mode
696
+ #endif
697
+ }
698
+
699
+
612
700
// General interrupt
613
701
ISR (USB_GEN_vect)
614
702
{
615
703
u8 udint = UDINT;
616
- UDINT = 0 ;
704
+ UDINT &= ~(( 1 <<EORSTI) | ( 1 <<SOFI)); // clear the IRQ flags for the IRQs which are handled here, except WAKEUPI and SUSPI (see below)
617
705
618
706
// End of Reset
619
707
if (udint & (1 <<EORSTI))
@@ -636,6 +724,30 @@ ISR(USB_GEN_vect)
636
724
if (RxLEDPulse && !(--RxLEDPulse))
637
725
RXLED0;
638
726
}
727
+
728
+ // the WAKEUPI interrupt is triggered as soon as there are non-idle patterns on the data
729
+ // lines. Thus, the WAKEUPI interrupt can occur even if the controller is not in the "suspend" mode.
730
+ // Therefore the we enable it only when USB is suspended
731
+ if (udint & (1 <<WAKEUPI))
732
+ {
733
+ UDIEN = (UDIEN & ~(1 <<WAKEUPE)) | (1 <<SUSPE); // Disable interrupts for WAKEUP and enable interrupts for SUSPEND
734
+
735
+ // TODO
736
+ // WAKEUPI shall be cleared by software (USB clock inputs must be enabled before).
737
+ // USB_ClockEnable();
738
+ UDINT &= ~(1 <<WAKEUPI);
739
+ _usbSuspendState = (_usbSuspendState & ~(1 <<SUSPI)) | (1 <<WAKEUPI);
740
+ }
741
+ else if (udint & (1 <<SUSPI)) // only one of the WAKEUPI / SUSPI bits can be active at time
742
+ {
743
+ UDIEN = (UDIEN & ~(1 <<SUSPE)) | (1 <<WAKEUPE); // Disable interrupts for SUSPEND and enable interrupts for WAKEUP
744
+
745
+ // TODO
746
+ // USB_ClockDisable();
747
+
748
+ UDINT &= ~((1 <<WAKEUPI) | (1 <<SUSPI)); // clear any already pending WAKEUP IRQs and the SUSPI request
749
+ _usbSuspendState = (_usbSuspendState & ~(1 <<WAKEUPI)) | (1 <<SUSPI);
750
+ }
639
751
}
640
752
641
753
// VBUS or counting frames
@@ -659,24 +771,12 @@ USBDevice_::USBDevice_()
659
771
void USBDevice_::attach ()
660
772
{
661
773
_usbConfiguration = 0 ;
662
- UHWCON = 0x01 ; // power internal reg
663
- USBCON = (1 <<USBE)|(1 <<FRZCLK); // clock frozen, usb enabled
664
- #if F_CPU == 16000000UL
665
- PLLCSR = 0x12 ; // Need 16 MHz xtal
666
- #elif F_CPU == 8000000UL
667
- PLLCSR = 0x02 ; // Need 8 MHz xtal
668
- #endif
669
- while (!(PLLCSR & (1 <<PLOCK))) // wait for lock pll
670
- ;
774
+ _usbCurrentStatus = 0 ;
775
+ _usbSuspendState = 0 ;
776
+ USB_ClockEnable ();
671
777
672
- // Some tests on specific versions of macosx (10.7.3), reported some
673
- // strange behaviuors when the board is reset using the serial
674
- // port touch at 1200 bps. This delay fixes this behaviour.
675
- delay (1 );
676
-
677
- USBCON = ((1 <<USBE)|(1 <<OTGPADE)); // start USB clock
678
- UDIEN = (1 <<EORSTE)|(1 <<SOFE); // Enable interrupts for EOR (End of Reset) and SOF (start of frame)
679
- UDCON = 0 ; // enable attach resistor
778
+ UDINT &= ~((1 <<WAKEUPI) | (1 <<SUSPI)); // clear already pending WAKEUP / SUSPEND requests
779
+ UDIEN = (1 <<EORSTE) | (1 <<SOFE) | (1 <<SUSPE); // Enable interrupts for EOR (End of Reset), SOF (start of frame) and SUSPEND
680
780
681
781
TX_RX_LED_INIT;
682
782
}
@@ -696,4 +796,25 @@ void USBDevice_::poll()
696
796
{
697
797
}
698
798
799
+
800
+ bool USBDevice_::wakeupHost ()
801
+ {
802
+ // clear any previous wakeup request which might have been set but could be processed at that time
803
+ // e.g. because the host was not suspended at that time
804
+ UDCON &= ~(1 << RMWKUP);
805
+
806
+ if (!(UDCON & (1 << RMWKUP))
807
+ && (_usbSuspendState & (1 <<SUSPI))
808
+ && (_usbCurrentStatus & FEATURE_REMOTE_WAKEUP_ENABLED))
809
+ {
810
+ // This short version will only work, when the device has not been suspended. Currently the
811
+ // Arduino core doesn't handle SUSPEND at all, so this is ok.
812
+ USB_ClockEnable ();
813
+ UDCON |= (1 << RMWKUP); // send the wakeup request
814
+ return true ;
815
+ }
816
+
817
+ return false ;
818
+ }
819
+
699
820
#endif /* if defined(USBCON) */
0 commit comments