Commit b30c02af authored by Damien George's avatar Damien George
Browse files

stmhal: Get USB enumerating a CDC device.

Enumerates CDC device over USB, but doesn't transmit/receive yet.
parent 536dde25
......@@ -8,9 +8,8 @@ include ../py/py.mk
CMSIS_DIR=cmsis
HAL_DIR=hal
#STMUSB_DIR=stmusb
#STMUSBD_DIR=stmusbd
#STMUSBH_DIR=stmusbh
USBDEV_DIR=usbdev
#USBHOST_DIR=usbhost
#FATFS_DIR=fatfs
#CC3K_DIR=cc3k
DFU=../tools/dfu.py
......@@ -22,9 +21,8 @@ INC += -I$(PY_SRC)
INC += -I$(CMSIS_DIR)/inc
INC += -I$(CMSIS_DIR)/devinc
INC += -I$(HAL_DIR)/inc
#INC += -I$(STMUSB_DIR)
#INC += -I$(STMUSBD_DIR)
#INC += -I$(STMUSBH_DIR)
INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc/inc
#INC += -I$(USBHOST_DIR)
#INC += -I$(FATFS_DIR)
#INC += -I$(CC3K_DIR)
......@@ -57,10 +55,15 @@ SRC_C = \
system_stm32f4xx.c \
stm32f4xx_it.c \
stm32f4xx_hal_msp.c \
usbd_conf.c \
usbd_desc.c \
usbd_cdc_interface.c \
pendsv.c \
systick.c \
led.c \
pin.c \
usart.c \
usb.c \
printf.c \
math.c \
malloc0.c \
......@@ -70,14 +73,12 @@ SRC_C = \
import.c \
lexerfatfs.c \
# pendsv.c \
# gpio.c \
# lcd.c \
# servo.c \
# flash.c \
# storage.c \
# accel.c \
# usb.c \
# timer.c \
# audio.c \
# sdcard.c \
......@@ -100,8 +101,10 @@ SRC_HAL = $(addprefix $(HAL_DIR)/src/,\
stm32f4xx_hal_cortex.c \
stm32f4xx_hal_dma.c \
stm32f4xx_hal_gpio.c \
stm32f4xx_hal_pcd.c \
stm32f4xx_hal_rcc.c \
stm32f4xx_hal_uart.c \
stm32f4xx_ll_usb.c \
)
SRC_STMPERIPH = $(addprefix $(STMPERIPH_DIR)/,\
......@@ -136,8 +139,14 @@ SRC_STMUSB = $(addprefix $(STMUSB_DIR)/,\
)
# usb_otg.c \
SRC_STMUSBD = $(addprefix $(STMUSBD_DIR)/,\
usbd_core.c \
SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
core/src/usbd_core.c \
core/src/usbd_ctlreq.c \
core/src/usbd_ioreq.c \
class/cdc/src/usbd_cdc.c \
)
# usbd_core.c \
usbd_ioreq.c \
usbd_req.c \
usbd_usr.c \
......@@ -186,7 +195,7 @@ OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSB:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBD:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBH:.c=.o))
#OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o))
......
......@@ -47,6 +47,7 @@
/* Exported constants --------------------------------------------------------*/
#define STM32F405xx
#define USE_USB_FS
/* ########################## Module Selection ############################## */
/**
......
......@@ -20,6 +20,7 @@
#include "misc.h"
#include "systick.h"
#include "pendsv.h"
#include "led.h"
#include "usart.h"
#include "mpconfig.h"
......@@ -37,16 +38,15 @@
#include "gccollect.h"
#include "pyexec.h"
#include "pybmodule.h"
#include "usb.h"
#if 0
#include "ff.h"
#include "lexerfatfs.h"
#include "pendsv.h"
#include "servo.h"
#include "lcd.h"
#include "storage.h"
#include "sdcard.h"
#include "accel.h"
#include "usb.h"
#include "timer.h"
#include "pybwlan.h"
#include "usrsw.h"
......@@ -82,8 +82,10 @@ void flash_error(int n) {
void __fatal_error(const char *msg) {
#if MICROPY_HW_HAS_LCD
#if 0
lcd_print_strn("\nFATAL ERROR:\n", 14);
lcd_print_strn(msg, strlen(msg));
#endif
#endif
for (;;) {
flash_error(1);
......@@ -116,6 +118,9 @@ void fatality(void) {
led_state(PYB_LED_G1, 1);
led_state(PYB_LED_R2, 1);
led_state(PYB_LED_G2, 1);
for (;;) {
flash_error(1);
}
}
static const char fresh_boot_py[] =
......@@ -244,9 +249,7 @@ int main(void) {
// basic sub-system init
sys_tick_init();
#if 0
pendsv_init();
#endif
led_init();
#if 0
......@@ -469,6 +472,7 @@ soft_reset:
}
}
#endif
#endif
#ifdef USE_HOST_MODE
// USB host
......@@ -478,6 +482,22 @@ soft_reset:
pyb_usb_dev_init(PYB_USB_DEV_VCP_MSC);
#endif
#if 0
// test USB CDC
extern uint8_t UserTxBuffer[];/* Received Data over UART (CDC interface) are stored in this buffer */
extern uint32_t UserTxBufPtrOut; /* Increment this pointer or roll it back to
start address when data are sent over USB */
for (;;) {
UserTxBuffer[UserTxBufPtrOut++] = 'a';
UserTxBuffer[UserTxBufPtrOut++] = 'b';
UserTxBuffer[UserTxBufPtrOut++] = 'c';
UserTxBuffer[UserTxBufPtrOut++] = 'd';
HAL_Delay(500);
led_toggle(PYB_LED_BLUE);
}
#endif
#if 0
// run main script
{
vstr_t *vstr = vstr_new();
......
#include <stdlib.h>
#include <stm32f4xx_hal.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "pendsv.h"
static void *pendsv_object = NULL;
void pendsv_init(void) {
// set PendSV interrupt at lowest priority
HAL_NVIC_SetPriority(PendSV_IRQn, 0xf, 0xf);
}
// call this function to raise a pending exception during an interrupt
// it will wait until all interrupts are finished then raise the given
// exception object using nlr_jump in the context of the top-level thread
void pendsv_nlr_jump(void *o) {
pendsv_object = o;
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
// since we play tricks with the stack, the compiler must not generate a
// prelude for this function
void pendsv_isr_handler(void) __attribute__((naked));
void pendsv_isr_handler(void) {
// re-jig the stack so that when we return from this interrupt handler
// it returns instead to nlr_jump with argument pendsv_object
// note that stack has a different layout if DEBUG is enabled
//
// on entry to this (naked) function, stack has the following layout:
//
// stack layout with DEBUG disabled:
// sp[6]: pc
// sp[5]: ?
// sp[4]: ?
// sp[3]: ?
// sp[2]: ?
// sp[1]: ?
// sp[0]: r0
//
// stack layout with DEBUG enabled:
// sp[8]: pc
// sp[7]: lr
// sp[6]: ?
// sp[5]: ?
// sp[4]: ?
// sp[3]: ?
// sp[2]: r0
// sp[1]: 0xfffffff9
// sp[0]: ?
__asm volatile (
"ldr r0, pendsv_object_ptr\n"
"ldr r0, [r0]\n"
#if defined(PENDSV_DEBUG)
"str r0, [sp, #8]\n"
#else
"str r0, [sp, #0]\n"
#endif
"ldr r0, nlr_jump_ptr\n"
#if defined(PENDSV_DEBUG)
"str r0, [sp, #32]\n"
#else
"str r0, [sp, #24]\n"
#endif
"bx lr\n"
".align 2\n"
"pendsv_object_ptr: .word pendsv_object\n"
"nlr_jump_ptr: .word nlr_jump\n"
);
/*
uint32_t x[2] = {0x424242, 0xdeaddead};
printf("PendSV: %p\n", x);
for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) {
printf(" %p: %08x %08x %08x %08x\n", p, (uint)p[0], (uint)p[1], (uint)p[2], (uint)p[3]);
}
*/
}
void pendsv_init(void);
void pendsv_nlr_jump(void *val);
void pendsv_isr_handler(void);
......@@ -56,6 +56,9 @@
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
extern void fatality();
extern PCD_HandleTypeDef hpcd;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
......@@ -82,6 +85,7 @@ void HardFault_Handler(void)
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
fatality();
}
}
......@@ -95,6 +99,7 @@ void MemManage_Handler(void)
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
fatality();
}
}
......@@ -108,6 +113,7 @@ void BusFault_Handler(void)
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
fatality();
}
}
......@@ -121,6 +127,7 @@ void UsageFault_Handler(void)
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
fatality();
}
}
......@@ -149,6 +156,8 @@ void DebugMon_Handler(void)
*/
void PendSV_Handler(void)
{
extern void pendsv_isr_handler(void);
pendsv_isr_handler();
}
/**
......@@ -158,7 +167,7 @@ void PendSV_Handler(void)
*/
void SysTick_Handler(void)
{
HAL_IncTick();
HAL_IncTick();
}
/******************************************************************************/
......@@ -168,6 +177,72 @@ void SysTick_Handler(void)
/* file (startup_stm32f4xx.s). */
/******************************************************************************/
/**
* @brief This function handles USB-On-The-Go FS global interrupt request.
* @param None
* @retval None
*/
#ifdef USE_USB_FS
void OTG_FS_IRQHandler(void)
#elif defined(USE_USB_HS)
void OTG_HS_IRQHandler(void)
#endif
{
HAL_PCD_IRQHandler(&hpcd);
}
/**
* @brief This function handles USB OTG FS or HS Wakeup IRQ Handler.
* @param None
* @retval None
*/
#ifdef USE_USB_FS
void OTG_FS_WKUP_IRQHandler(void)
#elif defined(USE_USB_HS)
void OTG_HS_WKUP_IRQHandler(void)
#endif
{
if((&hpcd)->Init.low_power_enable)
{
/* Reset SLEEPDEEP bit of Cortex System Control Register */
SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
/* Configures system clock after wake-up from STOP: enable HSE, PLL and select
PLL as system clock source (HSE and PLL are disabled in STOP mode) */
__HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
/* Wait till HSE is ready */
while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{}
/* Enable the main PLL. */
__HAL_RCC_PLL_ENABLE();
/* Wait till PLL is ready */
while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
{}
/* Select PLL as SYSCLK */
MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_SYSCLKSOURCE_PLLCLK);
while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL)
{}
/* ungate PHY clock */
__HAL_PCD_UNGATE_PHYCLOCK((&hpcd));
}
#ifdef USE_USB_FS
/* Clear EXTI pending Bit*/
__HAL_USB_FS_EXTI_CLEAR_FLAG();
#elif defined(USE_USB_HS)
/* Clear EXTI pending Bit*/
__HAL_USB_HS_EXTI_CLEAR_FLAG();
#endif
}
/**
* @brief This function handles PPP interrupt request.
* @param None
......
......@@ -58,6 +58,11 @@ void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
#ifdef USE_USB_FS
void OTG_FS_IRQHandler(void);
#elif defined(USE_USB_HS)
void OTG_HS_IRQHandler(void);
#endif
#ifdef __cplusplus
}
......
#include <string.h>
/*
#include "usb_core.h"
#include "usbd_cdc_core.h"
#include "usbd_pyb_core.h"
#include "usbd_usr.h"
*/
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_cdc.h"
#include "usbd_cdc_interface.h"
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "pendsv.h"
#include "usb.h"
#ifdef USE_DEVICE_MODE
//extern CDC_IF_Prop_TypeDef VCP_fops;
USBD_HandleTypeDef hUSBDDevice;
#endif
static int dev_is_enabled = 0;
uint32_t APP_dev_is_connected = 0; /* used by usbd_cdc_vcp */
static char rx_buf[64];
static int rx_buf_in;
static int rx_buf_out;
static int interrupt_char = VCP_CHAR_NONE;
mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
void pyb_usb_dev_init(int usb_dev_type) {
#ifdef USE_DEVICE_MODE
if (!dev_is_enabled) {
// only init USB once in the device's power-lifetime
switch (usb_dev_type) {
case PYB_USB_DEV_VCP_MSC:
// XXX USBD_CDC_Init (called by one of these functions below) uses malloc,
// so the memory is invalid after a soft reset (which resets the GC).
USBD_Init(&hUSBDDevice, &VCP_Desc, 0);
USBD_RegisterClass(&hUSBDDevice, &USBD_CDC);
USBD_CDC_RegisterInterface(&hUSBDDevice, &USBD_CDC_fops);
USBD_Start(&hUSBDDevice);
//USBD_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_PYB_cb, &USR_cb);
break;
case PYB_USB_DEV_HID:
//USBD_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_PYB_HID_cb, &USR_cb);
// TODO
break;
}
}
rx_buf_in = 0;
rx_buf_out = 0;
interrupt_char = VCP_CHAR_NONE;
dev_is_enabled = 1;
// create an exception object for interrupting by VCP
mp_const_vcp_interrupt = mp_obj_new_exception_msg(&mp_type_OSError, "VCPInterrupt");
#endif
}
bool usb_vcp_is_enabled(void) {
return dev_is_enabled;
}
bool usb_vcp_is_connected(void) {
return APP_dev_is_connected;
}
void usb_vcp_set_interrupt_char(int c) {
if (dev_is_enabled) {
interrupt_char = c;
}
}
void usb_vcp_receive(const char *buf, uint32_t len) {
if (dev_is_enabled) {
for (int i = 0; i < len; i++) {
// catch special interrupt character
if (buf[i] == interrupt_char) {
// raise exception when interrupts are finished
mp_obj_exception_clear_traceback(mp_const_vcp_interrupt);
pendsv_nlr_jump(mp_const_vcp_interrupt);
interrupt_char = VCP_CHAR_NONE;
continue;
}
rx_buf[rx_buf_in++] = buf[i];
if (rx_buf_in >= sizeof(rx_buf)) {
rx_buf_in = 0;
}
if (rx_buf_in == rx_buf_out) {
rx_buf_out = rx_buf_in + 1;
if (rx_buf_out >= sizeof(rx_buf)) {
rx_buf_out = 0;
}
}
}
}
}
int usb_vcp_rx_any(void) {
if (rx_buf_in >= rx_buf_out) {
return rx_buf_in - rx_buf_out;
} else {
return rx_buf_in + sizeof(rx_buf) - rx_buf_out;
}
}
char usb_vcp_rx_get(void) {
while (rx_buf_out == rx_buf_in) {
}
char c = rx_buf[rx_buf_out];
rx_buf_out += 1;
if (rx_buf_out >= sizeof(rx_buf)) {
rx_buf_out = 0;
}
return c;
}
void usb_vcp_send_str(const char *str) {
usb_vcp_send_strn(str, strlen(str));
}
void usb_vcp_send_strn(const char *str, int len) {
#ifdef USE_DEVICE_MODE
if (dev_is_enabled) {
#if 0
USBD_CDC_fops.pIf_DataTx((const uint8_t*)str, len);
#endif
}
#endif
}
#include "usbd_conf.h"
/* These are external variables imported from CDC core to be used for IN
transfer management. */
#ifdef USE_DEVICE_MODE
extern uint8_t UserRxBuffer[];/* Received Data over USB are stored in this buffer */
extern uint8_t UserTxBuffer[];/* Received Data over UART (CDC interface) are stored in this buffer */
extern uint32_t BuffLength;
extern uint32_t UserTxBufPtrIn;/* Increment this pointer or roll it back to
start address when data are received over USART */
extern uint32_t UserTxBufPtrOut; /* Increment this pointer or roll it back to
start address when data are sent over USB */
#endif
void usb_vcp_send_strn_cooked(const char *str, int len) {
#ifdef USE_DEVICE_MODE
#if 0
for (const char *top = str + len; str < top; str++) {
if (*str == '\n') {
APP_Rx_Buffer[APP_Rx_ptr_in] = '\r';
APP_Rx_ptr_in = (APP_Rx_ptr_in + 1) & (APP_RX_DATA_SIZE - 1);
}
APP_Rx_Buffer[APP_Rx_ptr_in] = *str;
APP_Rx_ptr_in = (APP_Rx_ptr_in + 1) & (APP_RX_DATA_SIZE - 1);
}
#endif
#endif
}
void usb_hid_send_report(uint8_t *buf) {
#ifdef USE_DEVICE_MODE
#if 0
USBD_HID_SendReport(&USB_OTG_Core, buf, 4);
#endif
#endif
}
/******************************************************************************/
// code for experimental USB OTG support
#ifdef USE_HOST_MODE
#include "led.h"
#include "usbh_core.h"
#include "usbh_usr.h"
#include "usbh_hid_core.h"
#include "usbh_hid_keybd.h"
#include "usbh_hid_mouse.h"
__ALIGN_BEGIN USBH_HOST USB_Host __ALIGN_END ;
static int host_is_enabled = 0;
void pyb_usb_host_init(void) {
if (!host_is_enabled) {
// only init USBH once in the device's power-lifetime
/* Init Host Library */
USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USB_Host, &HID_cb, &USR_Callbacks);
}
host_is_enabled = 1;
}
void pyb_usb_host_process(void) {
USBH_Process(&USB_OTG_Core, &USB_Host);
}
uint8_t usb_keyboard_key = 0;
// TODO this is an ugly hack to get key presses
uint pyb_usb_host_get_keyboard(void) {
uint key = usb_keyboard_key;
usb_keyboard_key = 0;
return key;
}
void USR_MOUSE_Init(void) {
led_state(4, 1);
USB_OTG_BSP_mDelay(100);
led_state(4, 0);
}
void USR_MOUSE_ProcessData(HID_MOUSE_Data_TypeDef *data) {
led_state(4, 1);
USB_OTG_BSP_mDelay(50);
led_state(4, 0);
}
void USR_KEYBRD_Init(void) {
led_state(4, 1);
USB_OTG_BSP_mDelay(100);
led_state(4, 0);
}
void USR_KEYBRD_ProcessData(uint8_t pbuf) {
led_state(4, 1);
USB_OTG_BSP_mDelay(50);
led_state(4, 0);
//lcd_print_strn((char*)&pbuf, 1);