commit
e303de6dff
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
/**
|
||||
* @brief PAL setup.
|
||||
* @details Digital I/O ports static configuration as defined in @p board.h.
|
||||
* This variable is used by the HAL when initializing the PAL driver.
|
||||
*/
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
const PALConfig pal_default_config =
|
||||
{
|
||||
#if defined(PORTA)
|
||||
{VAL_PORTA, VAL_DDRA},
|
||||
#endif
|
||||
#if defined(PORTB)
|
||||
{VAL_PORTB, VAL_DDRB},
|
||||
#endif
|
||||
#if defined(PORTC)
|
||||
{VAL_PORTC, VAL_DDRC},
|
||||
#endif
|
||||
#if defined(PORTD)
|
||||
{VAL_PORTD, VAL_DDRD},
|
||||
#endif
|
||||
#if defined(PORTE)
|
||||
{VAL_PORTE, VAL_DDRE},
|
||||
#endif
|
||||
#if defined(PORTF)
|
||||
{VAL_PORTF, VAL_DDRF},
|
||||
#endif
|
||||
#if defined(PORTG)
|
||||
{VAL_PORTG, VAL_DDRG},
|
||||
#endif
|
||||
#if defined(PORTH)
|
||||
{VAL_PORTH, VAL_DDRH},
|
||||
#endif
|
||||
#if defined(PORTJ)
|
||||
{VAL_PORTJ, VAL_DDRJ},
|
||||
#endif
|
||||
#if defined(PORTK)
|
||||
{VAL_PORTK, VAL_DDRK},
|
||||
#endif
|
||||
#if defined(PORTL)
|
||||
{VAL_PORTL, VAL_DDRL},
|
||||
#endif
|
||||
};
|
||||
#endif /* HAL_USE_PAL */
|
||||
|
||||
/**
|
||||
* Board-specific initialization code.
|
||||
*/
|
||||
void boardInit(void) {
|
||||
|
||||
/*
|
||||
* External interrupts setup, all disabled initially.
|
||||
*/
|
||||
EICRA = 0x00;
|
||||
EICRB = 0x00;
|
||||
EIMSK = 0x00;
|
||||
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
/*
|
||||
* Setup for the PJRC Teensy2++ board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board identifier.
|
||||
*/
|
||||
#define BOARD_TEENSY_2PLUS
|
||||
#define BOARD_NAME "PJRC Teensy 2++"
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRA 0x00
|
||||
#define VAL_PORTA 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRB 0x00
|
||||
#define VAL_PORTB 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRC 0x00
|
||||
#define VAL_PORTC 0xFF
|
||||
|
||||
/* All inputs with pull-ups, LED on D6, serial TX1 on D3 */
|
||||
#define VAL_DDRD 0x48
|
||||
#define VAL_PORTD 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRE 0x00
|
||||
#define VAL_PORTE 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRF 0x00
|
||||
#define VAL_PORTF 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRG 0x00
|
||||
#define VAL_PORTG 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRH 0x00
|
||||
#define VAL_PORTH 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRJ 0x00
|
||||
#define VAL_PORTJ 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRK 0x00
|
||||
#define VAL_PORTK 0xFF
|
||||
|
||||
/* All inputs with pull-ups */
|
||||
#define VAL_DDRL 0x00
|
||||
#define VAL_PORTL 0xFF
|
||||
|
||||
#define BOARD_LED1 6
|
||||
|
||||
#if !defined(_FROM_ASM_)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void boardInit(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _FROM_ASM_ */
|
||||
|
||||
#endif /* _BOARD_H_ */
|
|
@ -1,5 +0,0 @@
|
|||
# List of all the board related files.
|
||||
BOARDSRC = ${CHIBIOS}/os/hal/boards/PJRC_TEENSY_2PLUS/board.c
|
||||
|
||||
# Required include directories
|
||||
BOARDINC = ${CHIBIOS}/os/hal/boards/PJRC_TEENSY_2PLUS
|
|
@ -49,8 +49,7 @@
|
|||
#define SPI1_MISO 3
|
||||
#elif defined(__AVR_AT90CAN128__) || \
|
||||
defined(__AVR_AT90CAN64__) || \
|
||||
defined(__AVR_AT90CAN32__) || \
|
||||
defined(__AVR_AT90USB1286__)
|
||||
defined(__AVR_AT90CAN32__)
|
||||
#define PIN_SPI1 PINB
|
||||
#define PORT_SPI1 PORTB
|
||||
#define DDR_SPI1 DDRB
|
||||
|
@ -82,8 +81,7 @@
|
|||
#define DDRADC DDRF
|
||||
#elif defined(__AVR_AT90CAN128__) || \
|
||||
defined(__AVR_AT90CAN64__) || \
|
||||
defined(__AVR_AT90CAN32__) || \
|
||||
defined(__AVR_AT90USB1286__)
|
||||
defined(__AVR_AT90CAN32__)
|
||||
#define PINADC PINF
|
||||
#define PORTADC PORTF
|
||||
#define DDRADC DDRF
|
||||
|
|
|
@ -9,8 +9,7 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/AVR/hal_lld.c \
|
|||
${CHIBIOS}/os/hal/ports/AVR/gpt_lld.c \
|
||||
${CHIBIOS}/os/hal/ports/AVR/pwm_lld.c \
|
||||
${CHIBIOS}/os/hal/ports/AVR/icu_lld.c \
|
||||
${CHIBIOS}/os/hal/ports/AVR/st_lld.c \
|
||||
${CHIBIOS}/os/hal/ports/AVR/usb_lld.c
|
||||
${CHIBIOS}/os/hal/ports/AVR/st_lld.c
|
||||
|
||||
# Required include directories
|
||||
PLATFORMINC = ${CHIBIOS}/os/hal/ports/AVR
|
||||
|
|
|
@ -1,891 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file usb_lld.c
|
||||
* @brief AVR USB subsystem low level driver source.
|
||||
*
|
||||
* @addtogroup USB
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#ifndef F_USB
|
||||
#define F_USB F_CPU
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief USB1 driver identifier.
|
||||
*/
|
||||
#if (AVR_USB_USE_USB1 == TRUE) || defined(__DOXYGEN__)
|
||||
USBDriver USBD1;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief EP0 state.
|
||||
* @note It is an union because IN and OUT endpoints are never used at the
|
||||
* same time for EP0.
|
||||
*/
|
||||
static union {
|
||||
/**
|
||||
* @brief IN EP0 state.
|
||||
*/
|
||||
USBInEndpointState in;
|
||||
/**
|
||||
* @brief OUT EP0 state.
|
||||
*/
|
||||
USBOutEndpointState out;
|
||||
} ep0_state;
|
||||
|
||||
/**
|
||||
* @brief EP0 initialization structure.
|
||||
*/
|
||||
static const USBEndpointConfig ep0config = {
|
||||
USB_EP_MODE_TYPE_CTRL,
|
||||
_usb_ep0setup,
|
||||
_usb_ep0in,
|
||||
_usb_ep0out,
|
||||
0x40,
|
||||
0x40,
|
||||
&ep0_state.in,
|
||||
&ep0_state.out
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef AVR_USB_PLL_OFF_IN_SUSPEND
|
||||
static __attribute__((unused)) void usb_pll_off(void) {
|
||||
PLLCSR = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usb_pll_on(void) {
|
||||
#if (F_USB == 8000000)
|
||||
#if (defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || \
|
||||
defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || \
|
||||
defined(__AVR_ATmega32U2__))
|
||||
#define PLL_VAL 0
|
||||
#elif (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
|
||||
#define PLL_VAL 0
|
||||
#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
#define PLL_VAL ((0 << PLLP2) | (1 << PLLP1) | (1 << PLLP0))
|
||||
#elif (defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__))
|
||||
#define PLL_VAL ((0 << PLLP2) | (1 << PLLP1) | (1 << PLLP0))
|
||||
#endif
|
||||
#elif (F_USB == 16000000)
|
||||
#if (defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || \
|
||||
defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || \
|
||||
defined(__AVR_ATmega32U2__))
|
||||
#define PLL_VAL ((0 << PLLP2) | (0 << PLLP1) | (1 << PLLP0))
|
||||
#elif (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
|
||||
#define PLL_VAL (1 << PINDIV)
|
||||
#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__))
|
||||
#define PLL_VAL ((1 << PLLP2) | (1 << PLLP1) | (0 << PLLP0))
|
||||
#elif (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__))
|
||||
#define PLL_VAL ((1 << PLLP2) | (0 << PLLP1) | (1 << PLLP0))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef PLL_VAL
|
||||
#error Could not determine PLL value, unsupported AVR USB model type
|
||||
#endif
|
||||
|
||||
#ifdef PLLFRQ
|
||||
/* This initializes PLL on supported devices for USB 48MHz *only* */
|
||||
PLLFRQ = (0 << PDIV3) | (1 << PDIV2) | (0 << PDIV1) | (0 << PDIV0);
|
||||
#endif
|
||||
|
||||
PLLCSR = PLL_VAL;
|
||||
PLLCSR = PLL_VAL | (1 << PLLE);
|
||||
}
|
||||
|
||||
static int usb_pll_is_locked(void) {
|
||||
return !!(PLLCSR & (1 << PLOCK));
|
||||
}
|
||||
|
||||
#include "dbg.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers and threads. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief USB general/OTG/device management event interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(USB_GEN_vect) {
|
||||
uint8_t usbint, udint;
|
||||
USBDriver *usbp = &USBD1;
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
usbint = USBINT;
|
||||
udint = UDINT;
|
||||
|
||||
if (usbint & (1 << VBUSTI)) {
|
||||
/* Connected. */
|
||||
#ifdef AVR_USB_PLL_OFF_IN_SUSPEND
|
||||
usb_pll_on();
|
||||
while (!usb_pll_is_locked()) {}
|
||||
#endif /* AVR_USB_PLL_OFF_IN_SUSPEND */
|
||||
|
||||
/* Attach to bus */
|
||||
usb_lld_connect_bus(usbp);
|
||||
USBINT &= ~(1 << VBUSTI);
|
||||
}
|
||||
|
||||
/* USB bus SUSPEND condition handling.*/
|
||||
if (udint & (1 << SUSPI)) {
|
||||
/* Disable suspend interrupt, enable WAKEUP interrupt */
|
||||
UDIEN |= (1 << WAKEUPE);
|
||||
UDINT &= ~(1 << WAKEUPI);
|
||||
UDIEN &= ~(1 << SUSPE);
|
||||
|
||||
/* Freeze the clock to reduce power consumption */
|
||||
USBCON |= (1 << FRZCLK);
|
||||
#ifdef AVR_USB_PLL_OFF_IN_SUSPEND
|
||||
usb_pll_off();
|
||||
#endif /* AVR_USB_PLL_OFF_IN_SUSPEND */
|
||||
|
||||
/* Clear the interrupt */
|
||||
UDINT &= ~(1 << SUSPI);
|
||||
|
||||
_usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND);
|
||||
}
|
||||
|
||||
/* USB bus WAKEUP condition handling.*/
|
||||
if (udint & (1 << WAKEUPI)) {
|
||||
#ifdef AVR_USB_PLL_OFF_IN_SUSPEND
|
||||
usb_pll_on();
|
||||
while (!usb_pll_is_locked()) {}
|
||||
#endif /* AVR_USB_PLL_OFF_IN_SUSPEND */
|
||||
|
||||
/* Unfreeze the clock */
|
||||
USBCON &= ~(1 << FRZCLK);
|
||||
|
||||
/* Clear & disable wakeup interrupt, enable suspend interrupt */
|
||||
UDINT &= ~(1 << WAKEUPI);
|
||||
UDIEN &= ~(1 << WAKEUPE);
|
||||
UDIEN |= (1 << SUSPE);
|
||||
|
||||
_usb_isr_invoke_event_cb(usbp, USB_EVENT_WAKEUP);
|
||||
}
|
||||
|
||||
/* USB bus RESUME condition handling.*/
|
||||
if (udint & (1 << EORSMI)) {
|
||||
UDINT &= ~(1 << EORSMI);
|
||||
UDIEN &= ~(1 << EORSME);
|
||||
}
|
||||
|
||||
/* USB bus reset condition handling.*/
|
||||
if (udint & (1 << EORSTI)) {
|
||||
UDINT &= ~(1 << EORSTI);
|
||||
|
||||
/* Clear & disable suspend interrupt, enable WAKEUP interrupt */
|
||||
UDINT &= ~(1 << SUSPI);
|
||||
UDIEN &= ~(1 << SUSPE);
|
||||
UDIEN |= (1 << WAKEUPE);
|
||||
|
||||
/* Reinitialize EP0. This is not mentioned in the datasheet but
|
||||
* apparently is required. */
|
||||
usb_lld_init_endpoint(usbp, 0);
|
||||
|
||||
_usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET);
|
||||
}
|
||||
|
||||
/* Start-Of-Frame handling, only if enabled */
|
||||
if ((UDIEN & (1 << SOFE)) && (udint & (1 << SOFI))) {
|
||||
_usb_isr_invoke_sof_cb(usbp);
|
||||
UDINT &= ~(1 << SOFI);
|
||||
}
|
||||
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
static void usb_fifo_write(USBDriver *usbp, usbep_t ep, size_t n) {
|
||||
const USBEndpointConfig *epcp = usbp->epc[ep];
|
||||
USBInEndpointState *isp = epcp->in_state;
|
||||
syssts_t sts;
|
||||
if (n > epcp->in_maxsize)
|
||||
n = epcp->in_maxsize;
|
||||
|
||||
/* Must lock for entire operation to ensure nothing changes the ENUM value */
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
UENUM = ep & 0xf;
|
||||
if (isp->txqueued) {
|
||||
output_queue_t *outq = isp->mode.queue.txqueue;
|
||||
uint8_t i; /* TODO not enough for a 256b endpoint! */
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint8_t b = *outq->q_rdptr++;
|
||||
UEDATX = b;
|
||||
if (outq->q_rdptr >= outq->q_top) {
|
||||
outq->q_rdptr = outq->q_buffer;
|
||||
}
|
||||
}
|
||||
/* Update queue state */
|
||||
outq->q_counter += n;
|
||||
osalThreadDequeueAllI(&outq->q_waiting, Q_OK);
|
||||
} else {
|
||||
uint8_t i; /* TODO not enough for a 256b endpoint! */
|
||||
for (i = 0; i < n; ++i) {
|
||||
UEDATX = isp->mode.linear.txbuf[i];
|
||||
}
|
||||
isp->mode.linear.txbuf += n;
|
||||
}
|
||||
isp->last_tx_size = n;
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
static void usb_fifo_read(USBDriver *usbp, usbep_t ep, size_t n) {
|
||||
const USBEndpointConfig *epcp = usbp->epc[ep];
|
||||
USBOutEndpointState *osp = epcp->out_state;
|
||||
syssts_t sts;
|
||||
if (n > epcp->out_maxsize)
|
||||
n = epcp->out_maxsize;
|
||||
|
||||
/* Must lock for entire operation to ensure nothing changes the ENUM value */
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
UENUM = ep & 0xf;
|
||||
if (osp->rxqueued) {
|
||||
input_queue_t *inq = osp->mode.queue.rxqueue;
|
||||
uint8_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint8_t b = UEDATX;
|
||||
*inq->q_wrptr++ = b;
|
||||
if (inq->q_wrptr >= inq->q_top) {
|
||||
inq->q_wrptr = inq->q_buffer;
|
||||
}
|
||||
}
|
||||
/* Update queue state */
|
||||
inq->q_counter += n;
|
||||
osalThreadDequeueAllI(&inq->q_waiting, Q_OK);
|
||||
} else {
|
||||
uint8_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
osp->mode.linear.rxbuf[i] = UEDATX;
|
||||
}
|
||||
osp->mode.linear.rxbuf += n;
|
||||
}
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
static void ep_isr(USBDriver *usbp, usbep_t ep) {
|
||||
const USBEndpointConfig *epcp = usbp->epc[ep];
|
||||
size_t n;
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
/* TODO: if stalling is needed/expected remove this check */
|
||||
osalDbgAssert(!(UEINTX & (1 << STALLEDI)), "Endpoint stalled!");
|
||||
|
||||
if ((UEIENX & (1 << TXINE)) && (UEINTX & (1 << TXINI))) {
|
||||
/* Ready to accept more IN data to transmit to host */
|
||||
/* Disable TXIN interrupt for now, will be re-enabled below if we
|
||||
* send more data */
|
||||
UEIENX &= ~(1 << TXINE);
|
||||
|
||||
/* Update transaction counts to reflect newly transmitted bytes */
|
||||
epcp->in_state->txcnt += epcp->in_state->last_tx_size;
|
||||
n = epcp->in_state->txsize - epcp->in_state->txcnt;
|
||||
if (n > 0) {
|
||||
/* Transfer not completed, there are more packets to send. */
|
||||
usb_fifo_write(usbp, ep, n);
|
||||
|
||||
osalSysLockFromISR();
|
||||
usb_lld_start_in(usbp, ep);
|
||||
osalSysUnlockFromISR();
|
||||
} else {
|
||||
UEINTX &= ~(1 << TXINI);
|
||||
_usb_isr_invoke_in_cb(usbp, ep);
|
||||
}
|
||||
}
|
||||
|
||||
if ((UEIENX & (1 << RXSTPE)) && (UEINTX & (1 << RXSTPI))) {
|
||||
/* Received SETUP data */
|
||||
/* Reset transaction state for endpoint */
|
||||
epcp->in_state->txcnt = 0;
|
||||
epcp->in_state->txsize = 0;
|
||||
epcp->in_state->last_tx_size = 0;
|
||||
/* Setup packets handling, setup packets are handled using a
|
||||
specific callback.*/
|
||||
_usb_isr_invoke_setup_cb(usbp, ep);
|
||||
} else if (UEINTX & (1 << RXOUTI)) {
|
||||
/* Received OUT data from host */
|
||||
if (ep == 0 && usbp->ep0state == USB_EP0_WAITING_STS) {
|
||||
/* SETUP/control transaction complete, invoke the callback. */
|
||||
n = 0;
|
||||
UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON));
|
||||
_usb_isr_invoke_out_cb(usbp, ep);
|
||||
} else {
|
||||
/* Check the FIFO byte count to see how many bytes were received */
|
||||
n = UEBCX;
|
||||
}
|
||||
if (n > 0) {
|
||||
usb_fifo_read(usbp, ep, n);
|
||||
|
||||
/* Mark OUT FIFO processed to allow more data to be received */
|
||||
UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON));
|
||||
|
||||
/* Transaction state update */
|
||||
epcp->out_state->rxcnt += n;
|
||||
epcp->out_state->rxsize -= n;
|
||||
epcp->out_state->rxpkts -= 1;
|
||||
if (n < epcp->out_maxsize || epcp->out_state->rxpkts == 0) {
|
||||
/* Transfer complete, invokes the callback.*/
|
||||
_usb_isr_invoke_out_cb(usbp, ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB communication event interrupt handler.
|
||||
*
|
||||
* @isr
|
||||
*/
|
||||
OSAL_IRQ_HANDLER(USB_COM_vect) {
|
||||
USBDriver *usbp = &USBD1;
|
||||
const uint8_t epnum_orig = UENUM;
|
||||
uint8_t epint = UEINT;
|
||||
uint8_t i;
|
||||
|
||||
OSAL_IRQ_PROLOGUE();
|
||||
|
||||
/* Figure out which endpoint(s) are interrupting */
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; ++i) {
|
||||
if (epint & (1 << i)) {
|
||||
ep_isr(usbp, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore endpoint selector to pre-interrupt state */
|
||||
UENUM = epnum_orig;
|
||||
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level USB driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_init(void) {
|
||||
#if AVR_USB_USE_USB1 == TRUE
|
||||
/* Driver initialization.*/
|
||||
usbObjectInit(&USBD1);
|
||||
|
||||
/* Start and lock the USB 48MHz PLL (takes ~100ms) */
|
||||
usb_pll_on();
|
||||
while (!usb_pll_is_locked()) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the USB peripheral.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_start(USBDriver *usbp) {
|
||||
if (usbp->state == USB_STOP) {
|
||||
/* Enables the peripheral.*/
|
||||
#if AVR_USB_USE_USB1 == TRUE
|
||||
if (&USBD1 == usbp) {
|
||||
uint8_t i;
|
||||
/*
|
||||
* Workaround: disable pad drivers as first step in case bootloader left
|
||||
* it on. Otherwise VBUS detection interrupt will not trigger later.
|
||||
*/
|
||||
USBCON &= ~(1 << OTGPADE);
|
||||
|
||||
/* Enable the internal 3.3V pad regulator */
|
||||
UHWCON |= (1 << UVREGE);
|
||||
|
||||
/* Reset and disable all endpoints */
|
||||
UERST = 0x7f;
|
||||
UERST = 0;
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; ++i){
|
||||
UENUM = i;
|
||||
UEIENX = 0;
|
||||
UEINTX = 0;
|
||||
UECFG1X = 0;
|
||||
UECONX &= ~(1 << EPEN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Reset procedure enforced on driver start.*/
|
||||
_usb_reset(usbp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the USB peripheral.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_stop(USBDriver *usbp) {
|
||||
if (usbp->state == USB_READY) {
|
||||
/* Disables the peripheral.*/
|
||||
#if AVR_USB_USE_USB1 == TRUE
|
||||
if (&USBD1 == usbp) {
|
||||
/* Disable and clear transition interrupts */
|
||||
USBCON &= ~((1 << VBUSTE) | (1 << IDTE));
|
||||
USBINT = 0;
|
||||
|
||||
/* Disable and clear device interrupts */
|
||||
UDIEN &= ~((1 << UPRSME) | (1 << EORSME) | (1 << WAKEUPE) | (1 << EORSTE)
|
||||
| (1 << SOFE) | (1 << SUSPE));
|
||||
UDINT = 0;
|
||||
|
||||
/* Freeze clock */
|
||||
USBCON |= (1 << FRZCLK);
|
||||
|
||||
/* Disable USB logic */
|
||||
USBCON &= ~(1 << USBE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB low level reset routine.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_reset(USBDriver *usbp) {
|
||||
/* Post-reset initialization.*/
|
||||
/* Reset and enable via toggling the USB macro logic overall enable bit */
|
||||
USBCON &= ~(1 << USBE);
|
||||
USBCON |= (1 << USBE);
|
||||
|
||||
/* Unfreeze clock */
|
||||
USBCON &= ~(1 << FRZCLK);
|
||||
|
||||
/* Set Device mode */
|
||||
/* TODO: Support HOST/OTG mode if needed */
|
||||
UHWCON |= (1 << UIMOD);
|
||||
|
||||
/* Set FULL 12mbps speed */
|
||||
UDCON &= ~(1 << LSM);
|
||||
|
||||
/* Enable device pin interrupt */
|
||||
USBCON |= (1 << VBUSTE);
|
||||
|
||||
/* EP0 initialization.*/
|
||||
UERST |= (1 << 0);
|
||||
UERST &= ~(1 << 0);
|
||||
usbp->epc[0] = &ep0config;
|
||||
usb_lld_init_endpoint(usbp, 0);
|
||||
|
||||
/* Enable device-level event interrupts */
|
||||
UDINT &= ~(1 << SUSPI);
|
||||
UDIEN = (1 << UPRSME) | (1 << EORSME) | (1 << WAKEUPE) | (1 << EORSTE)
|
||||
| (1 << SUSPE);
|
||||
/* The SOF interrupt is only enabled if a callback is defined for
|
||||
this service because it is a high rate source. */
|
||||
if (usbp->config->sof_cb != NULL)
|
||||
UDIEN |= (1 << SOFE);
|
||||
|
||||
/* Set OTG PAD to on which will trigger VBUS transition if plugged in. */
|
||||
USBCON |= (1 << OTGPADE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the USB address.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_set_address(USBDriver *usbp) {
|
||||
UDADDR = (UDADDR & (1 << ADDEN)) | (usbp->address & 0x7F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables the USB address match for subsequent packets.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_enable_address(USBDriver *usbp) {
|
||||
UDADDR |= (1 << ADDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables an endpoint.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
|
||||
uint16_t size = 0;
|
||||
const USBEndpointConfig *epcp = usbp->epc[ep];
|
||||
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
/* Enable endpoint to take out of reset */
|
||||
UECONX |= (1 << EPEN);
|
||||
|
||||
UECFG1X = 0;
|
||||
/* Set the endpoint type.*/
|
||||
switch (epcp->ep_mode & USB_EP_MODE_TYPE) {
|
||||
case USB_EP_MODE_TYPE_ISOC:
|
||||
UECFG0X = (0 << EPTYPE1) | (1 << EPTYPE0);
|
||||
break;
|
||||
case USB_EP_MODE_TYPE_BULK:
|
||||
UECFG0X = (1 << EPTYPE1) | (0 << EPTYPE0);
|
||||
break;
|
||||
case USB_EP_MODE_TYPE_INTR:
|
||||
UECFG0X = (1 << EPTYPE1) | (1 << EPTYPE0);
|
||||
break;
|
||||
default:
|
||||
UECFG0X = (0 << EPTYPE1) | (0 << EPTYPE0);
|
||||
}
|
||||
if ((epcp->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_CTRL) {
|
||||
/* CTRL endpoint */
|
||||
osalDbgCheck(epcp->in_maxsize == epcp->out_maxsize);
|
||||
size = epcp->in_maxsize;
|
||||
} else {
|
||||
osalDbgAssert(!(epcp->in_cb != NULL && epcp->out_cb != NULL),
|
||||
"On AVR each endpoint can be IN or OUT not both");
|
||||
|
||||
/* IN endpoint? */
|
||||
if (epcp->in_cb != NULL) {
|
||||
UECFG0X |= (1 << EPDIR);
|
||||
size = epcp->in_maxsize;
|
||||
}
|
||||
|
||||
/* OUT endpoint? */
|
||||
if (epcp->out_cb != NULL) {
|
||||
UECFG0X &= ~(1 << EPDIR);
|
||||
size = epcp->out_maxsize;
|
||||
}
|
||||
}
|
||||
|
||||
/* Endpoint size and address initialization. */
|
||||
switch (size) {
|
||||
case 8: UECFG1X = (0 << EPSIZE0) | (1 << ALLOC); break;
|
||||
case 16: UECFG1X = (1 << EPSIZE0) | (1 << ALLOC); break;
|
||||
case 32: UECFG1X = (2 << EPSIZE0) | (1 << ALLOC); break;
|
||||
case 64: UECFG1X = (3 << EPSIZE0) | (1 << ALLOC); break;
|
||||
case 128:
|
||||
osalDbgAssert(ep == 1, "Endpoint size of 128 bytes only valid for EP#1");
|
||||
UECFG1X = (4 << EPSIZE0) | (1 << ALLOC); break;
|
||||
case 256:
|
||||
osalSysHalt("256 byte endpoints not tested yet, uint8 overflow likely bugs!");
|
||||
osalDbgAssert(ep == 1, "Endpoint size of 256 bytes only valid for EP#1");
|
||||
UECFG1X = (5 << EPSIZE0) | (1 << ALLOC); break;
|
||||
default:
|
||||
osalDbgAssert(false, "Invalid size for USB endpoint");
|
||||
}
|
||||
|
||||
UEIENX |= (1 << RXSTPE) | (1 << RXOUTE) | (1 << STALLEDE) ;
|
||||
|
||||
osalDbgAssert((UESTA0X & (1 << CFGOK)),
|
||||
"Hardware reports endpoint config is INVALID");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the active endpoints except the endpoint zero.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_disable_endpoints(USBDriver *usbp) {
|
||||
uint8_t i;
|
||||
for (i = 1; i <= USB_MAX_ENDPOINTS; ++i) {
|
||||
UENUM = i;
|
||||
UECFG1X &= ~(1 << ALLOC);
|
||||
UECONX &= ~(1 << EPEN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the status of an OUT endpoint.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
* @return The endpoint status.
|
||||
* @retval EP_STATUS_DISABLED The endpoint is not active.
|
||||
* @retval EP_STATUS_STALLED The endpoint is stalled.
|
||||
* @retval EP_STATUS_ACTIVE The endpoint is active.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
if (!(UECONX & (1 << EPEN)))
|
||||
return EP_STATUS_DISABLED;
|
||||
if (UECONX & (1 << STALLRQ))
|
||||
return EP_STATUS_STALLED;
|
||||
return EP_STATUS_ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the status of an IN endpoint.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
* @return The endpoint status.
|
||||
* @retval EP_STATUS_DISABLED The endpoint is not active.
|
||||
* @retval EP_STATUS_STALLED The endpoint is stalled.
|
||||
* @retval EP_STATUS_ACTIVE The endpoint is active.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
|
||||
return usb_lld_get_status_out(usbp, ep);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a setup packet from the dedicated packet buffer.
|
||||
* @details This function must be invoked in the context of the @p setup_cb
|
||||
* callback in order to read the received setup packet.
|
||||
* @pre In order to use this function the endpoint must have been
|
||||
* initialized as a control endpoint.
|
||||
* @post The endpoint is ready to accept another packet.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
* @param[out] buf buffer where to copy the packet data
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
|
||||
uint8_t i;
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
*buf++ = UEDATX;
|
||||
}
|
||||
/* Clear FIFOCON and RXSTPI to drain the setup packet data from the FIFO */
|
||||
UEINTX &= ~((1 << FIFOCON) | (1 << RXSTPI));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ends a SETUP transaction
|
||||
* @details This function must be invoked in the context of the @p setup_cb
|
||||
* callback in order to finish an entire setup packet.
|
||||
* @pre In order to use this function the endpoint must have been
|
||||
* initialized as a control endpoint.
|
||||
* @post The endpoint is ready to accept another packet.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_end_setup(USBDriver *usbp, usbep_t ep) {
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) {
|
||||
/* Enable interrupt and wait for OUT packet */
|
||||
UEINTX &= ~((1 << FIFOCON) | (1 << RXOUTI));
|
||||
UEIENX |= (1 << RXOUTE);
|
||||
} else {
|
||||
/* Enable interrupt and wait for IN packet */
|
||||
UEINTX &= ~((1 << FIFOCON) | (1 << TXINI));
|
||||
UEIENX |= (1 << TXINI);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares for a receive operation.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep) {
|
||||
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
|
||||
/* Initialize transfer by recording how many packets we expect to receive. */
|
||||
if (osp->rxsize == 0) /* Special case for zero sized packets.*/
|
||||
osp->rxpkts = 1;
|
||||
else
|
||||
osp->rxpkts = (uint8_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) /
|
||||
usbp->epc[ep]->out_maxsize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares for a transmit operation.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep) {
|
||||
USBInEndpointState *isp = usbp->epc[ep]->in_state;
|
||||
|
||||
/* Initialize transfer by filling FIFO with passed data. */
|
||||
usb_fifo_write(usbp, ep, isp->txsize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a receive operation on an OUT endpoint.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
|
||||
syssts_t sts;
|
||||
(void)usbp;
|
||||
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
/* Must lock for entire operation to ensure nothing changes the ENUM value */
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
UEIENX |= (1 << RXOUTE);
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts a transmit operation on an IN endpoint.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
|
||||
syssts_t sts;
|
||||
(void)usbp;
|
||||
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
/* Must lock for entire operation to ensure nothing changes the ENUM value */
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
/* Clear FIFOCON to send the data in the FIFO and switch bank */
|
||||
UEINTX &= ~((1 << TXINI) | (1 << FIFOCON));
|
||||
|
||||
/* Enable the TX complete interrupt */
|
||||
UEIENX |= (1 << TXINE);
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Brings an OUT endpoint in the stalled state.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
|
||||
syssts_t sts;
|
||||
(void)usbp;
|
||||
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
/* Must lock for entire operation to ensure nothing changes the ENUM value */
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
UECONX |= (1 << STALLRQ);
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Brings an IN endpoint in the stalled state.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
|
||||
usb_lld_stall_out(usbp, ep);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Brings an OUT endpoint in the active state.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
|
||||
syssts_t sts;
|
||||
(void)usbp;
|
||||
|
||||
/* Select this endpoint number for subsequent commands */
|
||||
/* Must lock for entire operation to ensure nothing changes the ENUM value */
|
||||
sts = osalSysGetStatusAndLockX();
|
||||
UENUM = ep & 0xf;
|
||||
|
||||
UECONX |= (1 << STALLRQC);
|
||||
osalSysRestoreStatusX(sts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Brings an IN endpoint in the active state.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
|
||||
usb_lld_clear_out(usbp, ep);
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_USB == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,397 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file usb_lld.h
|
||||
* @brief AVR USB subsystem low level driver header.
|
||||
*
|
||||
* @addtogroup USB
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _USB_LLD_H_
|
||||
#define _USB_LLD_H_
|
||||
|
||||
#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Maximum endpoint address.
|
||||
*/
|
||||
#define USB_MAX_ENDPOINTS 7
|
||||
|
||||
/**
|
||||
* @brief Status stage handling method.
|
||||
*/
|
||||
#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_HW
|
||||
|
||||
/**
|
||||
* @brief The address can be changed immediately upon packet reception.
|
||||
*/
|
||||
#define USB_SET_ADDRESS_MODE USB_EARLY_SET_ADDRESS
|
||||
|
||||
/**
|
||||
* @brief Method for set address acknowledge.
|
||||
*/
|
||||
#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name AVR configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief USB driver enable switch.
|
||||
* @details If set to @p TRUE the support for USB1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(AVR_USB_USE_USB1) || defined(__DOXYGEN__)
|
||||
#define AVR_USB_USE_USB1 FALSE
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of an IN endpoint state structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Buffer mode, queue or linear.
|
||||
*/
|
||||
bool txqueued;
|
||||
/**
|
||||
* @brief Requested transmit transfer size.
|
||||
*/
|
||||
size_t txsize;
|
||||
/**
|
||||
* @brief Transmitted bytes so far.
|
||||
*/
|
||||
size_t txcnt;
|
||||
union {
|
||||
struct {
|
||||
/**
|
||||
* @brief Pointer to the transmission linear buffer.
|
||||
*/
|
||||
const uint8_t *txbuf;
|
||||
} linear;
|
||||
struct {
|
||||
/**
|
||||
* @brief Pointer to the output queue.
|
||||
*/
|
||||
output_queue_t *txqueue;
|
||||
} queue;
|
||||
/* End of the mandatory fields.*/
|
||||
} mode;
|
||||
/**
|
||||
* @brief Number of expected bytes in the most recent transmisson.
|
||||
*/
|
||||
uint8_t last_tx_size;
|
||||
} USBInEndpointState;
|
||||
|
||||
/**
|
||||
* @brief Type of an OUT endpoint state structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Buffer mode, queue or linear.
|
||||
*/
|
||||
bool rxqueued;
|
||||
/**
|
||||
* @brief Requested receive transfer size.
|
||||
*/
|
||||
size_t rxsize;
|
||||
/**
|
||||
* @brief Received bytes so far.
|
||||
*/
|
||||
size_t rxcnt;
|
||||
union {
|
||||
struct {
|
||||
/**
|
||||
* @brief Pointer to the receive linear buffer.
|
||||
*/
|
||||
uint8_t *rxbuf;
|
||||
} linear;
|
||||
struct {
|
||||
/**
|
||||
* @brief Pointer to the input queue.
|
||||
*/
|
||||
input_queue_t *rxqueue;
|
||||
} queue;
|
||||
} mode;
|
||||
/* End of the mandatory fields.*/
|
||||
uint8_t rxpkts;
|
||||
} USBOutEndpointState;
|
||||
|
||||
/**
|
||||
* @brief Type of an USB endpoint configuration structure.
|
||||
* @note Platform specific restrictions may apply to endpoints.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Type and mode of the endpoint.
|
||||
*/
|
||||
uint32_t ep_mode;
|
||||
/**
|
||||
* @brief Setup packet notification callback.
|
||||
* @details This callback is invoked when a setup packet has been
|
||||
* received.
|
||||
* @post The application must immediately call @p usbReadPacket() in
|
||||
* order to access the received packet.
|
||||
* @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL
|
||||
* endpoints, it should be set to @p NULL for other endpoint
|
||||
* types.
|
||||
*/
|
||||
usbepcallback_t setup_cb;
|
||||
/**
|
||||
* @brief IN endpoint notification callback.
|
||||
* @details This field must be set to @p NULL if the IN endpoint is not
|
||||
* used.
|
||||
*/
|
||||
usbepcallback_t in_cb;
|
||||
/**
|
||||
* @brief OUT endpoint notification callback.
|
||||
* @details This field must be set to @p NULL if the OUT endpoint is not
|
||||
* used.
|
||||
*/
|
||||
usbepcallback_t out_cb;
|
||||
/**
|
||||
* @brief IN endpoint maximum packet size.
|
||||
* @details This field must be set to zero if the IN endpoint is not
|
||||
* used.
|
||||
*/
|
||||
uint16_t in_maxsize;
|
||||
/**
|
||||
* @brief OUT endpoint maximum packet size.
|
||||
* @details This field must be set to zero if the OUT endpoint is not
|
||||
* used.
|
||||
*/
|
||||
uint16_t out_maxsize;
|
||||
/**
|
||||
* @brief @p USBEndpointState associated to the IN endpoint.
|
||||
* @details This structure maintains the state of the IN endpoint.
|
||||
*/
|
||||
USBInEndpointState *in_state;
|
||||
/**
|
||||
* @brief @p USBEndpointState associated to the OUT endpoint.
|
||||
* @details This structure maintains the state of the OUT endpoint.
|
||||
*/
|
||||
USBOutEndpointState *out_state;
|
||||
/* End of the mandatory fields.*/
|
||||
} USBEndpointConfig;
|
||||
|
||||
/**
|
||||
* @brief Type of an USB driver configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief USB events callback.
|
||||
* @details This callback is invoked when an USB driver event is registered.
|
||||
*/
|
||||
usbeventcb_t event_cb;
|
||||
/**
|
||||
* @brief Device GET_DESCRIPTOR request callback.
|
||||
* @note This callback is mandatory and cannot be set to @p NULL.
|
||||
*/
|
||||
usbgetdescriptor_t get_descriptor_cb;
|
||||
/**
|
||||
* @brief Requests hook callback.
|
||||
* @details This hook allows to be notified of standard requests or to
|
||||
* handle non standard requests.
|
||||
*/
|
||||
usbreqhandler_t requests_hook_cb;
|
||||
/**
|
||||
* @brief Start Of Frame callback.
|
||||
*/
|
||||
usbcallback_t sof_cb;
|
||||
/* End of the mandatory fields.*/
|
||||
} USBConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an USB driver.
|
||||
*/
|
||||
struct USBDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
usbstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const USBConfig *config;
|
||||
/**
|
||||
* @brief Bit map of the transmitting IN endpoints.
|
||||
*/
|
||||
uint8_t transmitting;
|
||||
/**
|
||||
* @brief Bit map of the receiving OUT endpoints.
|
||||
*/
|
||||
uint8_t receiving;
|
||||
/**
|
||||
* @brief Active endpoints configurations.
|
||||
*/
|
||||
const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1];
|
||||
/**
|
||||
* @brief Fields available to user, it can be used to associate an
|
||||
* application-defined handler to an IN endpoint.
|
||||
* @note The base index is one, the endpoint zero does not have a
|
||||
* reserved element in this array.
|
||||
*/
|
||||
void *in_params[USB_MAX_ENDPOINTS];
|
||||
/**
|
||||
* @brief Fields available to user, it can be used to associate an
|
||||
* application-defined handler to an OUT endpoint.
|
||||
* @note The base index is one, the endpoint zero does not have a
|
||||
* reserved element in this array.
|
||||
*/
|
||||
void *out_params[USB_MAX_ENDPOINTS];
|
||||
/**
|
||||
* @brief Endpoint 0 state.
|
||||
*/
|
||||
usbep0state_t ep0state;
|
||||
/**
|
||||
* @brief Next position in the buffer to be transferred through endpoint 0.
|
||||
*/
|
||||
uint8_t *ep0next;
|
||||
/**
|
||||
* @brief Number of bytes yet to be transferred through endpoint 0.
|
||||
*/
|
||||
size_t ep0n;
|
||||
/**
|
||||
* @brief Endpoint 0 end transaction callback.
|
||||
*/
|
||||
usbcallback_t ep0endcb;
|
||||
/**
|
||||
* @brief Setup packet buffer.
|
||||
*/
|
||||
uint8_t setup[8];
|
||||
/**
|
||||
* @brief Current USB device status.
|
||||
*/
|
||||
uint16_t status;
|
||||
/**
|
||||
* @brief Assigned USB address.
|
||||
*/
|
||||
uint8_t address;
|
||||
/**
|
||||
* @brief Current USB device configuration.
|
||||
*/
|
||||
uint8_t configuration;
|
||||
#if defined(USB_DRIVER_EXT_FIELDS)
|
||||
USB_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Returns the current frame number.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @return The current frame number.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define usb_lld_get_frame_number(usbp) (UDFNUM)
|
||||
|
||||
/**
|
||||
* @brief Returns the exact size of a receive transaction.
|
||||
* @details The received size can be different from the size specified in
|
||||
* @p usbStartReceiveI() because the last packet could have a size
|
||||
* different from the expected one.
|
||||
* @pre The OUT endpoint must have been configured in transaction mode
|
||||
* in order to use this function.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
* @param[in] ep endpoint number
|
||||
* @return Received data size.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define usb_lld_get_transaction_size(usbp, ep) \
|
||||
((usbp)->epc[ep]->out_state->rxcnt)
|
||||
|
||||
/**
|
||||
* @brief Connects the USB device.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define usb_lld_connect_bus(usbp) (UDCON &= ~(1 << DETACH))
|
||||
|
||||
/**
|
||||
* @brief Disconnect the USB device.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define usb_lld_disconnect_bus(usbp) (UDCON |= (1 << DETACH))
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (AVR_USB_USE_USB1 == TRUE) && !defined(__DOXYGEN__)
|
||||
extern USBDriver USBD1;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void usb_lld_init(void);
|
||||
void usb_lld_start(USBDriver *usbp);
|
||||
void usb_lld_stop(USBDriver *usbp);
|
||||
void usb_lld_reset(USBDriver *usbp);
|
||||
void usb_lld_set_address(USBDriver *usbp);
|
||||
void usb_lld_enable_address(USBDriver *usbp);
|
||||
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_disable_endpoints(USBDriver *usbp);
|
||||
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
|
||||
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
|
||||
void usb_lld_end_setup(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_start_out(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_start_in(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_USB == TRUE */
|
||||
|
||||
#endif /* _USB_LLD_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1102,17 +1102,6 @@ void usb_lld_set_address(USBDriver *usbp) {
|
|||
otgp->DCFG = (otgp->DCFG & ~DCFG_DAD_MASK) | DCFG_DAD(usbp->address);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables the USB address match for subsequent packets.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_enable_address(USBDriver *usbp) {
|
||||
(void)usbp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables an endpoint.
|
||||
*
|
||||
|
|
|
@ -547,7 +547,6 @@ extern "C" {
|
|||
void usb_lld_stop(USBDriver *usbp);
|
||||
void usb_lld_reset(USBDriver *usbp);
|
||||
void usb_lld_set_address(USBDriver *usbp);
|
||||
void usb_lld_enable_address(USBDriver *usbp);
|
||||
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_disable_endpoints(USBDriver *usbp);
|
||||
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
|
||||
|
|
|
@ -556,17 +556,6 @@ void usb_lld_set_address(USBDriver *usbp) {
|
|||
STM32_USB->DADDR = (uint32_t)(usbp->address) | DADDR_EF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables the USB address match for subsequent packets.
|
||||
*
|
||||
* @param[in] usbp pointer to the @p USBDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void usb_lld_enable_address(USBDriver *usbp) {
|
||||
(void)usbp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables an endpoint.
|
||||
*
|
||||
|
|
|
@ -457,7 +457,6 @@ extern "C" {
|
|||
void usb_lld_stop(USBDriver *usbp);
|
||||
void usb_lld_reset(USBDriver *usbp);
|
||||
void usb_lld_set_address(USBDriver *usbp);
|
||||
void usb_lld_enable_address(USBDriver *usbp);
|
||||
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
|
||||
void usb_lld_disable_endpoints(USBDriver *usbp);
|
||||
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
|
||||
|
|
|
@ -119,7 +119,7 @@ static bool default_handler(USBDriver *usbp) {
|
|||
(usbp->setup[1] == USB_REQ_SET_ADDRESS)) {
|
||||
set_address(usbp);
|
||||
}
|
||||
usbSetupTransfer(usbp, NULL, 0, usb_lld_enable_address);
|
||||
usbSetupTransfer(usbp, NULL, 0, NULL);
|
||||
#else
|
||||
usbSetupTransfer(usbp, NULL, 0, set_address);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue