diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/SoundCard.ino b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/SoundCard.ino new file mode 100644 index 00000000..1c4e457e --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/SoundCard.ino @@ -0,0 +1,41 @@ +/* + USB sound card example + + created 2024 + by Deqing Sun for use with CH55xduino + + CH552 act as mono 24000K sound card + playback high 8bit on P3.4 + + Improved from ziv2013's work + + This example code is in the public domain. + + cli board options: usb_settings=user148 + +*/ + +#ifndef USER_USB_RAM +#error "This example needs to be compiled with a USER USB setting" +#endif + +#include "src/USBAudioSpeaker/USBAudioSpeaker.h" + +void setup() { + + USBInit(); + + // PWM2 is on P3.4 + pinMode(34, OUTPUT); + // turn on PWM2 + PIN_FUNC &= ~(bPWM2_PIN_X); + // Set PWM to Fsys/256 with 1 divider + PWM_CK_SE = 1; + PWM_CTRL |= bPWM2_OUT_EN; + PWM_DATA2 = 128; +} + + +void loop() { + +} diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBAudioSpeaker.c b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBAudioSpeaker.c new file mode 100644 index 00000000..8fd973a0 --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBAudioSpeaker.c @@ -0,0 +1,155 @@ +// clang-format off +#include +#include +#include +#include "include/ch5xx.h" +#include "include/ch5xx_usb.h" +#include "USBconstant.h" +#include "USBhandler.h" +#include "USBAudioSpeaker.h" +// clang-format on + +__xdata volatile uint8_t soundBufferPlayBackIndex = 0; + +#define T2_RELOAD_VALUE (65536 - F_CPU / 24000) +#define T2_RELOAD_VALUE_LOW (T2_RELOAD_VALUE & 0xFF) +#define T2_RELOAD_VALUE_HIGH ((T2_RELOAD_VALUE >> 8) & 0xFF) +#define T2_RELOAD_VALUE_NEAR_FINISH (65536 - F_CPU / 24000 / 4) +#define T2_RELOAD_VALUE_NEAR_FINISH_LOW (T2_RELOAD_VALUE_NEAR_FINISH & 0xFF) +#define T2_RELOAD_VALUE_NEAR_FINISH_HIGH \ + ((T2_RELOAD_VALUE_NEAR_FINISH >> 8) & 0xFF) + +void Timer2Interrupt(void) __interrupt { + // if (TF2) { + // TF2 = 0; + // __data signed char highByteOfPCM = + // Ep1Buffer[(soundBufferPlayBackIndex<<1)+1]; + // __data unsigned char highByteOfPCMUnsigned = highByteOfPCM+128; + + // PWM_CTRL |= bPWM_IF_END; + // while (!(PWM_CTRL & bPWM_IF_END)); + // PWM_DATA2 = highByteOfPCMUnsigned; + // soundBufferPlayBackIndex++; + // } + + // due to PWM bug, https://github.com/DeqingSun/ch55xduino/issues/135 + // we need to carefully handle the PWM data + // and SDCC is not good at handling partial inline assembly. + // we just do everything in inline assembly. + __asm__(";check if TF2 is set \n" + " jb _TF2,notSkipTimer2INTR$ \n" + " sjmp skipTimer2INTR$ \n" + "notSkipTimer2INTR$: \n" + " clr _TF2 \n" + + ";get (soundBufferPlayBackIndex<<1)+1 \n" + ";also inc soundBufferPlayBackIndex \n" + " mov dptr,#_soundBufferPlayBackIndex \n" + " movx a,@dptr \n" + " mov r7,a \n" + ";check if soundBufferPlayBackIndex is too big \n" + " add a,#232 \n" + " jnc soundBufferPlayBackIndexNotBig$ \n" + " sjmp skipTimer2INTR$ \n" + "soundBufferPlayBackIndexNotBig$: \n" + " mov a,r7 \n" + " inc a \n" + " movx @dptr,a \n" + " mov a,r7 \n" + " rl a \n" + " inc a \n" + + ";get Ep1Buffer[(soundBufferPlayBackIndex<<1)+1] \n" + " add a,#_Ep1Buffer \n" + " mov dpl,a \n" + " clr a \n" + " addc a,#(_Ep1Buffer >> 8) \n" + " mov dph,a \n" + " movx a,@dptr \n" + + ";add 128 for PWM \n" + " mov r7,a \n" + " mov a,#0x80 \n" + " add a,r7 \n" + " mov r7,a \n" + + ";load previous PWM \n" + " mov a,_PWM_DATA2 \n" + " add a,#232 \n" + " jnc previousPWMSmall$ \n" + ";if previous PWM was 20~25 \n" + ";we have chance to update PWM on the falling edge \n" + ";and that triggers bug of PWM \n" + ";so we just wait after falling in that case \n" + + ";previousPWM not Small, just set at beginning \n" + ";clear bPWM_IF_END \n" + " orl _PWM_CTRL,#0x10 \n" + ";wait for bPWM_IF_END \n" + "waitPWM_IF_END$: \n" + " mov a,_PWM_CTRL \n" + " jnb acc.4,waitPWM_IF_END$ \n" + " mov a,r7 \n" + " mov _PWM_DATA2,a \n" + " sjmp pwmSetFinish$ \n" + + "previousPWMSmall$: \n" + ";clear bPWM_IF_END \n" + " orl _PWM_CTRL,#0x10 \n" + ";wait for bPWM_IF_END \n" + "waitPWM_IF_END_small$: \n" + " mov a,_PWM_CTRL \n" + " jnb acc.4,waitPWM_IF_END_small$ \n" + " mov a,r7 \n" + " nop\n nop\n nop\n nop\n nop\n " + " nop\n nop\n nop\n nop\n nop\n " + " nop\n nop\n nop\n nop\n nop\n " + " nop\n nop\n nop\n nop\n nop\n " + " nop\n nop\n nop\n nop\n nop\n " + + " mov _PWM_DATA2,a \n" + + "pwmSetFinish$: \n" + + "skipTimer2INTR$: \n"); +} + +void USBInit() { + USBDeviceCfg(); // Device mode configuration + USBDeviceEndPointCfg(); // Endpoint configuration + USBDeviceIntCfg(); // Interrupt configuration + UEP0_T_LEN = 0; + UEP1_T_LEN = 0; // Pre-use send length must be cleared + + for (uint8_t i = 0; i < 48; i++) { + Ep1Buffer[i] = 0; + } + + T2CON = 0x00; + // bTMR_CLK may be set by uart0, we keep it as is. + T2MOD |= bTMR_CLK | bT2_CLK; // use Fsys for T2 + + TL2 = 0; + TH2 = 0; + RCAP2L = T2_RELOAD_VALUE_LOW; + RCAP2H = T2_RELOAD_VALUE_HIGH; + + ET2 = 1; + TR2 = 1; +} + +void AUDIO_EP1_Out(void) { + + // Force T2 interrupt to sync with the data received + TR2 = 0; + TF2 = 0; + // the last data will be played back during the new data is being received + // just make sure the last data is played back before the new last data is + // received + TL2 = T2_RELOAD_VALUE_NEAR_FINISH_LOW; + TH2 = T2_RELOAD_VALUE_NEAR_FINISH_HIGH; + soundBufferPlayBackIndex = 0; + TR2 = 1; + + UEP1_CTRL = UEP1_CTRL & ~MASK_UEP_T_RES | UEP_T_RES_TOUT; +} \ No newline at end of file diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBAudioSpeaker.h b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBAudioSpeaker.h new file mode 100644 index 00000000..728097ab --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBAudioSpeaker.h @@ -0,0 +1,23 @@ +#ifndef __USB_AUDIO_SPEAKER_H__ +#define __USB_AUDIO_SPEAKER_H__ + +// clang-format off +#include +#include "include/ch5xx.h" +#include "include/ch5xx_usb.h" +#include "USBhandler.h" +// clang-format on + +#ifdef __cplusplus +extern "C" { +#endif + +void USBInit(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +void AUDIO_EP1_Out(void); + +#endif diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBconstant.c b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBconstant.c new file mode 100644 index 00000000..28074902 --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBconstant.c @@ -0,0 +1,202 @@ +#include "USBconstant.h" + +// Device descriptor +__code uint8_t DevDesc[] = { + 0x12, // Descriptor size is 18 bytes + 0x01, // DEVICE Descriptor Type + 0x00, + 0x02, // USB Specification version 2.00 + 0x00, // Each interface specifies its own class information + 0x00, // Each interface specifies its own Subclass information + 0x00, // No protocols the device basis + DEFAULT_ENDP0_SIZE, // Maximum packet size for endpoint zero is 8 + 0x09, + 0x12, // Vendor ID + 0x5A, + 0xC5, // Product ID + 0x01, + 0x00, // The device release number is 0.01 + 0x01, // The manufacturer string descriptor index is 1 + 0x02, // The product string descriptor index is 2 + 0x00, // The device doesn't have the string descriptor describing the serial + // number + 0x01, // The device has 1 possible configurations +}; + +__code uint16_t DevDescLen = sizeof(DevDesc); + +__code uint8_t CfgDesc[] = { + 0x09, // Descriptor size is 9 bytes + 0x02, // CONFIGURATION Descriptor Type + sizeof(CfgDesc) & 0xff, + sizeof(CfgDesc) >> 8, // The total length of data for this configuration + 0x02, // This configuration supports 2 interfaces + 0x01, // The value 1 should be used to select this configuration + 0x00, // The device doesn't have the string descriptor describing this + // configuration + 0x80, // Configuration characteristics : Bit 7: Reserved (set to one) 1 Bit + // 6: Self-powered 1 Bit 5: Remote Wakeup 0 + 0x32, // Maximum power consumption of the device in this configuration is + // 100 mA + + 0x09, // Descriptor size is 9 bytes + 0x04, // INTERFACE Descriptor Type + 0x00, // The number of this interface is 0. + 0x00, // The value used to select the alternate setting for this interface + // is 0 + 0x00, // The number of endpoints used by this interface is 0 (excluding + // endpoint zero) + 0x01, // The interface implements the Audio Interface class + 0x01, // The interface implements the AUDIOCONTROL Subclass + 0x00, // The interface uses the IP_VERSION_01_00 Protocol + 0x00, // The device doesn't have a string descriptor describing this + // iInterface + + 0x09, // Size of the descriptor, in bytes + 0x24, // CS_INTERFACE Descriptor Type + 0x01, // HEADER descriptor subtype + 0x00, + 0x01, // Audio Device compliant to the USB Audio specification version 1.00 + 0x1E, + 0x00, // Total number of bytes returned for the class-specific AudioControl + // interface descriptor. Includes the combined length of this + // descriptor header and all Unit and Terminal descriptors. + 0x01, // The number of AudioStreaming and MIDIStreaming interfaces in the + // Audio Interface Collection to which this AudioControl interface + // belongs + 0x01, // Interface number of the AudioStreaming or MIDIStreaming interface + // in the Collection + + 0x0C, // Size of the descriptor, in bytes + 0x24, // CS_INTERFACE Descriptor Type + 0x02, // INPUT_TERMINAL descriptor subtype + 0x01, // Constant uniquely identifying the Terminal within the audio + // function. This value is used in all requests to address this + // Terminal. + 0x01, + 0x01, // A Terminal dealing with a signal carried over an endpoint in an + // AudioStreaming interface. The AudioStreaming interface descriptor + // points to the associated Terminal through the bTerminalLink field. + 0x00, // This Input Terminal has no association + 0x01, // This Terminal's output audio channel cluster has 1 logical output + // channels + 0x04, 0x00, // Spatial locations present in the cluster + // Bit 0: Left Front 1 + // Bit 1: Right Front 1 + // Bit 2: Center Front 0 + // Bit 3: Low Freq Enh 0 + // Bit 4: Left Surround 0 + // Bit 5: Right Surround 0 + // Bit 6: Left of Center 0 + // Bit 7: Right of Center 0 + // Bit 8: Surround 0 + // Bit 9: ... + 0x00, // Index of a string descriptor, describing the name of the first + // logical channel. + 0x00, // Index of a string descriptor, describing the Input Terminal. + + 0x09, // Size of the descriptor, in bytes + 0x24, // CS_INTERFACE Descriptor Type + 0x03, // OUTPUT_TERMINAL descriptor subtype + 0x02, // Constant uniquely identifying the Terminal within the audio + // function. This value is used in all requests to address this + // Terminal. + 0x01, 0x03, // A generic speaker or set of speakers that does not fit under + // any of the other classifications. + 0x00, // This Output Terminal has no association + 0x01, // ID of the Unit or Terminal to which this Terminal is connected. + 0x00, // Index of a string descriptor, describing the Output Terminal. + + 0x09, // Descriptor size is 9 bytes + 0x04, // INTERFACE Descriptor Type + 0x01, // The number of this interface is 1. + 0x00, // The value used to select the alternate setting for this interface + // is 0 + 0x00, // The number of endpoints used by this interface is 0 (excluding + // endpoint zero) + 0x01, // The interface implements the Audio Interface class + 0x02, // The interface implements the AUDIOSTREAMING Subclass + 0x00, // The interface uses the IP_VERSION_01_00 Protocol + 0x00, // The device doesn't have a string descriptor describing this + // iInterface + + 0x09, // Descriptor size is 9 bytes + 0x04, // INTERFACE Descriptor Type + 0x01, // The number of this interface is 1. + 0x01, // The value used to select the alternate setting for this interface + // is 1 + 0x01, // The number of endpoints used by this interface is 1 (excluding + // endpoint zero) + 0x01, // The interface implements the Audio Interface class + 0x02, // The interface implements the AUDIOSTREAMING Subclass + 0x00, // The interface uses the IP_VERSION_01_00 Protocol + 0x00, // The device doesn't have a string descriptor describing this + // iInterface + + 0x07, // Size of the descriptor, in bytes + 0x24, // CS_INTERFACE Descriptor Type + 0x01, // AS_GENERAL descriptor subtype + 0x01, // The Terminal ID of the Terminal to which the endpoint of this + // interface is connected. + 0x01, // Delay introduced by the data path. Expressed in number of frames. + 0x01, 0x00, // PCM. It seems PCM8 is not supported. + + 0x0B, // Size of the descriptor, in bytes + 0x24, // CS_INTERFACE Descriptor Type + 0x02, // FORMAT_TYPE descriptor subtype + 0x01, // FORMAT_TYPE_I + 0x01, // Indicates the number of physical channels in the audio data stream. + 0x02, // The number of bytes occupied by one audio subframe. Can be 1, 2, 3 + // or 4. + 0x10, // The number of effectively used bits from the available bits in an + // audio subframe. + 0x01, // Indicates how the sampling frequency can be programmed: + 0xC0, 0x5D, 0x00, // Sampling frequency 24000 in Hz for this + //isochronous data endpoint. + + 0x09, // Descriptor size is 9 bytes + 0x05, // ENDPOINT Descriptor Type + 0x01, // This is an OUT endpoint with endpoint number 1 + 0x0D, // Types - + // Transfer: ISOCHRONOUS + // Sync: Sync + // Usage: Data EP + 0x40, 0x00, // Maximum packet size for this endpoint is 64 Bytes. If + // Hi-Speed, 0 additional transactions per frame + 0x01, // The polling interval value is every 1 Frames. If Hi-Speed, 1 + // uFrames/NAK + 0x00, // Refresh Rate 2**n ms where n = 0 + 0x00, // Synchronization Endpoint (if used) is endpoint 0 + + 0x07, // Size of the descriptor, in bytes + 0x25, // CS_ENDPOINT Descriptor Type + 0x01, // AUDIO_EP_GENERAL descriptor subtype + 0x00, // Bit 0: Sampling Frequency 0 + // Bit 1: Pitch 0 + // Bit 7: MaxPacketsOnly 0 + 0x00, // Indicates the units used for the wLockDelay field: 0: Undefined + 0x00, 0x00 // Indicates the time it takes this endpoint to reliably lock its + // internal clock recovery circuitry. Units used depend on the + // value of the bLockDelayUnits field. + +}; + +__code uint16_t CfgDescLen = sizeof(CfgDesc); + +// String Descriptors +__code uint8_t LangDes[] = {0x04, 0x03, 0x09, 0x04}; // Language Descriptor +__code uint16_t LangDesLen = sizeof(LangDes); +__code uint8_t SerDes[] = { // Serial String Descriptor + 0x0C, 0x03, 'C', 0x00, 'H', 0x00, '5', 0x00, '5', 0x00, 'x', 0x00}; +__code uint16_t SerDesLen = sizeof(SerDes); +__code uint8_t Prod_Des[] = { // Produce String Descriptor + 0x22, 0x03, 'C', 0x00, 'H', 0x00, '5', 0x00, '5', 0x00, 'x', 0x00, + 'd', 0x00, 'u', 0x00, 'i', 0x00, 'n', 0x00, 'o', 0x00, ' ', 0x00, + 'A', 0x00, 'u', 0x00, 'd', 0x00, 'i', 0x00, 'o', 0x00}; +__code uint16_t Prod_DesLen = sizeof(Prod_Des); + +__code uint8_t Manuf_Des[] = { + 0x0E, 0x03, 'D', 0x00, 'e', 0x00, 'q', + 0x00, 'i', 0x00, 'n', 0x00, 'g', 0x00, +}; +__code uint16_t Manuf_DesLen = sizeof(Manuf_Des); diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBconstant.h b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBconstant.h new file mode 100644 index 00000000..5a4e0598 --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBconstant.h @@ -0,0 +1,32 @@ +#ifndef __CONST_DATA_H__ +#define __CONST_DATA_H__ + +// clang-format off +#include +#include "include/ch5xx.h" +#include "include/ch5xx_usb.h" +// clang-format on + +#define EP0_ADDR 0 +#define EP1_ADDR 10 + +#define SET_CUR 0x01 + +extern __code uint8_t DevDesc[]; +extern __code uint8_t CfgDesc[]; +extern __code uint8_t LangDes[]; +extern __code uint8_t SerDes[]; +extern __code uint8_t Prod_Des[]; +extern __code uint8_t CDC_Des[]; +extern __code uint8_t WEBUSB_Des[]; +extern __code uint8_t Manuf_Des[]; + +extern __code uint16_t DevDescLen; +extern __code uint16_t CfgDescLen; +extern __code uint16_t LangDesLen; +extern __code uint16_t SerDesLen; +extern __code uint16_t Prod_DesLen; +extern __code uint16_t CDC_DesLen; +extern __code uint16_t Manuf_DesLen; + +#endif diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBhandler.c b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBhandler.c new file mode 100644 index 00000000..02ef318e --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBhandler.c @@ -0,0 +1,530 @@ +// clang-format off +#include +#include "USBhandler.h" +#include "USBconstant.h" +// clang-format on + +void AUDIO_EP1_Out(); + +// clang-format off +__xdata __at (EP0_ADDR) uint8_t Ep0Buffer[8]; +__xdata __at (EP1_ADDR) uint8_t Ep1Buffer[64]; +// clang-format on + +#if (EP1_ADDR + 128) > USER_USB_RAM +#error "This example needs more USB ram. Increase this setting in menu." +#endif + +__data uint16_t SetupLen; +__data uint8_t SetupReq; +volatile __xdata uint8_t UsbConfig; + +__code uint8_t *__data pDescr; + +inline void NOP_Process(void) {} + +void USB_EP0_SETUP() { + __data uint8_t len = USB_RX_LEN; + if (len == (sizeof(USB_SETUP_REQ))) { + SetupLen = ((uint16_t)UsbSetupBuf->wLengthH << 8) | (UsbSetupBuf->wLengthL); + len = 0; // Default is success and upload 0 length + SetupReq = UsbSetupBuf->bRequest; + if ((UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK) != + USB_REQ_TYP_STANDARD) // Not standard request + { + + // here is the commnunication starts, refer to usbFunctionSetup of USBtiny + // or usb_setup in usbtiny + + switch ((UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK)) { + case USB_REQ_TYP_VENDOR: { + switch (SetupReq) { + default: + len = 0xFF; // command not supported + break; + } + break; + } + case USB_REQ_TYP_CLASS: { + switch (SetupReq) { + case 0x01: // SET_CUR + break; + default: + len = 0xFF; // command not supported + break; + } + break; + } + default: + len = 0xFF; // command not supported + break; + } + + } else // Standard request + { + switch (SetupReq) // Request ccfType + { + case USB_GET_DESCRIPTOR: + switch (UsbSetupBuf->wValueH) { + case 1: // Device Descriptor + pDescr = DevDesc; + len = DevDescLen; + break; + case 2: // Configure Descriptor + pDescr = CfgDesc; + len = CfgDescLen; + break; + case 3: + switch (UsbSetupBuf->wValueL) { + case 0: + pDescr = LangDes; + break; + case 1: + pDescr = Manuf_Des; + break; + case 2: + pDescr = Prod_Des; + break; + case 3: + pDescr = SerDes; + break; + default: + len = 0xff; + break; + } + len = pDescr[0]; + break; + default: + len = 0xff; // Unsupported descriptors or error + break; + } + if (len != 0xff) { + if (SetupLen > len) { + SetupLen = len; // Limit length + } + len = SetupLen >= DEFAULT_ENDP0_SIZE + ? DEFAULT_ENDP0_SIZE + : SetupLen; // transmit length for this packet + for (__data uint8_t i = 0; i < len; i++) { + Ep0Buffer[i] = pDescr[i]; + } + SetupLen -= len; + pDescr += len; + } + break; + case USB_SET_ADDRESS: + SetupLen = UsbSetupBuf->wValueL; // Save the assigned address + break; + case USB_GET_CONFIGURATION: + Ep0Buffer[0] = UsbConfig; + if (SetupLen >= 1) { + len = 1; + } + break; + case USB_SET_CONFIGURATION: + UsbConfig = UsbSetupBuf->wValueL; + break; + case USB_GET_INTERFACE: + break; + case USB_SET_INTERFACE: + break; + case USB_CLEAR_FEATURE: // Clear Feature + if ((UsbSetupBuf->bRequestType & 0x1F) == + USB_REQ_RECIP_DEVICE) // Clear the device featuee. + { + if ((((uint16_t)UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == + 0x01) { + if (CfgDesc[7] & 0x20) { + // wake up + } else { + len = 0xFF; // Failed + } + } else { + len = 0xFF; // Failed + } + } else if ((UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK) == + USB_REQ_RECIP_ENDP) // endpoint + { + switch (UsbSetupBuf->wIndexL) { + case 0x84: + UEP4_CTRL = + UEP4_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK; + break; + case 0x04: + UEP4_CTRL = + UEP4_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES) | UEP_R_RES_ACK; + break; + case 0x83: + UEP3_CTRL = + UEP3_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK; + break; + case 0x03: + UEP3_CTRL = + UEP3_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES) | UEP_R_RES_ACK; + break; + case 0x82: + UEP2_CTRL = + UEP2_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK; + break; + case 0x02: + UEP2_CTRL = + UEP2_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES) | UEP_R_RES_ACK; + break; + case 0x81: + // UEP1_CTRL = + // UEP1_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES) | UEP_T_RES_NAK; + break; + case 0x01: + // UEP1_CTRL = + // UEP1_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES) | UEP_R_RES_ACK; + break; + default: + len = 0xFF; // Unsupported endpoint + break; + } + } else { + len = 0xFF; // Unsupported for non-endpoint + } + break; + case USB_SET_FEATURE: // Set Feature + if ((UsbSetupBuf->bRequestType & 0x1F) == + USB_REQ_RECIP_DEVICE) // Set the device featuee. + { + if ((((uint16_t)UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == + 0x01) { + if (CfgDesc[7] & 0x20) { + // suspend + + // while ( XBUS_AUX & bUART0_TX ); //Wait till uart0 sending + // complete SAFE_MOD = 0x55; SAFE_MOD = 0xAA; WAKE_CTRL = + // bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //wake up by USB or + // RXD0/1 signal PCON |= PD; //sleep SAFE_MOD = 0x55; SAFE_MOD = + // 0xAA; WAKE_CTRL = 0x00; + } else { + len = 0xFF; // Failed + } + } else { + len = 0xFF; // Failed + } + } else if ((UsbSetupBuf->bRequestType & 0x1F) == + USB_REQ_RECIP_ENDP) // endpoint + { + if ((((uint16_t)UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == + 0x00) { + switch (((uint16_t)UsbSetupBuf->wIndexH << 8) | + UsbSetupBuf->wIndexL) { + case 0x84: + UEP4_CTRL = UEP4_CTRL & (~bUEP_T_TOG) | + UEP_T_RES_STALL; // Set endpoint4 IN STALL + break; + case 0x04: + UEP4_CTRL = UEP4_CTRL & (~bUEP_R_TOG) | + UEP_R_RES_STALL; // Set endpoint4 OUT Stall + break; + case 0x83: + UEP3_CTRL = UEP3_CTRL & (~bUEP_T_TOG) | + UEP_T_RES_STALL; // Set endpoint3 IN STALL + break; + case 0x03: + UEP3_CTRL = UEP3_CTRL & (~bUEP_R_TOG) | + UEP_R_RES_STALL; // Set endpoint3 OUT Stall + break; + case 0x82: + UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | + UEP_T_RES_STALL; // Set endpoint2 IN STALL + break; + case 0x02: + UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | + UEP_R_RES_STALL; // Set endpoint2 OUT Stall + break; + case 0x81: + UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | + UEP_T_RES_STALL; // Set endpoint1 IN STALL + break; + case 0x01: + UEP1_CTRL = UEP1_CTRL & (~bUEP_R_TOG) | + UEP_R_RES_STALL; // Set endpoint1 OUT Stall + default: + len = 0xFF; // Failed + break; + } + } else { + len = 0xFF; // Failed + } + } else { + len = 0xFF; // Failed + } + break; + case USB_GET_STATUS: + Ep0Buffer[0] = 0x00; + Ep0Buffer[1] = 0x00; + if (SetupLen >= 2) { + len = 2; + } else { + len = SetupLen; + } + break; + default: + len = 0xff; // Failed + break; + } + } + } else { + len = 0xff; // Wrong packet length + } + if (len == 0xff) { + SetupReq = 0xFF; + UEP0_CTRL = + bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL + } else if (len <= + DEFAULT_ENDP0_SIZE) // Tx data to host or send 0-length packet + { + UEP0_T_LEN = len; + UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | + UEP_T_RES_ACK; // Expect DATA1, Answer ACK + } else { + UEP0_T_LEN = 0; // Tx data to host or send 0-length packet + UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | + UEP_T_RES_ACK; // Expect DATA1, Answer ACK + } +} + +void USB_EP0_IN() { + switch (SetupReq) { + case USB_GET_DESCRIPTOR: { + __data uint8_t len = SetupLen >= DEFAULT_ENDP0_SIZE + ? DEFAULT_ENDP0_SIZE + : SetupLen; // send length + for (__data uint8_t i = 0; i < len; i++) { + Ep0Buffer[i] = pDescr[i]; + } + // memcpy( Ep0Buffer, pDescr, len ); + SetupLen -= len; + pDescr += len; + UEP0_T_LEN = len; + UEP0_CTRL ^= bUEP_T_TOG; // Switch between DATA0 and DATA1 + } break; + case USB_SET_ADDRESS: + USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen; + UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + break; + default: + UEP0_T_LEN = 0; // End of transaction + UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + break; + } +} + +void USB_EP0_OUT() { + if (SetupReq == 0x01) // SET_CUR + { + if (U_TOG_OK) { + UEP0_T_LEN = 0; + UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK; // send 0-length packet + } + } else { + UEP0_T_LEN = 0; + UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK; // Respond Nak + } +} + +#pragma save +#pragma nooverlay +void USBInterrupt(void) { // inline not really working in multiple files in SDCC + if (UIF_TRANSFER) { + // Dispatch to service functions + __data uint8_t callIndex = USB_INT_ST & MASK_UIS_ENDP; + switch (USB_INT_ST & MASK_UIS_TOKEN) { + case UIS_TOKEN_OUT: { // SDCC will take IRAM if array of function pointer is + // used. + switch (callIndex) { + case 0: + EP0_OUT_Callback(); + break; + case 1: + EP1_OUT_Callback(); + break; + case 2: + EP2_OUT_Callback(); + break; + case 3: + EP3_OUT_Callback(); + break; + case 4: + EP4_OUT_Callback(); + break; + default: + break; + } + } break; + case UIS_TOKEN_SOF: { // SDCC will take IRAM if array of function pointer is + // used. + switch (callIndex) { + case 0: + EP0_SOF_Callback(); + break; + case 1: + EP1_SOF_Callback(); + break; + case 2: + EP2_SOF_Callback(); + break; + case 3: + EP3_SOF_Callback(); + break; + case 4: + EP4_SOF_Callback(); + break; + default: + break; + } + } break; + case UIS_TOKEN_IN: { // SDCC will take IRAM if array of function pointer is + // used. + switch (callIndex) { + case 0: + EP0_IN_Callback(); + break; + case 1: + EP1_IN_Callback(); + break; + case 2: + EP2_IN_Callback(); + break; + case 3: + EP3_IN_Callback(); + break; + case 4: + EP4_IN_Callback(); + break; + default: + break; + } + } break; + case UIS_TOKEN_SETUP: { // SDCC will take IRAM if array of function pointer + // is used. + switch (callIndex) { + case 0: + EP0_SETUP_Callback(); + break; + case 1: + EP1_SETUP_Callback(); + break; + case 2: + EP2_SETUP_Callback(); + break; + case 3: + EP3_SETUP_Callback(); + break; + case 4: + EP4_SETUP_Callback(); + break; + default: + break; + } + } break; + } + + UIF_TRANSFER = 0; // Clear interrupt flag + } + + // Device mode USB bus reset + if (UIF_BUS_RST) { + UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + UEP1_CTRL = bUEP_AUTO_TOG | + UEP_T_RES_NAK; // Endpoint 1 automatically flips the sync flag, + // and IN transaction returns NAK + UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | + UEP_R_RES_ACK; // Endpoint 2 automatically flips the sync flag, + // IN transaction returns NAK, OUT returns ACK + // UEP4_CTRL = UEP_T_RES_NAK | UEP_R_RES_ACK; //bUEP_AUTO_TOG only work for + // endpoint 1,2,3 + + USB_DEV_AD = 0x00; + UIF_SUSPEND = 0; + UIF_TRANSFER = 0; + UIF_BUS_RST = 0; // Clear interrupt flag + + UsbConfig = 0; + } + + // USB bus suspend / wake up + if (UIF_SUSPEND) { + UIF_SUSPEND = 0; + if (USB_MIS_ST & bUMS_SUSPEND) { // Suspend + + // while ( XBUS_AUX & bUART0_TX ); // Wait for Tx + // SAFE_MOD = 0x55; + // SAFE_MOD = 0xAA; + // WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO; // Wake up by USB or RxD0 + // PCON |= PD; // Chip sleep SAFE_MOD = 0x55; SAFE_MOD = 0xAA; WAKE_CTRL = + // 0x00; + + } else { // Unexpected interrupt, not supposed to happen ! + USB_INT_FG = 0xFF; // Clear interrupt flag + } + } +} +#pragma restore + +void USBDeviceCfg() { + USB_CTRL = 0x00; // Clear USB control register + USB_CTRL &= ~bUC_HOST_MODE; // This bit is the device selection mode + USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | + bUC_DMA_EN; // USB device and internal pull-up enable, + // automatically return to NAK before interrupt flag + // is cleared during interrupt + USB_DEV_AD = 0x00; // Device address initialization + // USB_CTRL |= bUC_LOW_SPEED; + // UDEV_CTRL |= bUD_LOW_SPEED; //Run for 1.5M + USB_CTRL &= ~bUC_LOW_SPEED; + UDEV_CTRL &= ~bUD_LOW_SPEED; // Select full speed 12M mode, default mode + +#if defined(CH551) || defined(CH552) || defined(CH549) + UDEV_CTRL = bUD_PD_DIS; // Disable DP/DM pull-down resistor +#endif +#if defined(CH559) + UDEV_CTRL = bUD_DP_PD_DIS; // Disable DP/DM pull-down resistor +#endif + UDEV_CTRL |= bUD_PORT_EN; // Enable physical port +} + +void USBDeviceIntCfg() { + USB_INT_EN |= bUIE_SUSPEND; // Enable device hang interrupt + USB_INT_EN |= bUIE_TRANSFER; // Enable USB transfer completion interrupt + USB_INT_EN |= bUIE_BUS_RST; // Enable device mode USB bus reset interrupt + USB_INT_FG |= 0x1F; // Clear interrupt flag + IE_USB = 1; // Enable USB interrupt + EA = 1; // Enable global interrupts +} + +void USBDeviceEndPointCfg() { + // UEP1_DMA = (uint16_t) Ep1Buffer; //Endpoint 1 data transfer address + // //UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; //Endpoint 1 + // automatically flips the sync flag, and IN transaction returns NAK UEP1_CTRL + // = bUEP_AUTO_TOG | UEP_T_RES_TOUT; + + // UEP0_DMA = (uint16_t) Ep0Buffer; //Endpoint 0 data transfer address + // UEP4_1_MOD = 0XC0; //endpoint1 TX RX enable UEP0_CTRL = UEP_R_RES_ACK | + // UEP_T_RES_NAK; //Manual flip, OUT transaction returns ACK, + // IN transaction returns NAK + +#if defined(CH559) + // CH559 use differend endianness for these registers + UEP0_DMA_H = ((uint16_t)Ep0Buffer >> 8); // Endpoint 0 data transfer address + UEP0_DMA_L = ((uint16_t)Ep0Buffer >> 0); // Endpoint 0 data transfer address + UEP1_DMA_H = ((uint16_t)Ep1Buffer >> 8); // Endpoint 1 data transfer address + UEP1_DMA_L = ((uint16_t)Ep1Buffer >> 0); // Endpoint 1 data transfer address +#else + UEP0_DMA = (uint16_t)Ep0Buffer; // Endpoint 0 data transfer address + UEP1_DMA = (uint16_t)Ep1Buffer; // Endpoint 1 data transfer address +#endif + + UEP1_CTRL = UEP_T_RES_NAK; // Endpoint 1 will not flip as isochronous endpoint + // flag, and IN transaction returns NAK + + UEP4_1_MOD = 0X80; // endpoint1 RX enable + UEP0_CTRL = + UEP_R_RES_ACK | UEP_T_RES_NAK; // Manual flip, OUT transaction returns + // ACK, IN transaction returns NAK +} diff --git a/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBhandler.h b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBhandler.h new file mode 100644 index 00000000..db37acf0 --- /dev/null +++ b/ch55xduino/ch55x/libraries/Generic_Examples/examples/05.USB/SoundCard/src/USBAudioSpeaker/USBhandler.h @@ -0,0 +1,65 @@ +#ifndef __USB_HANDLER_H__ +#define __USB_HANDLER_H__ + +// clang-format off +#include +#include "include/ch5xx.h" +#include "include/ch5xx_usb.h" +#include "USBconstant.h" +// clang-format on + +// clang-format off +extern __xdata __at (EP0_ADDR) uint8_t Ep0Buffer[]; +extern __xdata __at (EP1_ADDR) uint8_t Ep1Buffer[]; +//extern __xdata __at (EP2_ADDR) uint8_t Ep2Buffer[]; +// clang-format on + +extern __data uint16_t SetupLen; +extern __data uint8_t SetupReq; +volatile extern __xdata uint8_t UsbConfig; +extern const __code uint8_t *__data pDescr; + +#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer) + +// Out +#define EP0_OUT_Callback USB_EP0_OUT +#define EP1_OUT_Callback AUDIO_EP1_Out +#define EP2_OUT_Callback NOP_Process +#define EP3_OUT_Callback NOP_Process +#define EP4_OUT_Callback NOP_Process + +// SOF +#define EP0_SOF_Callback NOP_Process +#define EP1_SOF_Callback NOP_Process +#define EP2_SOF_Callback NOP_Process +#define EP3_SOF_Callback NOP_Process +#define EP4_SOF_Callback NOP_Process + +// IN +#define EP0_IN_Callback USB_EP0_IN +#define EP1_IN_Callback NOP_Process +#define EP2_IN_Callback NOP_Process +#define EP3_IN_Callback NOP_Process +#define EP4_IN_Callback NOP_Process + +// SETUP +#define EP0_SETUP_Callback USB_EP0_SETUP +#define EP1_SETUP_Callback NOP_Process +#define EP2_SETUP_Callback NOP_Process +#define EP3_SETUP_Callback NOP_Process +#define EP4_SETUP_Callback NOP_Process + +#ifdef __cplusplus +extern "C" { +#endif + +void USBInterrupt(void); +void USBDeviceCfg(); +void USBDeviceIntCfg(); +void USBDeviceEndPointCfg(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif