Example #1
0
/**
 * Performs an in transfer from a USB device from an arbitrary endpoint.
 *
 * @param device USB bulk device.
 * @param device length number of bytes to read.
 * @param data target buffer.
 * @return number of bytes read, or error code in case of failure.
 */
int16_t USB::read( usb_device * device, usb_endpoint * endpoint, uint16_t length, uint8_t *data, uint16_t nakLimit )
{
	int8_t rcode;
	int8_t bytesRead;
	uint16_t maxPacketSize = endpoint->maxPacketSize;

	uint16_t totalTransferred = 0;

	// Set device address.
	max3421e_write( MAX_REG_PERADDR, device->address );

	// Set toggle value.
	max3421e_write( MAX_REG_HCTL, endpoint->receiveToggle );

	while( 1 ) {
		// Start IN transfer
		rcode = USB::dispatchPacket( tokIN, endpoint, nakLimit );
		if( rcode ) {
//			if( rcode != hrNAK ) serialPrintf( "USB::read: dispatch error %d\n", rcode );
			return -1;
		}

		// Assert that the RCVDAVIRQ bit in register MAX_REG_HIRQ is set.
		if( (max3421e_read( MAX_REG_HIRQ ) & bmRCVDAVIRQ) == 0 ) {
//			serialPrintf("USB::read: toggle error? %d\n", rcode);

			// TODO: the absence of RCVDAVIRQ indicates a toggle error. Need to add handling for that.
			return -2;
		}

		// Obtain the number of bytes in FIFO.
		bytesRead = max3421e_read( MAX_REG_RCVBC );

		// Read the data from the FIFO.
		data = max3421e_readMultiple( MAX_REG_RCVFIFO, bytesRead, data );

		// Clear the interrupt to free the buffer.
		max3421e_write(MAX_REG_HIRQ, bmRCVDAVIRQ);

		totalTransferred += bytesRead;

		// Check if we're done reading. Either we've received a 'short' packet (<maxPacketSize), or the
		// desired number of bytes has been transferred.
		if( (bytesRead < maxPacketSize) || (totalTransferred >= length) ) {
			// Remember the toggle value for the next transfer.
			if (max3421e_read(MAX_REG_HRSL) & bmRCVTOGRD)
				endpoint->receiveToggle = bmRCVTOG1;
			else
				endpoint->receiveToggle = bmRCVTOG0;

			// Break out of the loop.
			break;
		}
	}

	// Report success.
	return totalTransferred;
}
Example #2
0
/**
 * Interrupt handler.
 */
uint8_t max3421e_interruptHandler(void)
{
    uint8_t interruptStatus;
    uint8_t HIRQ_sendback = 0x00;

    // Determine interrupt source.
    interruptStatus = max3421e_read(MAX_REG_HIRQ);

    if (interruptStatus & bmFRAMEIRQ)
    {
        //->1ms SOF interrupt handler
        HIRQ_sendback |= bmFRAMEIRQ;
    }

    if (interruptStatus & bmCONDETIRQ)
    {
        max3421e_busprobe();

        HIRQ_sendback |= bmCONDETIRQ;
    }

    // End HIRQ interrupts handling, clear serviced IRQs
    max3421e_write(MAX_REG_HIRQ, HIRQ_sendback);

    return (HIRQ_sendback);
}
Example #3
0
/**
 * Probes the bus to determine device presence and speed, and switches host to this speed.
 */
void max3421e_busprobe(void)
{
    uint8_t bus_sample;
    bus_sample = max3421e_read(MAX_REG_HRSL); //Get J,K status
    bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the uint8_t

    switch (bus_sample)
    {
    //start full-speed or low-speed host
    case (bmJSTATUS):
        if ((max3421e_read(MAX_REG_MODE) & bmLOWSPEED) == 0)
        {
            max3421e_write(MAX_REG_MODE, MODE_FS_HOST ); //start full-speed host
            vbusState = FSHOST;
        } else
        {
            max3421e_write(MAX_REG_MODE, MODE_LS_HOST); //start low-speed host
            vbusState = LSHOST;
        }
        break;
    case (bmKSTATUS):
        if ((max3421e_read(MAX_REG_MODE) & bmLOWSPEED) == 0)
        {
            max3421e_write(MAX_REG_MODE, MODE_LS_HOST ); //start low-speed host
            vbusState = LSHOST;
        } else
        {
            max3421e_write(MAX_REG_MODE, MODE_FS_HOST ); //start full-speed host
            vbusState = FSHOST;
        }
        break;
    case (bmSE1): //illegal state
        vbusState = SE1;
        break;
    case (bmSE0): //disconnected state
        vbusState = SE0;
        break;
    }
}
Example #4
0
/**
 * GPX interrupt handler
 */
uint8_t max3421e_gpxInterruptHandler(void)
{
    //read GPIN IRQ register
    uint8_t interruptStatus = max3421e_read(MAX_REG_GPINIRQ);

    //    if( GPINIRQ & bmGPINIRQ7 ) {            //vbus overload
    //        vbusPwr( OFF );                     //attempt powercycle
    //        delay( 1000 );
    //        vbusPwr( ON );
    //        regWr( rGPINIRQ, bmGPINIRQ7 );
    //    }

    return (interruptStatus);
}
Example #5
0
/**
 * Initialises the max3421e after power-on.
 */
void max3421e_powerOn(void)
{
    // Configure full-duplex SPI, interrupt pulse.
    max3421e_write(MAX_REG_PINCTL, (bmFDUPSPI + bmINTLEVEL + bmGPXB)); //Full-duplex SPI, level interrupt, GPX

    // Stop/start the oscillator.
    if (max3421e_reset() == false)
        Serial.print("Error: OSCOKIRQ failed to assert\n");

    // Configure host operation.
    max3421e_write(MAX_REG_MODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ ); // set pull-downs, Host, Separate GPIN IRQ on GPX
    max3421e_write(MAX_REG_HIEN, bmCONDETIE | bmFRAMEIE ); //connection detection

    // Check if device is connected.
    max3421e_write(MAX_REG_HCTL, bmSAMPLEBUS ); // sample USB bus
    while (!(max3421e_read(MAX_REG_HCTL) & bmSAMPLEBUS)); //wait for sample operation to finish

    max3421e_busprobe(); //check if anything is connected
    max3421e_write(MAX_REG_HIRQ, bmCONDETIRQ ); //clear connection detect interrupt

    // Enable interrupt pin.
    max3421e_write(MAX_REG_CPUCTL, 0x01);
}
Example #6
0
/**
 * Resets the max3412e. Sets the chip reset bit, SPI configuration is not affected.
 * @return true iff success.
 */
boolean max3421e_reset(void)
{
    uint8_t tmp = 0;

    // Chip reset. This stops the oscillator
    max3421e_write(MAX_REG_USBCTL, bmCHIPRES);

    // Remove the reset
    max3421e_write(MAX_REG_USBCTL, 0x00);

    delay(10);

    // Wait until the PLL is stable
    while (!(max3421e_read(MAX_REG_USBIRQ) & bmOSCOKIRQ))
    {
        // Timeout after 256 attempts.
        tmp++;
        if (tmp == 0)
            return (false);
    }

    // Success.
    return (true);
}
Example #7
0
int usb_dispatchPacket(uint8_t token, usb_endpoint * endpoint, unsigned int nakLimit)
{
//	uint32_t timeout = avr_millis() + USB_XFER_TIMEOUT;
	uint16_t timeout = xTaskGetTickCount() + USB_XFER_TIMEOUT / portTICK_RATE_MS; // XXX from freeRTOS
	uint8_t tmpdata;
	uint8_t rcode = 0;
	unsigned int nak_count = 0;
	char retry_count = 0;

	while (timeout > xTaskGetTickCount() )
	{
		// Analyze transfer result.

		// Launch the transfer.
		max3421e_write(MAX_REG_HXFR, (token | endpoint->address));
		rcode = 0xff;

		// Wait for interrupt
		while (timeout > xTaskGetTickCount() )
		{
			tmpdata = max3421e_read(MAX_REG_HIRQ);
			if (tmpdata & bmHXFRDNIRQ)
			{
				// Clear the interrupt.
				max3421e_write(MAX_REG_HIRQ, bmHXFRDNIRQ);

				rcode = 0x00;
				break;
			}
		}

		// Exit if timeout.
		if (rcode != 0x00)
			return (rcode);

		// Wait for HRSL
		while (timeout > xTaskGetTickCount() )
		{
			rcode = (max3421e_read(MAX_REG_HRSL) & 0x0f);
			if (rcode != hrBUSY)
				break;
			else
				xSerialPrint_P(PSTR("USB dispatch busy!\r\n"));
		}


		switch (rcode)
		{
			case hrNAK:
				nak_count++;
				if (nak_count == nakLimit)
					return (rcode);
				break;
			case hrTIMEOUT:
				retry_count++;
				if (retry_count == USB_RETRY_LIMIT)
					return (rcode);
				break;
			default:
				return (rcode);
		}
	}

	return (rcode);
}
Example #8
0
/**
 * Performs ab out transfer to a USB device on an arbitrary endpoint.
 *
 * @param device USB bulk device.
 * @param device length number of bytes to read.
 * @param data target buffer.
 * @return number of bytes written, or error code in case of failure.
 */
int usb_write(usb_device * device, usb_endpoint * endpoint, uint16_t length, uint8_t * data)
{
	uint8_t rcode = 0, retry_count;

	// Set device address.
	max3421e_write(MAX_REG_PERADDR, device->address);

	// Local copy of the data pointer.
	uint8_t * data_p = data;

	unsigned int bytes_tosend, nak_count;
	unsigned int bytes_left = length;
	unsigned int nak_limit = USB_NAK_LIMIT;

//	uint32_t timeout = avr_millis() + USB_XFER_TIMEOUT;  // XXX from freeRTOS
	uint16_t timeout = xTaskGetTickCount() + USB_XFER_TIMEOUT / portTICK_RATE_MS;
	uint8_t maxPacketSize = endpoint->maxPacketSize;

	// If maximum packet size is not set, return.
	if (!maxPacketSize) return 0xFE;

	max3421e_write(MAX_REG_HCTL, endpoint->sendToggle); //set toggle value

	while (bytes_left)
	{
		retry_count = 0;
		nak_count = 0;

		bytes_tosend = (bytes_left >= maxPacketSize) ? maxPacketSize : bytes_left;

		// Filling output FIFO
		max3421e_writeMultiple(MAX_REG_SNDFIFO, bytes_tosend, data_p);

		// Set number of bytes to send.
		max3421e_write(MAX_REG_SNDBC, bytes_tosend);

		// Dispatch packet.
		max3421e_write(MAX_REG_HXFR, (tokOUT | endpoint->address));

		// Wait for completion.
		while (!(max3421e_read(MAX_REG_HIRQ) & bmHXFRDNIRQ));

		// Clear IRQ.
		max3421e_write(MAX_REG_HIRQ, bmHXFRDNIRQ);

		rcode = (max3421e_read(MAX_REG_HRSL) & 0x0f);

		while (rcode && (timeout > xTaskGetTickCount()) )
		{
			switch (rcode)
			{
			case hrNAK:
				nak_count++;
				if (nak_limit && (nak_count == USB_NAK_LIMIT))
				{
					return (rcode); //return NAK
				}
				break;
			case hrTIMEOUT:
				retry_count++;
				if (retry_count == USB_RETRY_LIMIT)
				{
					return (rcode); //return TIMEOUT
				}
				break;
			default:
				return (rcode);
			}

			// Process NAK according to Host out NAK bug.
			max3421e_write(MAX_REG_SNDBC, 0);
			max3421e_write(MAX_REG_SNDFIFO, *data_p);
			max3421e_write(MAX_REG_SNDBC, bytes_tosend);
			max3421e_write(MAX_REG_HXFR, (tokOUT | endpoint->address)); //dispatch packet

			// Wait for the completion interrupt.
			while (!(max3421e_read(MAX_REG_HIRQ) & bmHXFRDNIRQ));

			// Clear interrupt.
			max3421e_write(MAX_REG_HIRQ, bmHXFRDNIRQ);

			rcode = (max3421e_read(MAX_REG_HRSL) & 0x0f);
		}

		bytes_left -= bytes_tosend;
		data_p += bytes_tosend;
	}

	endpoint->sendToggle = (max3421e_read(MAX_REG_HRSL) & bmSNDTOGRD) ? bmSNDTOG1 : bmSNDTOG0; //update toggle

	// Should be 0 in all cases.
	return (rcode);
}
Example #9
0
/**
 * USB main task. Performs enumeration/cleanup
 */
void usb_poll(void)
{
	uint8_t i;
	uint8_t rcode;
	uint8_t tmpdata;
	static uint16_t delay = 0;
	usb_deviceDescriptor deviceDescriptor;

	// Poll the MAX3421E device.
	max3421e_poll();

	/* modify USB task state if Vbus changed */
	tmpdata = max3421e_getVbusState();

	switch (tmpdata)
	{
	case SE1: //illegal state
		usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
		break;
	case SE0: //disconnected
		if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED)
		{
			usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
		}
		break;
	case FSHOST: //attached
	case LSHOST:
		if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED)
		{
			delay = xTaskGetTickCount() + USB_SETTLE_DELAY / portTICK_RATE_MS;
			usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
		}
		break;
	}// switch( tmpdata


	switch (usb_task_state)
	{
	case USB_DETACHED_SUBSTATE_INITIALIZE:

		// TODO right now it looks like the USB board is just reset on disconnect. Fire disconnect for all connected
		// devices.
		for (i = 1; i < USB_NUMDEVICES; i++)
			if (deviceTable[i].active)
				usb_fireEvent(&(deviceTable[i]), USB_DISCONNECT);

		usb_init();
		usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
		break;

	case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
		break;

	case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
		break;

	case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
		if (delay < xTaskGetTickCount() )
		{
			usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
		}
		break;

	case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
		// Issue bus reset.
		max3421e_write(MAX_REG_HCTL, bmBUSRST);
		usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
		break;

	case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
		if ((max3421e_read(MAX_REG_HCTL) & bmBUSRST) == 0)
		{
			tmpdata = max3421e_read(MAX_REG_MODE) | bmSOFKAENAB; //start SOF generation
			max3421e_write(MAX_REG_MODE, tmpdata);
			//                  max3421e_regWr( rMODE, bmSOFKAENAB );
			usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
			delay = xTaskGetTickCount() + 20 / portTICK_RATE_MS; //20ms wait after reset per USB spec
		}
		break;

	case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
		if (max3421e_read(MAX_REG_HIRQ) & bmFRAMEIRQ)
		{ //when first SOF received we can continue
			if (delay < xTaskGetTickCount() )
			{ //20ms passed
				usb_task_state
						= USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
			}
		}
		break;

	case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE:
		// toggle( BPNT_0 );

		deviceTable[0].control.maxPacketSize = 8;

		rcode = usb_getDeviceDescriptor(&deviceTable[0], &deviceDescriptor);
		if (rcode == 0)
		{
			deviceTable[0].control.maxPacketSize = deviceDescriptor.bMaxPacketSize0;
			usb_task_state = USB_STATE_ADDRESSING;
		} else
		{
			usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
			usb_task_state = USB_STATE_ERROR;
		}
		break;

	case USB_STATE_ADDRESSING:

		// Look for an empty spot
		for (i = 1; i < USB_NUMDEVICES; i++)
		{
			if (!deviceTable[i].active)
			{
				// Set correct MaxPktSize
				// deviceTable[i].epinfo = deviceTable[0].epinfo;

				deviceTable[i].address = i;
				deviceTable[i].active = true;

				usb_initEndPoint(&(deviceTable[i].control), 0);

				//temporary record
				//until plugged with real device endpoint structure
				rcode = usb_setAddress(&deviceTable[0], i);

				if (rcode == 0)
				{
					usb_fireEvent(&deviceTable[i], USB_CONNECT);
					// usb_task_state = USB_STATE_CONFIGURING;
					// NB: I've bypassed the configuring state, because configuration should be handled
					// in the usb event handler.
					usb_task_state = USB_STATE_RUNNING;
				} else
				{
					usb_fireEvent(&deviceTable[i], USB_ADRESSING_ERROR);

					// TODO remove usb_error at some point?
					usb_error = USB_STATE_ADDRESSING;
					usb_task_state = USB_STATE_ERROR;
				}
				break; //break if address assigned or error occurred during address assignment attempt
			}
		}

		// If no vacant spot was found in the device table, fire an error.
		if (usb_task_state == USB_STATE_ADDRESSING)
		{
			usb_fireEvent(&deviceTable[i], USB_ADRESSING_ERROR);

			// No vacant place in devtable
			usb_error = 0xfe;
			usb_task_state = USB_STATE_ERROR;
		}

		break;
	case USB_STATE_CONFIGURING:
		break;
	case USB_STATE_RUNNING:
		break;
	case USB_STATE_ERROR:
		break;
	}
//	xSerialPrintf_P(PSTR("\r\nusb_poll usb_task_state: %u @ Tick: %u"), usb_task_state, xTaskGetTickCount()); // FIXME remove this debugging
}
Example #10
0
int usb_dispatchPacket(uint8_t token, usb_endpoint * endpoint, unsigned int nakLimit)
{
    uint32_t timeout = millis() + USB_XFER_TIMEOUT;
    uint8_t tmpdata;
    uint8_t rcode = 0;
    unsigned int nak_count = 0;
    char retry_count = 0;

    while (timeout > millis())
    {
        // Analyze transfer result.

        // Launch the transfer.
        max3421e_write(MAX_REG_HXFR, (token | endpoint->address));
        rcode = 0xff;

        // Wait for interrupt
        while (timeout > millis())
        {
            tmpdata = max3421e_read(MAX_REG_HIRQ);
            if (tmpdata & bmHXFRDNIRQ)
            {
                // Clear the interrupt.
                max3421e_write(MAX_REG_HIRQ, bmHXFRDNIRQ);

                rcode = 0x00;
                break;
            }
        }

        // Exit if timeout.
        if (rcode != 0x00)
            return (rcode);

        // Wait for HRSL
        while (timeout > millis())
        {
            rcode = (max3421e_read(MAX_REG_HRSL) & 0x0f);
            if (rcode != hrBUSY)
                break;
//			else
//				serialPrintf("busy!\n");
        }


        switch (rcode)
        {
        case hrNAK:
            nak_count++;
            if (nak_count == nakLimit)
                return (rcode);
            break;
        case hrTIMEOUT:
            retry_count++;
            if (retry_count == USB_RETRY_LIMIT)
                return (rcode);
            break;
        default:
            return (rcode);
        }
    }

    return (rcode);
}