void configPoll() { int reset = 0; if (!usbReady || USBFS_IsConfigurationChanged()) { reset = 1; } usbReady = USBFS_bGetConfiguration(); if (!usbReady) { return; } if (reset) { USBFS_EnableOutEP(USB_EP_OUT); USBFS_EnableOutEP(USB_EP_COMMAND); usbInEpState = usbDebugEpState = USB_IDLE; } if(USBFS_GetEPState(USB_EP_OUT) == USBFS_OUT_BUFFER_FULL) { ledOn(); // The host sent us some data! int byteCount = USBFS_GetEPCount(USB_EP_OUT); USBFS_ReadOutEP(USB_EP_OUT, hidBuffer, sizeof(hidBuffer)); hidPacket_recv(hidBuffer, byteCount); size_t cmdSize; const uint8_t* cmd = hidPacket_getPacket(&cmdSize); if (cmd && (cmdSize > 0)) { processCommand(cmd, cmdSize); } // Allow the host to send us another updated config. USBFS_EnableOutEP(USB_EP_OUT); ledOff(); } switch (usbInEpState) { case USB_IDLE: { const uint8_t* nextChunk = hidPacket_getHIDBytes(hidBuffer); if (nextChunk) { USBFS_LoadInEP(USB_EP_IN, nextChunk, sizeof(hidBuffer)); usbInEpState = USB_DATA_SENT; } } break; case USB_DATA_SENT: if (USBFS_bGetEPAckState(USB_EP_IN)) { // Data accepted. usbInEpState = USB_IDLE; } break; } }
/******************************************************************************* * Function Name: ServiceUSB ******************************************************************************** * Summary: This routine performs tasks that should be done soon after USB * enumeration is completed (configure DMA, initialize state machine etc). * When the USB configuration is changed, this routine reinitializes all * the USB endpoints as required by the application. * * Parameters: * void * * Return: * void * *******************************************************************************/ void ServiceUSB(void) { CYBIT macPC_flag=FALSE; if(USB_INTERFACE_INACTIVE == USBDeviceState) { USBDeviceState = USB_INIT_AFTER_ENUMERATION_REQUIRED; } /* Initialization sequence for every USB host enumeration event */ if(USBDeviceState == USB_INIT_AFTER_ENUMERATION_REQUIRED) { uint16 index = 0; USBDeviceState = USB_INIT_AFTER_ENUMERATION_COMPLETED; SetAppleDeviceAudioSource(AUDIO_SOURCE_DIGITAL); macPC_flag = IsMacPCConnected(); #if(USBFS_EP_MM == USBFS__EP_DMAAUTO) /* USER_CODE: [Audio Buffers] Add a separate for loop if the playback and recording audio buffer size are * not equal */ for(index=0; index< OUT_AUDIOMAXPKT; index++) { #ifndef ENABLE_DIGITAL_AUDIO_OUT_ONLY inRam[index] = 0; #endif #ifndef ENABLE_DIGITAL_AUDIO_IN_ONLY outRam[index] = 0; #endif } #ifndef ENABLE_DIGITAL_AUDIO_OUT_ONLY inCnt = IN_AUDIOMAXPKT; #endif #endif #ifdef CDC_ENABLED USBUARTStart(); /* Initializes the USB UART interface */ #endif /* Configure the HID input endpoint buffer for Mac/PC playlist control */ if(macPC_flag) { USBFS_LoadInEP(MAC_PC_HID_CONTROL_ENDPOINT, (uint8 *)&playlistControlReport, sizeof(playlistControlReport)); #ifdef PHONE_CONTROL_ENABLED USBFS_ReadOutEP(MAC_PC_HID_OUT_ENDPOINT, &hidOutReport, sizeof(hidOutReport)); USBFS_EnableOutEP(MAC_PC_HID_OUT_ENDPOINT); #endif } /* If Aux is not currently configured, then switch to digital audio mode */ if(IS_AUX_NOT_SELECTED()) { ConfigureDigitalAudioDMA(); } else { #ifdef LCD_MODULE_ENABLED /* Else Display Aux Configured message on the LCD */ LCD2LineDisplay("Analog Loopback ", " "); #endif } /* USER_CODE: [USB enumeration] placeholder for initializing custom user code after the USB host enumerates the * accessory. This routine will be called once per accessory connection after the host issues SET_CONFIGURATION * request */ } #ifdef MIDI_ENABLED if (midiEPInitialized == FALSE || usbReset) { /* Initialize MIDI only when a valid USB host is connected */ if ((IsUSBConfigured() && IsMacPCConnected())) { USBFS_MIDI_EP_Init(); /* USB Component internally sets the priority of the UART TX and RX ISRs to 4 and 2 respectively, change the * interrupt priority in the application code to match the system interrupt setup */ CyIntSetPriority(MIDI1_UART_TX_VECT_NUM, MIDI_UART_INTERRUPT_PRIORITY_SIX); CyIntSetPriority(MIDI1_UART_RX_VECT_NUM, MIDI_UART_INTERRUPT_PRIORITY_FIVE); #if (USBFS_MIDI_EXT_MODE >= USBFS_TWO_EXT_INTRF) CyIntSetPriority(MIDI2_UART_TX_VECT_NUM, MIDI_UART_INTERRUPT_PRIORITY_SIX); CyIntSetPriority(MIDI2_UART_RX_VECT_NUM, MIDI_UART_INTERRUPT_PRIORITY_FIVE); #endif midiEPInitialized = TRUE; usbReset = 0; } } if(USBFS_midiInPointer%USBFS_EVENT_LENGTH == 0 && USBFS_midiInPointer!=0) { if(midiInWaitTimer == 0) { midiInWaitTimer = MIDI_IN_EP_WAIT_TIME; USBFS_MIDI_IN_EP_Service(); } } else { midiInWaitTimer = MIDI_IN_EP_WAIT_TIME; } #endif /* USBFS_IsConfigurationChanged() is a clear on read status update therefore, only one read of * USBFS_IsConfigurationChanged() should ever exist in user code */ if(USBFS_IsConfigurationChanged()) { macPC_flag = IsMacPCConnected(); #ifndef ENABLE_DIGITAL_AUDIO_IN_ONLY /* Get Alternate setting */ altSetting[AUDIO_OUT_INTERFACE_INDEX] = (macPC_flag? USBFS_GetInterfaceSetting(1):USBFS_GetInterfaceSetting(2)); /* ByteSwap control register bit is set to 1 if alt setting 2 is selected so that * Byte swap digital logic processes data as 16 bits. ByteSwap control register is set to 0 * if alt setting 1 is selected and byte swap processes data as 24 bits */ if (altSetting[AUDIO_OUT_INTERFACE_INDEX]==ALT_SETTING_ACTIVE_24_BIT) { ByteSwap_Tx_CONTROL_REG = ByteSwap_Tx_CONTROL_REG & (~ByteSwap_Tx_RES_CTRL_16); } else if (altSetting[AUDIO_OUT_INTERFACE_INDEX]==ALT_SETTING_ACTIVE_16_BIT) { ByteSwap_Tx_CONTROL_REG = ByteSwap_Tx_CONTROL_REG | ByteSwap_Tx_RES_CTRL_16; } /* Arming the audio out EP if it is not zero bandwidth alt setting */ if (altSetting[AUDIO_OUT_INTERFACE_INDEX]!= ALT_SETTING_ZERO_BANDWIDTH && (CY_GET_REG8(USBFS_SIE_EP1_CR0_PTR + ((AUDIO_OUT_ENDPOINT - USBFS_EP1) << USBFS_EPX_CNTX_ADDR_SHIFT)) & USBFS_MODE_MASK) == USBFS_MODE_NAK_IN_OUT) { /* Init DMA configurations for audio OUT EP */ USBFS_ReadOutEP(AUDIO_OUT_ENDPOINT, &outRam[0], OUT_AUDIOMAXPKT); USBFS_EnableOutEP(AUDIO_OUT_ENDPOINT); } #endif #ifndef ENABLE_DIGITAL_AUDIO_OUT_ONLY #ifndef ENABLE_DIGITAL_AUDIO_IN_ONLY if(altSetting[AUDIO_IN_INTERFACE_INDEX] != (macPC_flag? USBFS_GetInterfaceSetting(2):USBFS_GetInterfaceSetting(3))) { altSetting[AUDIO_IN_INTERFACE_INDEX] = (macPC_flag? USBFS_GetInterfaceSetting(2):USBFS_GetInterfaceSetting(3)); #else if(altSetting[AUDIO_IN_INTERFACE_INDEX] != (macPC_flag? USBFS_GetInterfaceSetting(1):USBFS_GetInterfaceSetting(2))) { altSetting[AUDIO_IN_INTERFACE_INDEX] = (macPC_flag? USBFS_GetInterfaceSetting(1):USBFS_GetInterfaceSetting(2)); #endif /* Setting the ByteSwap control register bit to 0 regardless of alt setting is selected. Because audio in * interface both the alternate settings alt setting1 and alt setting 2 both use 3 byte subframe size. */ ByteSwap_Rx_CONTROL_REG = ByteSwap_Rx_CONTROL_REG & (~ByteSwap_Rx_RES_CTRL_16); /* Arming the audio in EP if it is not zero bandwidth alt setting */ if (altSetting[AUDIO_IN_INTERFACE_INDEX]!= ALT_SETTING_ZERO_BANDWIDTH && (CY_GET_REG8(USBFS_SIE_EP1_CR0_PTR + ((AUDIO_IN_ENDPOINT - USBFS_EP1) << USBFS_EPX_CNTX_ADDR_SHIFT)) & USBFS_MODE_MASK) == USBFS_MODE_NAK_IN_OUT) { /* Init DMA configurations for audio IN EP */ inCnt = IN_AUDIOMAXPKT; USBFS_LoadInEP(AUDIO_IN_ENDPOINT, &inRam[0], inCnt); /* Pre-arm first audio IN request */ USBFS_LoadInEP(AUDIO_IN_ENDPOINT, USBFS_NULL, inCnt); } } #endif /* USER_CODE: [USB configuration changed] Placeholder for adding additional USB endpoint initialization code * when the host issues either a SET_INTERFACE or SET_CONFIGURATION request to the accessory. After receiving * a SET_INTERFACE request from the host, the endpoint belonging to the alternate setting being configured * by the USB host is reset and must be reinitialized here for proper operation of the USB block */ } } /******************************************************************************* * Function Name: ServiceUSBSuspend ******************************************************************************** * Summary: * This function handles USB suspend event from USB host and forces PSoC 3 * to enter low power mode. Once the USB resume event is detected, PSoC3 * wakes up and starts operating in normal mode. * * Parameters: * void * * Return: * void * *******************************************************************************/ #ifdef HANDLE_USB_SUSPEND void ServiceUSBSuspend(void) { if(!IsMacPCConnected() || ! USBFS_initVar) { return; } /* Check if the host is active */ if(USBFS_bCheckActivity() != 0 ) { usbActivityCounter = 0; } else { usbActivityCounter++; } /* USB Suspend event is lack of greater than 3 consecutive SOF's */ if(usbActivityCounter > USB_SUSPEND_TIME_TICKS ) { /* The debounce delay is taken care by increasing the suspend time to 40ms (5 * 8ms) */ if(IsMacPCConnected() && IsUSBConfigured()) { /* USER_CODE: [USB suspend] Placeholder for configuring ALL the additional components added by the user in * sleep mode before calling USB suspend/PSoC 3 sleep API */ #ifdef LCD_MODULE_ENABLED LCD_Position(0,0); LCD_PrintString(" USB Suspend "); #endif /* If the accessory is not in low power mode, enter low power mode on seeing a USB suspend */ if(!lowPowerIdle) { lowPowerIdle = TRUE; StopAudioComponents(); /* Changes to 24 MHz IMO for USB */ StopAnalogAudioComponents(); /* Turn OFF Analog path for Audio-In/iPod Analog */ } if(!midiPowerIdle) { if(!lowPowerIdle) { StopAudioComponents(); /* Changes to 24 MHz IMO for USB */ } CyPins_SetPin(PSOC_MIDI_PWR_0); /* Turn off the MIDI I/O hardware */ midiPowerIdle = TRUE; /* MIDI low power mode enabled */ } CyPins_ClearPin(PSOC_CODEC_PWR_0); /* Turn off the regulator to reduce suspend mode current */ USBFS_Suspend(); I2C_Master_Sleep(); /* Configure I2C master block in sleep mode */ #ifdef CAPSENSE_ENABLED while(CapSense_IsBusy()); /* Wait for current scan to complete */ CapSense_Sleep(); #endif #ifdef MIDI_ENABLED MIDI1_UART_Sleep(); #if (USBFS_MIDI_EXT_MODE >= USBFS_TWO_EXT_INTRF) MIDI2_UART_Sleep(); #endif #endif CyPmSaveClocks(); CyPmSleep(PM_SLEEP_TIME_NONE, PM_SLEEP_SRC_PICU); /* PSoC 3 is in sleep mode */ CyPmRestoreClocks(); USBFS_Resume(); I2C_Master_Wakeup(); #ifdef CAPSENSE_ENABLED CapSense_Wakeup(); CapSense_IntClock_SetSource(CYCLK_SRC_SEL_IMO); #endif #ifdef MIDI_ENABLED MIDI1_UART_Wakeup(); #if (USBFS_MIDI_EXT_MODE >= USBFS_TWO_EXT_INTRF) MIDI2_UART_Wakeup(); #endif #endif CyPins_SetPin(PSOC_CODEC_PWR_0); /* Turn ON the CODEC regulator after wake up */ #ifdef WINDOWS7_WORKAROUND if(USBFS_GetConfiguration() != 0) { USBFS_configurationChanged = USBFS_TRUE; USBFS_Config(USBFS_FALSE); } #endif #ifdef LCD_MODULE_ENABLED LCD_Position(0,0); LCD_PrintString("Mac/PC Interface"); #endif /* USER_CODE: [USB wakeup] Placeholder for re-configuring ALL the additional components added by the user in * wakeup mode after calling USB wakeup */ } usbActivityCounter = 0; /* After coming out of USB suspend, MIDI end point should be re-initialized */ midiEPInitialized = 0; } } #endif /******************************************************************************* * Function Name: HandlePCMacUSBInterface ******************************************************************************** * Summary: Checks if PC/Mac is connected/disconnected and start the USB component * * Parameters: * void * * Return: * void * *******************************************************************************/ void HandlePCMacUSBInterface(void) { /* If Aux mode is enabled, then Mac/PC connection disconnection is handled only when the system is not in * aux In mode. For self powered case, Apple device connection is also checked before starting the Mac/PC * interface */ if(IS_AUX_NOT_SELECTED() && !USBFS_initVar && IsMacPCConnected()) { /* Switch the PSoC USB D+ and D- lines to USB Mini B */ CyPins_ClearPin(PSOC_USB_SEL_0); /* Start the USB component when PC/Mac is connected */ USBFS_Start(PC_MAC_AUDIO_WITH_VOLUME_DEVICE, USBFS_DWR_VDDD_OPERATION); USBDeviceState = USB_INIT_AFTER_ENUMERATION_REQUIRED; #ifdef LCD_MODULE_ENABLED if(IS_AUX_NOT_SELECTED()) { LCD2LineDisplay("Mac/PC Interface", " "); } #endif #ifdef ENABLE_VOLUME_CONTROL currentLCDVolume--; /* dirty the LCD volume and mute update flag to update volume and mute info on the LCD */ currentLCDMute--; #endif usbMiniBActive = TRUE; /* USER_CODE: [Mac/PC connection] Placeholder for initializing components or external peripherals when the * accessory is plugged into Mac/PC (USB VBus = High) */ } /* Check for PC/Mac USB Audio device disconnection in self powered mode. * In device powered mode project, no need of checking disconnection event as power is shut off * as soon as USB cable is disconnected from USB mini connector. */ else if(usbMiniBActive && (USBFS_bGetConfiguration() || USBDeviceState == USB_INIT_AFTER_ENUMERATION_REQUIRED)) { /* If VBUS voltage from mini B is now gone and was previous present then stop USB interface */ if(!IsMacPCConnected()) { if(USBFS_initVar) { USBFS_Stop(); } CyPins_SetPin(PSOC_USB_SEL_0); /* Switch the PSoC USB D+ and D- lines back to Apple device */ /* If Aux was not configured when PC is unplugged, then switch off CODEC */ if(!auxConfigured) { CyPins_ClearPin(PSOC_CODEC_RST_0); /* Hold CODEC in reset */ codecInit = FALSE; } usbMiniBActive = FALSE; /* USER_CODE: [Mac/PC disconnection] Placeholder for shutting down components or external peripherals when * the accessory is disconnected from Mac/PC (USB VBus transitioned from High to Low) */ } } } /******************************************************************************* * Function Name: EnableNAKBulkIN ******************************************************************************** * Summary: Enables the NAK interrupt on a USB endpoint * * Parameters: * Endpoint number for which NAK interrupt is to be enabled * * Return: * void * *******************************************************************************/ void EnableNAKBulkIN(uint8 bEPNumber) { uint8 index = (bEPNumber - USBFS_EP1) << USBFS_EPX_CNTX_ADDR_SHIFT; if((CY_GET_REG8(&USBFS_SIE_EP1_CR0_PTR[index]) & USBFS_MODE_MASK) != USBFS_MODE_ACK_IN) { CY_SET_REG8(&USBFS_SIE_EP1_CR0_PTR[index], CY_GET_REG8(&USBFS_SIE_EP1_CR0_PTR[index]) | NAK_IN_INTERRUPT_ENABLE_MASK); } }
void USBrefresh() { uint8 skipNextOut = 0u; /* Check if configuration or interface settings are changed. */ if (0u != USBFS_IsConfigurationChanged()) { /* Check active alternate setting. */ if ((0u != USBFS_GetConfiguration()) && (0u != USBFS_GetInterfaceSetting(AUDIO_INTERFACE))) { /* Alternate settings 1: Audio is streaming. */ /* Reset variables. */ inIndex = 0u; outIndex = 0u; syncDma = 0u; skipNextOut = 0u; syncDmaCounter = 0u; /* Enable OUT endpoint to receive audio stream. */ USBFS_EnableOutEP(OUT_EP_NUM); } if (USBFS_OUT_BUFFER_FULL == USBFS_GetEPState(OUT_EP_NUM)) { if (0u == skipNextOut) { /* Trigger DMA to copy data from OUT endpoint buffer. */ USBFS_ReadOutEP(OUT_EP_NUM, &soundBuffer[inIndex * TRANSFER_SIZE], TRANSFER_SIZE); /* Wait until DMA completes copying data from OUT endpoint buffer. */ while (USBFS_OUT_BUFFER_FULL == USBFS_GetEPState(OUT_EP_NUM)) { } /* Move to the next buffer location and adjust to be within * buffer size. Lock from DmaDone interruption. */ DmaDone_Disable(); ++inIndex; inIndex = (inIndex >= NUM_OF_BUFFERS) ? 0u : inIndex; DmaDone_Enable(); ++syncDmaCounter; /* Enable OUT endpoint to receive data from host. */ USBFS_EnableOutEP(OUT_EP_NUM); } else { /* Ignore received data from host and arm OUT endpoint * without reading if overflow is detected. */ USBFS_EnableOutEP(OUT_EP_NUM); skipNextOut = 0u; } /* When internal 32-kHz clock is slower, compare to PC traffic * then skip next transfer from PC. */ if (outIndex == inIndex) { skipNextOut = 1u; } } /* Enable DMA transfers when sound buffer is half-full. */ if ((0u == syncDma) && (syncDmaCounter == (NUM_OF_BUFFERS / 2u))) { /* Start DMA operation. */ CyDmaChEnable(TxOutDmaCh, TX_DMA_ENABLE_PRESERVE_TD); /* Disable underflow delayed start. */ syncDma = 1u; } } }