diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2018-09-28 21:09:19 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2018-09-30 22:55:21 -0400 |
commit | d05aa81927af8672656b0b3f0ccdefb6e6b42f94 (patch) | |
tree | 8cf4bee789e68ad03e2b370073f1319b2aa17f1a | |
parent | c0311bee338a433295a56241f29c1acbf52f0930 (diff) | |
download | kutter-d05aa81927af8672656b0b3f0ccdefb6e6b42f94.tar.gz kutter-d05aa81927af8672656b0b3f0ccdefb6e6b42f94.tar.xz kutter-d05aa81927af8672656b0b3f0ccdefb6e6b42f94.zip |
avr: Use generic usb_cdc code for usb serial support
Use the generic usb_cdc driver code instead of the "pjrc" usb driver
code.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r-- | config/generic-printrboard.cfg | 2 | ||||
-rw-r--r-- | src/avr/Makefile | 4 | ||||
-rw-r--r-- | src/avr/usbserial.c | 267 |
3 files changed, 226 insertions, 47 deletions
diff --git a/config/generic-printrboard.cfg b/config/generic-printrboard.cfg index 5fd99e1e..8a667370 100644 --- a/config/generic-printrboard.cfg +++ b/config/generic-printrboard.cfg @@ -66,7 +66,7 @@ max_temp: 130 pin: PC6 [mcu] -serial: /dev/ttyACM0 +serial: /dev/serial/by-id/usb-Klipper_Klipper_firmware_12345-if00 [printer] kinematics: cartesian diff --git a/src/avr/Makefile b/src/avr/Makefile index 9f814a44..c3f3ab34 100644 --- a/src/avr/Makefile +++ b/src/avr/Makefile @@ -3,14 +3,14 @@ # Use the avr toolchain CROSS_PREFIX=avr- -dirs-y += src/avr src/generic lib/pjrc_usb_serial +dirs-y += src/avr src/generic CFLAGS += -mmcu=$(CONFIG_MCU) # Add avr source files src-y += avr/main.c avr/timer.c avr/gpio.c src-$(CONFIG_AVR_WATCHDOG) += avr/watchdog.c -src-$(CONFIG_AVR_USBSERIAL) += avr/usbserial.c ../lib/pjrc_usb_serial/usb_serial.c +src-$(CONFIG_AVR_USBSERIAL) += avr/usbserial.c generic/usb_cdc.c src-$(CONFIG_AVR_SERIAL) += avr/serial.c generic/serial_irq.c # Suppress broken "misspelled signal handler" warnings on gcc 4.8.1 diff --git a/src/avr/usbserial.c b/src/avr/usbserial.c index 2a16160d..188a1b14 100644 --- a/src/avr/usbserial.c +++ b/src/avr/usbserial.c @@ -1,71 +1,250 @@ -// Wrappers for AVR usb serial. +// Hardware interface to USB on AVR at90usb // -// Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> // // This file may be distributed under the terms of the GNU GPLv3 license. -#include <string.h> // memmove -#include "../lib/pjrc_usb_serial/usb_serial.h" -#include "board/misc.h" // console_sendf -#include "command.h" // command_find_and_dispatch +#include <avr/interrupt.h> // USB_COM_vect +#include <string.h> // NULL +#include "autoconf.h" // CONFIG_MACH_at90usb1286 +#include "board/usb_cdc.h" // usb_notify_ep0 +#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN +#include "pgm.h" // READP #include "sched.h" // DECL_INIT -static uint8_t receive_buf[MESSAGE_MAX], receive_pos; +// EPCFG0X definitions +#define EP_TYPE_CONTROL 0x00 +#define EP_TYPE_BULK_IN 0x81 +#define EP_TYPE_BULK_OUT 0x80 +#define EP_TYPE_INTERRUPT_IN 0xC1 -void -usbserial_init(void) +// EPCFG1X definitions +#define EP_SINGLE_BUFFER 0x02 +#define EP_DOUBLE_BUFFER 0x06 +#define EP_SIZE(s) ((s)==64 ? 0x30 : ((s)==32 ? 0x20 : ((s)==16 ? 0x10 : 0x00))) + +static void +usb_write_packet(const uint8_t *data, uint8_t len) { - usb_init(); + while (len--) + UEDATX = *data++; } -DECL_INIT(usbserial_init); -// Check for new incoming data static void -console_check_input(void) +usb_write_packet_progmem(const uint8_t *data, uint8_t len) { - for (;;) { - if (receive_pos >= sizeof(receive_buf)) - break; - int16_t ret = usb_serial_getchar(); - if (ret == -1) - break; - receive_buf[receive_pos++] = ret; - } + while (len--) + UEDATX = READP(*data++); } -// Remove from the receive buffer the given number of bytes static void -console_pop_input(uint8_t len) +usb_read_packet(uint8_t *data, uint8_t len) +{ + while (len--) + *data++ = UEDATX; +} + +int_fast8_t +usb_read_bulk_out(void *data, uint_fast8_t max_len) +{ + UENUM = USB_CDC_EP_BULK_OUT; + if (!(UEINTX & (1<<RWAL))) + // No data ready + return -1; + uint8_t len = UEBCLX; + usb_read_packet(data, len); + UEINTX = (uint8_t)~(1<<FIFOCON); + return len; +} + +int_fast8_t +usb_send_bulk_in(void *data, uint_fast8_t len) +{ + UENUM = USB_CDC_EP_BULK_IN; + if (!(UEINTX & (1<<RWAL))) + // Buffer full + return -1; + usb_write_packet(data, len); + UEINTX = (uint8_t)~((1<<FIFOCON) | (1<<RXOUTI)); + return len; +} + +int_fast8_t +usb_read_ep0(void *data, uint_fast8_t max_len) { - uint8_t needcopy = receive_pos - len; - if (needcopy) { - memmove(receive_buf, &receive_buf[len], needcopy); - sched_wake_tasks(); + UENUM = 0; + uint8_t ueintx = UEINTX; + if (ueintx & (1<<RXSTPI)) + return -2; + if (!(ueintx & (1<<RXOUTI))) { + // Not ready to receive data + UEIENX = (1<<RXSTPE) | (1<<RXOUTE); + return -1; } - receive_pos = needcopy; + usb_read_packet(data, max_len); + if (UEINTX & (1<<RXSTPI)) + return -2; + UEINTX = ~(1<<RXOUTI); + return max_len; +} + +int_fast8_t +usb_read_ep0_setup(void *data, uint_fast8_t max_len) +{ + UENUM = 0; + uint8_t ueintx = UEINTX; + if (!(ueintx & ((1<<RXSTPI)))) { + // No data ready to read + UEIENX = 1<<RXSTPE; + return -1; + } + usb_read_packet(data, max_len); + UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI)); + return max_len; +} + +static int8_t +_usb_send_ep0(const void *data, uint8_t len, uint8_t progmem) +{ + UENUM = 0; + uint8_t ueintx = UEINTX; + if (ueintx & ((1<<RXSTPI) | (1<<RXOUTI))) + return -2; + if (!(ueintx & (1<<TXINI))) { + // Not ready to send + UEIENX = (1<<RXSTPE) | (1<<RXOUTE) | (1<<TXINE); + return -1; + } + if (progmem) + usb_write_packet_progmem(data, len); + else + usb_write_packet(data, len); + UEINTX = ~(1<<TXINI); + return len; +} + +int_fast8_t +usb_send_ep0(const void *data, uint_fast8_t len) +{ + return _usb_send_ep0(data, len, 0); +} + +int_fast8_t +usb_send_ep0_progmem(const void *data, uint_fast8_t len) +{ + return _usb_send_ep0(data, len, 1); } -// Process any incoming commands void -console_task(void) +usb_stall_ep0(void) { - console_check_input(); - uint_fast8_t pop_count; - int8_t ret = command_find_and_dispatch(receive_buf, receive_pos, &pop_count); - if (ret) - console_pop_input(pop_count); + UENUM = 0; + UECONX = (1<<STALLRQ) | (1<<EPEN); + UEIENX = 1<<RXSTPE; } -DECL_TASK(console_task); -// Encode and transmit a "response" message +static uint8_t set_address; + void -console_sendf(const struct command_encoder *ce, va_list args) +usb_set_address(uint_fast8_t addr) { - // Generate message - static uint8_t buf[MESSAGE_MAX]; - uint8_t msglen = command_encode_and_frame(buf, ce, args); + set_address = addr | (1<<ADDEN); + _usb_send_ep0(NULL, 0, 0); + UEIENX = (1<<RXSTPE) | (1<<TXINE); +} + +void +usb_set_configure(void) +{ + UENUM = USB_CDC_EP_ACM; + UECONX = 1<<EPEN; + UECFG0X = EP_TYPE_INTERRUPT_IN; + UECFG1X = EP_SIZE(USB_CDC_EP_ACM_SIZE) | EP_SINGLE_BUFFER; - // Transmit message - usb_serial_write((void*)buf, msglen); - usb_serial_flush_output(); + UENUM = USB_CDC_EP_BULK_OUT; + UECONX = 1<<EPEN; + UECFG0X = EP_TYPE_BULK_OUT; + UECFG1X = EP_SIZE(USB_CDC_EP_BULK_OUT_SIZE) | EP_DOUBLE_BUFFER; + UEIENX = 1<<RXOUTE; + + UENUM = USB_CDC_EP_BULK_IN; + UECONX = 1<<EPEN; + UECFG0X = EP_TYPE_BULK_IN; + UECFG1X = EP_SIZE(USB_CDC_EP_BULK_IN_SIZE) | EP_DOUBLE_BUFFER; + UEIENX = 1<<TXINE; +} + +void +usbserial_init(void) +{ + // Set USB controller to device mode + UHWCON = (1<<UIMOD) | (1<<UVREGE); + + // Enable USB clock + USBCON = (1<<USBE) | (1<<FRZCLK); + if (CONFIG_MACH_at90usb1286) + PLLCSR = (1<<PLLP2) | (1<<PLLP0) | (1<<PLLE); + else + PLLCSR = (1<<PLLP2) | (1<<PLLP1) | (1<<PLLE); + while (!(PLLCSR & (1<<PLOCK))) + ; + USBCON = (1<<USBE) | (1<<OTGPADE); + + // Enable USB pullup + UDCON = 0; + + // Enable interrupts + UDIEN = 1<<EORSTE; +} +DECL_INIT(usbserial_init); + +ISR(USB_GEN_vect) +{ + uint8_t udint = UDINT; + UDINT = 0; + if (udint & (1<<EORSTI)) { + // Configure endpoint 0 after usb reset completes + uint8_t old_uenum = UENUM; + UENUM = 0; + UECONX = 1<<EPEN; + UECFG0X = EP_TYPE_CONTROL; + UECFG1X = EP_SIZE(USB_CDC_EP0_SIZE) | EP_SINGLE_BUFFER; + UEIENX = 1<<RXSTPE; + UENUM = old_uenum; + } +} + +ISR(USB_COM_vect) +{ + uint8_t ueint = UEINT, old_uenum = UENUM; + if (ueint & (1<<0)) { + UENUM = 0; + UEIENX = 0; + usb_notify_ep0(); + + uint8_t ueintx = UEINTX; + if (!(ueintx & (1<<RXSTPI)) && (ueintx & (1<<TXINI)) && set_address) { + // Ack from set_address command sent - now update address + UDADDR = set_address; + set_address = 0; + } + } + if (ueint & (1<<USB_CDC_EP_BULK_OUT)) { + UENUM = USB_CDC_EP_BULK_OUT; + UEINTX = ~(1<<RXOUTI); + usb_notify_bulk_out(); + } + if (ueint & (1<<USB_CDC_EP_BULK_IN)) { + UENUM = USB_CDC_EP_BULK_IN; + UEINTX = ~((1<<RXOUTI) | (1<<TXINI)); + usb_notify_bulk_in(); + } + UENUM = old_uenum; +} + +void +usbserial_shutdown(void) +{ + UEIENX = 1<<RXSTPE; } +DECL_SHUTDOWN(usbserial_shutdown); |