-
-
Save shima-529/7906fea25daa103376674cac2eceff71 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stm32f0xx.h" | |
#include <usb_struct.h> | |
#include <usb_desc/usb_packet.h> | |
#include <stdio.h> | |
typedef struct | |
__attribute__((packed)) | |
tagPacketBuffer { | |
uint16_t addr_tx; | |
uint16_t count_tx; | |
uint16_t addr_rx; | |
uint16_t count_rx; | |
} PacketBuffer; | |
#define PMA ((volatile PacketBuffer *)USB_PMAADDR) | |
#define USB_PMASIZE 1024 | |
#define USB_EPnR(n) *(volatile uint16_t *)((uintptr_t)&USB->EP0R + 2 * (n)) | |
volatile static uint16_t pma_sp; | |
volatile static PacketBuffer *g_packet_buffer; | |
volatile static USBSetupPacket current_setup_packet; | |
volatile static uint16_t pma_packet_buffer_offset; | |
enum USBSetupPacketRequest { | |
GET_STATUS = 0, CLEAR_FEATURE = 1, SET_FEATURE = 3, | |
SET_ADDRESS = 5, GET_DESCRIPTOR = 6, SET_DESCRIPTOR = 7, | |
GET_CONFIGURATION = 8, SET_CONFIGURATION = 9, | |
GET_INTERFACE = 10, SET_INTERFACE = 11, SYNCH_FRAME = 12 | |
}; | |
static uint16_t alloc(int size) { | |
uint16_t ret = pma_sp; | |
pma_sp += size; | |
return ret; | |
} | |
static void dealloc(int size) { | |
pma_sp -= size; | |
} | |
static void pma_out(void *dest, uintptr_t src, int size) { | |
volatile uint16_t *src_p = (void *)src + USB_PMAADDR; | |
volatile uint16_t *dest_p = dest; | |
if( size & 1 ) size++; | |
size /= 2; | |
for(int i = 0; i < size; i++) { | |
*(dest_p + i) = *(src_p + i); | |
} | |
} | |
static void pma_in(uintptr_t dest, void *src, int size) { | |
volatile uint16_t *src_p = src; | |
volatile uint16_t *dest_p = (void *)dest + USB_PMAADDR; | |
if( size & 1 ) size++; | |
size /= 2; | |
for(int i = 0; i < size; i++) { | |
*(dest_p + i) = *(src_p + i); | |
} | |
} | |
void usb_init(void) { | |
RCC->APB1ENR |= RCC_APB1ENR_USBEN; | |
USB->CNTR &= ~USB_CNTR_PDWN; | |
for(volatile int i=0; i<100; i++); // wait for voltage to be stable | |
USB->CNTR &= ~USB_CNTR_FRES; | |
USB->BCDR |= USB_BCDR_DPPU; // pull-up DP so as to notify the connection to the host | |
USB->CNTR = USB_CNTR_RESETM; // enable reset interrupt | |
NVIC_SetPriority(USB_IRQn, 0); // Highest Priority | |
NVIC_EnableIRQ(USB_IRQn); | |
} | |
static void usb_endpoint_set_status(int endp, uint32_t status, uint32_t mask) { | |
const uint32_t reg = USB_EPnR(endp); | |
USB_EPnR(endp) = (reg & (USB_EPREG_MASK | status)) ^ status; | |
} | |
static void usb_ep0_send(uint16_t addr, int size) { | |
*(uint16_t *)&g_packet_buffer[0].addr_tx = addr; | |
*(uint16_t *)&g_packet_buffer[0].count_tx = size; | |
usb_endpoint_set_status(0, USB_EP_TX_VALID, USB_EPTX_STAT); | |
} | |
static void usb_ep0_receive(uint16_t addr, int size) { | |
*(uint16_t *)&g_packet_buffer[0].addr_rx = addr; | |
if( size > 62 ) { | |
*(uint16_t *)&g_packet_buffer[0].count_rx = (size / 32) << 10; | |
*(uint16_t *)&g_packet_buffer[0].count_rx |= 1 << 15; | |
}else{ | |
*(uint16_t *)&g_packet_buffer[0].count_rx = size << 10; | |
} | |
usb_endpoint_set_status(0, USB_EP_RX_VALID, USB_EPRX_STAT); | |
} | |
static void usb_ep0_handle_setup(void) { | |
if( current_setup_packet.bRequest == SET_ADDRESS ) { | |
USB->DADDR |= current_setup_packet.wValue & 0x7F; | |
usb_ep0_send(0, 0); | |
} | |
} | |
void USB_IRQHandler(void) { | |
uint32_t flag = USB->ISTR; | |
if( flag & USB_ISTR_RESET ) { | |
iprintf("\nRESET\n"); | |
USB->ISTR &= ~USB_ISTR_RESET; | |
USB->CNTR |= USB_CNTR_CTRM | USB_CNTR_RESETM; | |
pma_sp = 0; | |
USB->BTABLE = alloc(sizeof(PacketBuffer) * 1); | |
g_packet_buffer = (PacketBuffer *)((uintptr_t)USB->BTABLE + USB_PMAADDR); | |
USB->DADDR = USB_DADDR_EF; // enable the functionality | |
// initialize EP | |
USB->EP0R = USB_EP_CONTROL; | |
pma_packet_buffer_offset = alloc(sizeof(USBSetupPacket)); | |
usb_ep0_receive(pma_packet_buffer_offset, sizeof(USBSetupPacket)); | |
} | |
while( (flag = USB->ISTR) & USB_ISTR_CTR ) { | |
const int ep_num = flag & USB_ISTR_EP_ID; | |
const uint32_t epreg = USB_EPnR(ep_num); | |
if( ep_num == 0 ) { | |
if( flag & USB_ISTR_DIR ) { | |
// DIR == 1 : IRQ by SETUP transaction. CTR_RX is set. | |
USB_EPnR(0) = (epreg & ~USB_EP_CTR_RX & USB_EPREG_MASK); | |
if( epreg & USB_EP_SETUP ) { | |
pma_out((void *)¤t_setup_packet, pma_packet_buffer_offset, sizeof(USBSetupPacket)); | |
iprintf("** SETUP\n"); | |
iprintf("bmResuestType: %d\n", current_setup_packet.bmRequestType); | |
iprintf("bRequest: %d\n", current_setup_packet.bRequest); | |
iprintf("wLength: 0x%x\n", current_setup_packet.wLength); | |
iprintf("wValue: 0x%x\n", current_setup_packet.wValue); | |
usb_ep0_handle_setup(); | |
}else{ | |
// IRQ by OUT transaction | |
} | |
}else{ | |
// DIR = 0 : IRQ by IN transaction. CTR_TX is set. | |
USB_EPnR(0) = (epreg & ~USB_EP_CTR_TX & USB_EPREG_MASK); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment