Pinscape Controller version 1 fork. This is a fork to allow for ongoing bug fixes to the original controller version, from before the major changes for the expansion board project.
Dependencies: FastIO FastPWM SimpleDMA mbed
Fork of Pinscape_Controller by
Revision 56:c435f370f511, committed 2016-02-11
- Comitter:
- mjr
- Date:
- Thu Feb 11 20:24:50 2016 +0000
- Parent:
- 55:e47a4b7ab348
- Child:
- 57:20d54f25065a
- Commit message:
- Roll-forward #3 (superficial USBHAL_KL25Z changes)
Changed in this revision
USBDevice/USBDevice/USBHAL_KL25Z.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/USBDevice/USBDevice/USBHAL_KL25Z.cpp Thu Feb 11 19:14:12 2016 +0000 +++ b/USBDevice/USBDevice/USBHAL_KL25Z.cpp Thu Feb 11 20:24:50 2016 +0000 @@ -18,42 +18,90 @@ #if defined(TARGET_KL25Z) | defined(TARGET_KL46Z) | defined(TARGET_K20D5M) | defined(TARGET_K64F) +//#define DEBUG +#ifdef DEBUG +#define printd(fmt, ...) printf(fmt, __VA_ARGS__) +#else +#define printd(fmt, ...) +#endif + #include "USBHAL.h" +// Critical section controls. This module uses a bunch of static variables, +// and much of the code that accesses the statics can be called from either +// normal application context or IRQ context. Whenever a shared variable is +// accessed from code that can run in an application context, we have to +// protect against interrupts by entering a critical section. These macros +// enable and disable the USB IRQ if we're running in application context. +// (They do nothing if we're already in interrupt context, because the +// hardware interrupt controller won't generated another of the same IRQ +// that we're already handling. We could still be interrupted by a different, +// higher-priority IRQ, but our shared variables are only shared within this +// module, so they won't be affected by other interrupt handlers.) +static int inIRQ; +#define ENTER_CRITICAL_SECTION \ + if (!inIRQ) \ + NVIC_DisableIRQ(USB0_IRQn); +#define EXIT_CRITICAL_SECTION \ + if (!inIRQ) \ + NVIC_EnableIRQ(USB0_IRQn); + +// static singleton instance pointer USBHAL * USBHAL::instance; -static volatile int epComplete = 0; // Convert physical endpoint number to register bit #define EP(endpoint) (1<<(endpoint)) -// Convert physical to logical +// Convert physical endpoint number to logical endpoint number. +// Each logical endpoint has two physical endpoints, one RX and +// one TX. The physical endpoints are numbered in RX,TX pairs, +// so the logical endpoint number is simply the physical endpoint +// number divided by 2 (discarding the remainder). #define PHY_TO_LOG(endpoint) ((endpoint)>>1) -// Get endpoint direction +// Get a physical endpoint's direction. IN and OUT are from +// the host's perspective, so from our perspective on the device, +// IN == TX and OUT == RX. The physical endpoints are in RX,TX +// pairs, so the OUT/RX is the even numbered element of a pair +// and the IN/TX is the odd numbered element. #define IN_EP(endpoint) ((endpoint) & 1U ? true : false) #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true) -#define BD_OWN_MASK (1<<7) -#define BD_DATA01_MASK (1<<6) -#define BD_KEEP_MASK (1<<5) -#define BD_NINC_MASK (1<<4) -#define BD_DTS_MASK (1<<3) -#define BD_STALL_MASK (1<<2) +// BDT status flags, defined by the SIE hardware. These are +// bits packed into the 'info' byte of a BDT entry. +#define BD_OWN_MASK (1<<7) // OWN - hardware SIE owns the BDT (TX/RX in progress) +#define BD_DATA01_MASK (1<<6) // DATA01 - DATA0/DATA1 bit for current TX/RX on endpoint +#define BD_KEEP_MASK (1<<5) // KEEP - hardware keeps BDT ownership after token completes +#define BD_NINC_MASK (1<<4) // NO INCREMENT - buffer location is a FIFO, so use same address for all bytes +#define BD_DTS_MASK (1<<3) // DATA TOGGLE SENSING - hardware SIE checks for DATA0/DATA1 match during RX/TX +#define BD_STALL_MASK (1<<2) // STALL - SIE issues STALL handshake in reply to any host access to endpoint +// Endpoint direction (from DEVICE perspective) #define TX 1 #define RX 0 -#define ODD 0 -#define EVEN 1 -// this macro waits a physical endpoint number -#define EP_BDT_IDX(ep, dir, odd) (((ep * 4) + (2 * dir) + (1 * odd))) + +// Buffer parity. The hardware has a double-buffering scheme where each +// physical endpoint has two associated BDT entries, labeled EVEN and ODD. +// We disable the double buffering, so only the EVEN buffers are used in +// this implementation. +#define EVEN 0 +#define ODD 1 +// Get the BDT index for a given logical endpoint, direction, and buffer parity +#define EP_BDT_IDX(logep, dir, odd) ((((logep) * 4) + (2 * (dir)) + (1 * (odd)))) + +// Get the BDT index for a given physical endpoint and buffer parity +#define PEP_BDT_IDX(phyep, odd) (((phyep) * 2) + (1 * (odd))) + +// Token types reported in the BDT 'info' flags. +#define TOK_PID(idx) ((bdt[idx].info >> 2) & 0x0F) #define SETUP_TOKEN 0x0D #define IN_TOKEN 0x09 #define OUT_TOKEN 0x01 -#define TOK_PID(idx) ((bdt[idx].info >> 2) & 0x0F) -// for each endpt: 8 bytes +// Buffer Descriptor Table (BDT) entry. This is the hardware-defined +// memory structure for the shared memory block controlling an endpoint. typedef struct BDT { uint8_t info; // BD[0:7] uint8_t dummy; // RSVD: BD[8:15] @@ -62,18 +110,37 @@ } BDT; -// there are: -// * 16 bidirectionnal endpt -> 32 physical endpt -// * as there are ODD and EVEN buffer -> 32*2 bdt +// There are: +// * 16 bidirectional logical endpoints -> 32 physical endpoints +// * 2 BDT entries per endpoint (EVEN/ODD) -> 64 BDT entries __attribute__((__aligned__(512))) BDT bdt[NUMBER_OF_PHYSICAL_ENDPOINTS * 2]; uint8_t * endpoint_buffer[(NUMBER_OF_PHYSICAL_ENDPOINTS - 2) * 2]; uint8_t * endpoint_buffer_iso[2*2]; +// SET ADDRESS mode tracking. The address assignment has to be done in a +// specific order and with specific timing defined by the USB setup protocol +// standards. To get the sequencing right, we set a flag when we get the +// address message, and then set the address in the SIE when we're at the +// right subsequent packet step in the protocol exchange. These variables +// are just a place to stash the information between the time we receive the +// data and the time we're ready to update the SIE register. static uint8_t set_addr = 0; static uint8_t addr = 0; +// Endpoint DATA0/DATA1 bits, packed as a bit vector. Each endpoint's +// bit is at (1 << endpoint number). These track the current bit value +// on the endpoint. For TX endpoints, this is the bit for the LAST +// packet we sent (so the next packet will be the inverse). For RX +// endpoints, this is the bit value we expect for the NEXT packet. +// (Yes, it's inconsistent.) static uint32_t Data1 = 0x55555555; +// Endpoint read/write completion flags, packed as a bit vector. Each +// endpoint's bit is at (1 << endpoint number). A 1 bit signifies that +// the last read or write has completed (and hasn't had its result +// consumed yet). +static volatile int epComplete = 0; + static uint32_t frameNumber() { return((USB0->FRMNUML | (USB0->FRMNUMH << 8)) & 0x07FF); } @@ -215,13 +282,13 @@ if ((flags & ISOCHRONOUS) == 0) { handshake_flag = USB_ENDPT_EPHSHK_MASK; if (IN_EP(endpoint)) { - if (endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD)] == NULL) - endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD)] = (uint8_t *) malloc (64*2); - buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, ODD)][0]; + if (endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, EVEN)] == NULL) + endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, EVEN)] = (uint8_t *) malloc (64*2); + buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, TX, EVEN)][0]; } else { - if (endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)] == NULL) - endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)] = (uint8_t *) malloc (64*2); - buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)][0]; + if (endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, EVEN)] == NULL) + endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, EVEN)] = (uint8_t *) malloc (64*2); + buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, EVEN)][0]; } } else { if (IN_EP(endpoint)) { @@ -239,17 +306,17 @@ if (IN_EP(endpoint)) { USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | // ep handshaking (not if iso endpoint) USB_ENDPT_EPTXEN_MASK; // en TX (IN) tran - bdt[EP_BDT_IDX(log_endpoint, TX, ODD )].address = (uint32_t) buf; - bdt[EP_BDT_IDX(log_endpoint, TX, EVEN)].address = 0; + bdt[EP_BDT_IDX(log_endpoint, TX, EVEN )].address = (uint32_t) buf; + bdt[EP_BDT_IDX(log_endpoint, TX, ODD )].address = 0; } // OUT endpt -> host to device (RX) else { USB0->ENDPOINT[log_endpoint].ENDPT |= handshake_flag | // ep handshaking (not if iso endpoint) USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran. - bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket; - bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = (uint32_t) buf; - bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_OWN_MASK | BD_DTS_MASK; - bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = 0; + bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].byte_count = maxPacket; + bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].address = (uint32_t) buf; + bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = BD_OWN_MASK | BD_DTS_MASK; + bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = 0; } Data1 |= (1 << endpoint);