Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust usbdrvasm16.inc to support AVR 1-series. #26

Closed
wants to merge 1 commit into from

Conversation

sgielen
Copy link

@sgielen sgielen commented Nov 21, 2020

Tested on attiny1614. Can't be merged immediately, since it would break usbdrvasm16 for older AVR devices, so this is a first version. I'm mostly putting this here as to allow other people to work with the code on their 1-series AVR device. If you'd like to merge this, I will spend additional time to get the patch into mergeable state, but didn't want to start on that before hearing your intentions :-)

Usage instructions

Clock speed

16 MHz is the only supported clock speed that can be produced by the internal oscillator, at least on my attiny1614, so this PR only updates the 16MHz-clocked version of the code (usbdrvasm16.inc). To set your AVR to 16 MHz, you need to set the FUSE_OSCCFG to FREQSEL_16MHZ_gc. Be careful doing this, since setting the wrong fuses can brick your device. For my device, I read the fuses using pyupdi -d tiny1614 -c /dev/tty.usbserial -fr, where fuse 2 (OSCCFG) was set to 0x02, meaning 20 MHz. I cleared bit 2 and set bit 1, so the value becomes 0x01 i.e. 16 MHz, using pyupdi -d tiny1614 -c /dev/tty.usbserial -fs 2:0x01. Check your datasheet before doing this! After setting the fuse, you need to disable the prescaler inside your firmware. My firmware starts with this:

// Disable the clock prescaler so that we are running at 16 MHz or 20 MHz
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0);

// Confirm that 16 MHz clock is selected in fuses.
if ((FUSE_OSCCFG & FUSE_FREQSEL_gm) != FRESQL_16MHZ_gc) {
  led_fatal();
}

where led_fatal() makes a LED blink really fast to indicate error state.

GPIO pins

I connected the USB D- to PB0, which is pin 9, and D+ to PB1, which is pin 8. A hint for when you're just starting out: USB cable coloring is not consistent between cables, so don't look only at the cable colors when connecting everything up. To make my device USB low-speed compliant, I have a 1.5 kOhm resistor between D- and Vcc. Also, I have a 1MOhm resistor between D+ and Vcc so it doesn't float when no host is connected.

usbInit

Then, I don't use usbInit() to initialize my GPIO pins, since it seemed harder to get this function to do the right thing generically than to just do it myself for now. V-USB supports interrupt on both D- and D+, but the recommended interrupt is on the rising edge of D+ (in my case, PB1), so:

    // instead of usbInit():
    PORTB.DIRCLR = (1 << 1);
    PORTB.DIRCLR = (1 << 0);
    PORTB.PIN0CTRL = 0;
    PORTB.PIN1CTRL = PORT_ISC_RISING_gc;
    PORTB.PIN2CTRL = 0;
    PORTB.PIN3CTRL = 0;
    PORTB.PIN4CTRL = 0;
    PORTB.PIN5CTRL = 0;
    PORTB.PIN6CTRL = 0;
    PORTB.PIN7CTRL = 0;

    usbDeviceDisconnect();
    _delay_ms(250);
    usbDeviceConnect();

    sei();
    while (1)
    {
        wdt_reset();
        usbPoll();
    }

usbconfig.h

The following settings are important in usbconfig.h:

  • Start with the default v-usb/usbdrv/usbconfig-prototype.h
  • USB_CFG_IOPORTNAME is B in my case
  • USB_CFG_DMINUS_BIT & USB_CFG_DPLUS_BIT are 0 and 1 in my case
  • You should set F_CPU to 16000000 (see above), so USB_CFG_CLOCK_KHZ can remain defined as (F_CPU/1000)
  • USB_CFG_CHECK_CRC must be 0, since there's no time to check the CRC
  • USB_INTR_CFG* and USB_INTR_ENABLE* are only used in usbInit, so we don't use that
  • USB_INTR_PENDING must be set to VPORTB_INTFLAGS (or another VPORT if you don't use port B)
  • USB_INTR_PENDING_BIT in my case is set to VPORT_INT1_bp meaning the bit position of pin 1, together with the previous option this means the assembly will read/write the interrupt pending bit for pin PB1 (D+), where we actually have the interrupt set
  • USB_INTR_VECTOR is set to PORTB_PORT_vect, the interrupt vector for port B. This is translated to __vector_4.
  • Do go through the options in the entire file yourself as well, and modify options as indicated.

Thanks

I'd like to shout out to the author of http://www.usbmadesimple.co.uk/, whose documentation was invaluable while writing this patch. Also, thanks to the authors of V-USB, since the code is quite clear and well-written.

Tested on attiny1614. Can't be merged immediately, since it would break
usbdrvasm16 for older AVR devices, so this is a first version.
@sgielen sgielen changed the title Adjust usbdrvasm16.inc to support AVR 1-series. Adjust usbdrvasm16.inc to support AVR 1-series. Closes #24. Nov 21, 2020
@sgielen sgielen changed the title Adjust usbdrvasm16.inc to support AVR 1-series. Closes #24. Adjust usbdrvasm16.inc to support AVR 1-series. Nov 21, 2020
@sgielen
Copy link
Author

sgielen commented Nov 21, 2020

This PR would close #24.

@sgielen
Copy link
Author

sgielen commented Nov 21, 2020

I think the patch could be improved/simplified by using usbTxLen instead of usbTxToken, since I'm only using usbTxToken for token bytes and the docs for usbTxLen say it is not to be used if it contains a token byte. However, I haven't investigated if there are any adverse consequences to this.

@sgielen
Copy link
Author

sgielen commented Dec 11, 2020

Bump to the maintainer (@starkjohann)

@starkjohann
Copy link
Contributor

It's quite a while since I wrote that code, so my knowledge is no better than your's...

@sgielen
Copy link
Author

sgielen commented Dec 14, 2020

It's quite a while since I wrote that code, so my knowledge is no better than your's...

Would you be willing to merge a PR like this, if I change it not to break compatibility with older AVR devices? I'd put the effort in, but only if you're likely to merge it eventually...

@starkjohann
Copy link
Contributor

V-USB is distributed under two licenses: GPL and commercial. If I merge your changes into the main code, this would probably mean that we need to maintain two branches: One commercial without contributions and one GPL'd with all the contributions.

This change requires rewriting docs which explain the dual licensing. This needs to be done anyway in your fork because it's plain wrong that people can pay us money to use without the limitations of GPL.

@sgielen
Copy link
Author

sgielen commented Dec 27, 2020

V-USB is distributed under two licenses: GPL and commercial. If I merge your changes into the main code, this would probably mean that we need to maintain two branches: One commercial without contributions and one GPL'd with all the contributions.

TBH I don't mind to give up my copyrights & have this contribution relicensed under the existing licenses, including the commercial one. For me, the benefit is that I've given back after your project helped me, and I've already developed this anyway, so I might as well help others with it :-)

@starkjohann
Copy link
Contributor

If the commercial license is OK for you, I would like to merge your pull request.

When you convert it for backward compatibility: Please try to avoid #if and #ifdef as much as possible and keep them as local as possible so that the code stays "readable" (as much as this type of assembler code can be considered readable...).

@sgielen
Copy link
Author

sgielen commented Oct 5, 2022

Closing, because I haven't worked on this for a very long time and likely won't finish it. To anyone else, please feel free to pick up my changes and rework them into a new PR.

@sgielen sgielen closed this Oct 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants