diff options
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/adc.c | 2 | ||||
-rw-r--r-- | libmaple/adc.h | 13 | ||||
-rw-r--r-- | libmaple/dac.c | 4 | ||||
-rw-r--r-- | libmaple/dac.h | 4 | ||||
-rw-r--r-- | libmaple/dma.c | 2 | ||||
-rw-r--r-- | libmaple/exti.h | 8 | ||||
-rw-r--r-- | libmaple/flash.h | 3 | ||||
-rw-r--r-- | libmaple/fsmc.c | 4 | ||||
-rw-r--r-- | libmaple/fsmc.h | 4 | ||||
-rw-r--r-- | libmaple/gpio.c | 5 | ||||
-rw-r--r-- | libmaple/gpio.h | 26 | ||||
-rw-r--r-- | libmaple/libmaple.h | 115 | ||||
-rw-r--r-- | libmaple/libmaple_types.h | 2 | ||||
-rw-r--r-- | libmaple/rcc.h | 3 | ||||
-rw-r--r-- | libmaple/spi.h | 1 | ||||
-rw-r--r-- | libmaple/systick.c | 2 | ||||
-rw-r--r-- | libmaple/timers.c | 90 | ||||
-rw-r--r-- | libmaple/timers.h | 335 | ||||
-rw-r--r-- | libmaple/usart.c | 17 | ||||
-rw-r--r-- | libmaple/usart.h | 1 | ||||
-rw-r--r-- | libmaple/usb/README | 84 | ||||
-rw-r--r-- | libmaple/usb/descriptors.c | 48 | ||||
-rw-r--r-- | libmaple/usb/descriptors.h | 25 | ||||
-rw-r--r-- | libmaple/usb/usb.c | 272 | ||||
-rw-r--r-- | libmaple/usb/usb.h | 93 | ||||
-rw-r--r-- | libmaple/usb/usb_callbacks.c | 425 | ||||
-rw-r--r-- | libmaple/usb/usb_callbacks.h | 11 | ||||
-rw-r--r-- | libmaple/usb/usb_config.h | 1 | ||||
-rw-r--r-- | libmaple/usb/usb_hardware.c | 183 | ||||
-rw-r--r-- | libmaple/util.c | 2 | ||||
-rw-r--r-- | libmaple/util.h | 4 |
31 files changed, 1058 insertions, 731 deletions
diff --git a/libmaple/adc.c b/libmaple/adc.c index 9b21b49..b70c8bd 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -23,8 +23,6 @@ *****************************************************************************/ /** - * @file adc.c - * * @brief Analog to digital converter routines */ diff --git a/libmaple/adc.h b/libmaple/adc.h index 776768e..fe1196f 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -25,7 +25,7 @@ /** * @file adc.h * - * @brief ADC prototypes and defines + * @brief Analog-to-Digital Conversion (ADC) routines. */ #ifndef _ADC_H_ @@ -43,7 +43,8 @@ extern "C"{ * * Need to up the sample time if otherwise... see datasheet */ -/* TODO: We'll only use ADC1 for now... */ +/* TODO: We'll only use ADC1 for now. See page 41 of the manual for + ADC2 and ADC3's real addresses. */ #define ADC1_BASE 0x40012400 #define ADC2_BASE 0x40012400 #define ADC3_BASE 0x40012400 @@ -74,17 +75,17 @@ void adc_init(void); void adc_disable(void); /** - * Perform a single conversion on ADC[0-16], + * Perform a single conversion on ADC[0-15]. * PRECONDITIONS: * adc initialized */ static inline int adc_read(int channel) { - /* Set channel */ + /* Set channel */ ADC_SQR3 = channel; - /* Start the conversion */ + /* Start the conversion */ CR2_SWSTART_BIT = 1; - /* Wait for it to finish */ + /* Wait for it to finish */ while(SR_EOC_BIT == 0) ; diff --git a/libmaple/dac.c b/libmaple/dac.c index 4c00edb..7f6101d 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -27,6 +27,10 @@ #include "gpio.h" #include "dac.h" +/** + * @brief DAC peripheral routines. + */ + /* Only one, so global to this file */ DAC_Map *dac = (DAC_Map*)(DAC_BASE); diff --git a/libmaple/dac.h b/libmaple/dac.h index 17b67b7..9c84f2e 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -26,6 +26,10 @@ * See ../notes/dac.txt for more info */ +/** + * @file dac.h + */ + #ifndef _DAC_H_ #define _DAC_H_ diff --git a/libmaple/dma.c b/libmaple/dma.c index 1de9b60..15c96e1 100644 --- a/libmaple/dma.c +++ b/libmaple/dma.c @@ -64,7 +64,7 @@ static dma_regs *dma_get_regs(uint8 channel) { if (channel >= 1 && channel <= 7) { return (dma_regs *)(DMA1_CCR1 + DMA_CHANNEL_STRIDE * (channel-1)); } else { - ASSERT(false); + ASSERT(0); return NULL; } } diff --git a/libmaple/exti.h b/libmaple/exti.h index 1765045..806578f 100644 --- a/libmaple/exti.h +++ b/libmaple/exti.h @@ -141,10 +141,10 @@ #define EXTI14 14 #define EXTI15 15 -#define EXTI_CONFIG_PORTA 0 -#define EXTI_CONFIG_PORTB 1 -#define EXTI_CONFIG_PORTC 2 -#define EXTI_CONFIG_PORTD 3 +#define EXTI_CONFIG_PORTA 0 // Maple, Maple Native, Maple Mini +#define EXTI_CONFIG_PORTB 1 // Maple, Maple Native, Maple Mini +#define EXTI_CONFIG_PORTC 2 // Maple, Maple Native, Maple Mini +#define EXTI_CONFIG_PORTD 3 // Maple and Maple Native only #define EXTI_CONFIG_PORTE 4 // Native only #define EXTI_CONFIG_PORTF 5 // Native only #define EXTI_CONFIG_PORTG 6 // Native only diff --git a/libmaple/flash.h b/libmaple/flash.h index 54bda0e..7b74c83 100644 --- a/libmaple/flash.h +++ b/libmaple/flash.h @@ -24,7 +24,8 @@ /** - * @brief basic stm32 flash setup routines + * @file flash.h + * @brief basic stm32 flash setup routines */ #ifndef _FLASH_H_ diff --git a/libmaple/fsmc.c b/libmaple/fsmc.c index 301a90d..49526f4 100644 --- a/libmaple/fsmc.c +++ b/libmaple/fsmc.c @@ -22,6 +22,10 @@ * THE SOFTWARE. *****************************************************************************/ +/** + * @brief + */ + #include "libmaple.h" #include "rcc.h" #include "gpio.h" diff --git a/libmaple/fsmc.h b/libmaple/fsmc.h index 471cad1..e83b529 100644 --- a/libmaple/fsmc.h +++ b/libmaple/fsmc.h @@ -26,6 +26,10 @@ * See ../notes/fsmc.txt for more info */ +/** + * @file fsmc.h + */ + #ifndef _FSMC_H_ #define _FSMC_H_ diff --git a/libmaple/gpio.c b/libmaple/gpio.c index f7aee2b..71e5230 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -23,8 +23,6 @@ *****************************************************************************/ /** - * @file gpio.c - * * @brief GPIO initialization routine */ @@ -36,8 +34,9 @@ void gpio_init(void) { rcc_clk_enable(RCC_GPIOA); rcc_clk_enable(RCC_GPIOB); rcc_clk_enable(RCC_GPIOC); +#if NR_GPIO_PORTS >= 4 /* Maple, but not Maple Mini */ rcc_clk_enable(RCC_GPIOD); -#if NR_GPIO_PORTS >= 7 +#elif NR_GPIO_PORTS >= 7 /* Maple Native (high density only) */ rcc_clk_enable(RCC_GPIOE); rcc_clk_enable(RCC_GPIOF); rcc_clk_enable(RCC_GPIOG); diff --git a/libmaple/gpio.h b/libmaple/gpio.h index 49360ee..53f77c4 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -42,15 +42,18 @@ * Alternate function open-drain * * - After reset, the alternate functions are not active and IO prts - * are set to Input Floating mode */ + * are set to Input Floating mode, EXCEPT for the Serial Wire and JTAG + * ports, which are in alternate function mode by default. */ -#define GPIOA_BASE (GPIO_Port*)0x40010800 -#define GPIOB_BASE (GPIO_Port*)0x40010C00 -#define GPIOC_BASE (GPIO_Port*)0x40011000 -#define GPIOD_BASE (GPIO_Port*)0x40011400 -#define GPIOE_BASE (GPIO_Port*)0x40011800 // High-density devices only -#define GPIOF_BASE (GPIO_Port*)0x40011C00 // High-density devices only -#define GPIOG_BASE (GPIO_Port*)0x40012000 // High-density devices only +#define AFIO_MAPR ((volatile uint32*)0x40010004) + +#define GPIOA_BASE ((GPIO_Port*)0x40010800) +#define GPIOB_BASE ((GPIO_Port*)0x40010C00) +#define GPIOC_BASE ((GPIO_Port*)0x40011000) +#define GPIOD_BASE ((GPIO_Port*)0x40011400) +#define GPIOE_BASE ((GPIO_Port*)0x40011800) // High-density devices only +#define GPIOF_BASE ((GPIO_Port*)0x40011C00) // High-density devices only +#define GPIOG_BASE ((GPIO_Port*)0x40012000) // High-density devices only #define GPIO_SPEED_50MHZ (0x3) @@ -109,6 +112,13 @@ static inline uint32 gpio_read_bit(GPIO_Port *port, uint8 gpio_pin) { return (port->IDR & BIT(gpio_pin) ? 1 : 0); } +/* For pins configured as output push-pull, reading the ODR returns + * the last value written in push-pull mode. + */ +static inline void gpio_toggle_pin(GPIO_Port *port, uint8 gpio_pin) { + port->ODR = port->ODR ^ BIT(gpio_pin); +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 664568f..dbc77a4 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -33,36 +33,43 @@ #include "libmaple_types.h" -// General configuration -#define MAPLE_DEBUG 1 +/* General configuration */ +#define DEBUG_NONE 0 +#define DEBUG_FAULT 1 +#define DEBUG_ALL 2 -// MCU-specific configuration -#ifdef MCU_STM32F103RB - // eg, LeafLabs Maple +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL DEBUG_ALL +#endif - // Number of 16-bit backup registers - #define NR_BKP_REGS 10 +/* MCU-specific configuration */ +#if defined(MCU_STM32F103RB) + /* e.g., LeafLabs Maple */ - // Number of GPIO ports (GPIOA, GPIOB, etc), definately used + /* Number of GPIO ports (GPIOA, GPIOB, etc.) */ #define NR_GPIO_PORTS 4 - // Total number of GPIO pins + /* Total number of GPIO pins */ #define NR_GPIO_PINS 39 - // Number of timer devices ports, definately used + /* Number of 16-bit backup registers */ + #define NR_BKP_REGS 10 + + /* Number of timer devices ports, definitely used */ #define NR_TIMERS 4 - // Number of USART ports + /* Number of USART ports */ #define NR_USART 3 - // Has an FSMC bus? + /* Has an FSMC bus? */ #define NR_FSMC 0 - // Has an FSMC bus? + /* Has an FSMC bus? */ #define NR_DAC_PINS 0 - // USB Identifier numbers - // Descriptor strings must be modified by hand in usb/descriptors.c for now + /* USB Identifier numbers */ + /* Descriptor strings must be modified by hand in + usb/descriptors.c for now */ #define VCOM_ID_VENDOR 0x1EAF #define VCOM_ID_PRODUCT 0x0004 #define USB_DISC_BANK GPIOC_BASE @@ -70,39 +77,38 @@ #define USB_CONFIG_MAX_POWER (100 >> 1) #define RESET_DELAY (100) - // Where to put usercode (based on space reserved for bootloader) + /* Where to put usercode (based on space reserved for bootloader) */ #define USER_ADDR_ROM 0x08005000 #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 - // Debug port settings (from ASSERT) - #define ERROR_LED_PORT GPIOA_BASE - #define ERROR_LED_PIN 5 + /* Debug port settings (from ASSERT) */ + #define ERROR_LED_PORT GPIOB_BASE + #define ERROR_LED_PIN 12 #define ERROR_USART_NUM USART2 #define ERROR_USART_BAUD 9600 - #define ERROR_TX_PIN 2 #define ERROR_TX_PORT GPIOA_BASE + #define ERROR_TX_PIN 2 - // Just in case, most boards have at least some memory + /* Just in case, most boards have at least some memory */ #ifndef RAMSIZE # define RAMSIZE (caddr_t)0x50000 #endif - // Bitbanded Memory sections + /* Bitbanded Memory sections */ #define BITBAND_SRAM_REF 0x20000000 #define BITBAND_SRAM_BASE 0x22000000 #define BITBAND_PERI_REF 0x40000000 #define BITBAND_PERI_BASE 0x42000000 -#endif -#ifdef MCU_STM32F103ZE - // eg, LeafLabs Maple Native - #define NR_BKP_REGS 42 +#elif defined(MCU_STM32F103ZE) + /* e.g., LeafLabs Maple Native */ + #define NR_GPIO_PORTS 7 - #define NR_GPIO_PINS 63 + #define NR_GPIO_PINS 100 + #define NR_BKP_REGS 42 /* TODO test on Native */ #define NR_TIMERS 8 - // 3 USART, plus UART4 and UART5 - #define NR_USART 5 + #define NR_USART 5 /* NB: 4 and 5 are UART only */ #define NR_FSMC 1 #define NR_DAC_PINS 2 @@ -121,8 +127,8 @@ #define ERROR_LED_PIN 15 #define ERROR_USART_NUM USART1 #define ERROR_USART_BAUD 9600 - #define ERROR_TX_PIN 10 #define ERROR_TX_PORT GPIOA_BASE + #define ERROR_TX_PIN 10 #ifndef RAMSIZE # define RAMSIZE (caddr_t)0x50000 @@ -132,15 +138,54 @@ #define BITBAND_SRAM_BASE 0x22000000 #define BITBAND_PERI_REF 0x40000000 #define BITBAND_PERI_BASE 0x42000000 -#endif -// Make sure MCU-specific settings were defined -#ifndef NR_GPIO_PORTS -#error "No MCU type specified. Add something like -DMCU_STM32F103RB " \ +#elif defined(MCU_STM32F103CB) + /* e.g., LeafLabs Maple Mini */ + + #define NR_GPIO_PORTS 3 + #define NR_GPIO_PINS 34 + #define NR_BKP_REGS 10 /* TODO test on Mini */ + #define NR_TIMERS 4 + #define NR_USART 3 + #define NR_FSMC 0 + #define NR_DAC_PINS 0 + + #define VCOM_ID_VENDOR 0x1EAF + #define VCOM_ID_PRODUCT 0x0005 + #define USB_DISC_BANK GPIOB_BASE + #define USB_DISC_PIN 9 + #define USB_CONFIG_MAX_POWER (100 >> 1) + #define RESET_DELAY 100 + + #define USER_ADDR_ROM 0x08005000 + #define USER_ADDR_RAM 0x20000C00 + #define STACK_TOP 0x20000800 + + #define ERROR_LED_PORT GPIOB_BASE + #define ERROR_LED_PIN 12 + #define ERROR_USART_NUM USART2 + #define ERROR_USART_BAUD 9600 + #define ERROR_TX_PORT GPIOA_BASE + #define ERROR_TX_PIN 2 + + #ifndef RAMSIZE + # define RAMSIZE (caddr_t)0x50000 + #endif + + /* Bitbanded Memory sections */ + #define BITBAND_SRAM_REF 0x20000000 + #define BITBAND_SRAM_BASE 0x22000000 + #define BITBAND_PERI_REF 0x40000000 + #define BITBAND_PERI_BASE 0x42000000 + +#else + +#error "No MCU type specified. Add something like -DMCU_STM32F103RB " \ "to your compiler arguments (probably in a Makefile)." + #endif -// Requires board configuration info +/* Requires board configuration info */ #include "util.h" #endif diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h index a976a9e..8d216a8 100644 --- a/libmaple/libmaple_types.h +++ b/libmaple/libmaple_types.h @@ -45,6 +45,8 @@ typedef void (*voidFuncPtr)(void); #define __io volatile +#define ALWAYS_INLINE inline __attribute__((always_inline)) + #ifndef NULL #define NULL 0 #endif diff --git a/libmaple/rcc.h b/libmaple/rcc.h index a7c4c53..4b1f35d 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -23,7 +23,8 @@ *****************************************************************************/ /** - * @brief reset and clock control definitions and prototypes + * @file rcc.h + * @brief reset and clock control definitions and prototypes */ #ifndef _RCC_H_ diff --git a/libmaple/spi.h b/libmaple/spi.h index d1973c5..db8aa9c 100644 --- a/libmaple/spi.h +++ b/libmaple/spi.h @@ -23,6 +23,7 @@ *****************************************************************************/ /** + * @file spi.h * @brief libmaple serial peripheral interface (SPI) prototypes and * declarations */ diff --git a/libmaple/systick.c b/libmaple/systick.c index 961d42b..b056001 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -23,8 +23,6 @@ *****************************************************************************/ /** - * @file systick.c - * * @brief System timer interrupt handler and initialization routines */ diff --git a/libmaple/timers.c b/libmaple/timers.c index 04bfa9f..29aeeba 100644 --- a/libmaple/timers.c +++ b/libmaple/timers.c @@ -23,8 +23,6 @@ *****************************************************************************/ /** - * @file timers.c - * * @brief General timer routines */ @@ -75,16 +73,20 @@ struct timer_dev timer_dev_table[] = { /* This function should probably be rewriten to take (timer_num, mode) * and have prescaler set elsewhere. The mode can be passed through to * set_mode at the end */ -void timer_init(uint8 timer_num, uint16 prescale) { +void timer_init(timer_dev_num timer_num, uint16 prescale) { /* TODO: doesn't catch 6+7 */ - ASSERT((timer_num != TIMER6) && (timer_num != TIMER7)); timer_port *timer = timer_dev_table[timer_num].base; uint8 is_advanced = 0; - if((timer_num == TIMER1) || (timer_num == TIMER8)) { + if (timer_num == TIMER1) { is_advanced = 1; } +#if NR_TIMERS >= 8 + if (timer_num == TIMER8) { + is_advanced = 1; + } +#endif rcc_clk_enable(timer_dev_table[timer_num].rcc_dev_num); @@ -105,19 +107,15 @@ void timer_init(uint8 timer_num, uint16 prescale) { * we'll worry about that later. */ timer->CCR1 = 0x8FFF; // PWM start value timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register. - timer->CCER |= 0x001; // enable ch timer->CCR2 = 0x8FFF; // PWM start value timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register. - timer->CCER |= 0x010; // enable ch timer->CCR3 = 0x8FFF; // PWM start value timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register. - timer->CCER |= 0x100; // enable ch timer->CCR4 = 0x8FFF; // PWM start value timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register. - timer->CCER |= 0x1000; // enable ch /* Advanced timer? */ if (is_advanced) { @@ -131,48 +129,61 @@ void timer_init(uint8 timer_num, uint16 prescale) { } /* Stops the counter; the mode and settings are not modified */ -void timer_pause(uint8 timer_num) { +void timer_pause(timer_dev_num timer_num) { timer_port *timer = timer_dev_table[timer_num].base; timer->CR1 &= ~(0x0001); // CEN } /* Starts the counter; the mode and settings are not modified */ -void timer_resume(uint8 timer_num) { +void timer_resume(timer_dev_num timer_num) { timer_port *timer = timer_dev_table[timer_num].base; timer->CR1 |= 0x0001; // CEN } +/* Returns the current timer counter value. Probably very inaccurate + * if the counter is running with a low prescaler. */ +uint16 timer_get_count(timer_dev_num timer_num) { + timer_port *timer = timer_dev_table[timer_num].base; + + return timer->CNT; +} + /* This function sets the counter value via register for the specified * timer. Can't think of specific usecases except for resetting to * zero but it's easy to implement and allows for "creative" * programming */ -void timer_set_count(uint8 timer_num, uint16 value) { +void timer_set_count(timer_dev_num timer_num, uint16 value) { timer_port *timer = timer_dev_table[timer_num].base; timer->CNT = value; } -/* Returns the current timer counter value. Probably very inaccurate - * if the counter is running with a low prescaler. */ -uint16 timer_get_count(uint8 timer_num) { +/* Get the prescaler buffer value (remember, the actual prescaler + * doesn't get set until an update event). */ +uint16 timer_get_prescaler(timer_dev_num timer_num) { timer_port *timer = timer_dev_table[timer_num].base; - - return timer->CNT; + return timer->PSC; } /* Sets the prescaler */ -void timer_set_prescaler(uint8 timer_num, uint16 prescale) { +void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale) { timer_port *timer = timer_dev_table[timer_num].base; timer->PSC = prescale; } +/* Get the reload value for the entire timer. */ +uint16 timer_get_reload(timer_dev_num timer_num) { + timer_port *timer = timer_dev_table[timer_num].base; + return timer->ARR; +} + /* This sets the "reload" or "overflow" value for the entire timer. We * should probably settle on either "reload" or "overflow" to prevent * confusion? */ -void timer_set_reload(uint8 timer_num, uint16 max_reload) { +void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) { timer_port *timer = timer_dev_table[timer_num].base; timer->ARR = max_reload; @@ -217,7 +228,7 @@ void timer_disable_all(void) { } /* Sets the mode of individual timer channels, including a DISABLE mode */ -void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) { +void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode) { timer_port *timer = timer_dev_table[timer_num].base; ASSERT(channel >= 1); @@ -292,18 +303,36 @@ void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) { } } +uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel_num) { + /* faster: just read TIMERx_CHy_CCR (see timers.h) */ + ASSERT(channel_num > 0 && channel_num <= 4); + timer_port *timer = timer_dev_table[timer_num].base; + switch(channel_num) { + case 1: + return timer->CCR1; + case 2: + return timer->CCR2; + case 3: + return timer->CCR3; + case 4: + return timer->CCR4; + default: /* in case ASSERT is disabled */ + return 0; + } +} + /* This sets the compare value (aka the trigger) for a given timer * channel */ -void timer_set_compare_value(uint8 timer_num, - uint8 compare_num, +void timer_set_compare_value(timer_dev_num timer_num, + uint8 channel_num, uint16 value) { + ASSERT(channel_num > 0 && channel_num <= 4); + /* The faster version of this function is the inline timer_pwm_write_ccr */ timer_port *timer = timer_dev_table[timer_num].base; - ASSERT(compare_num > 0 && compare_num <= 4); - - switch(compare_num) { + switch(channel_num) { case 1: timer->CCR1 = value; break; @@ -321,7 +350,7 @@ void timer_set_compare_value(uint8 timer_num, /* Stores a pointer to the passed usercode interrupt function and configures * the actual ISR so that it will actually be called */ -void timer_attach_interrupt(uint8 timer_num, +void timer_attach_interrupt(timer_dev_num timer_num, uint8 compare_num, voidFuncPtr handler) { ASSERT(compare_num > 0 && compare_num <= 4); @@ -333,7 +362,7 @@ void timer_attach_interrupt(uint8 timer_num, nvic_irq_enable(timer_dev_table[timer_num].nvic_dev_num); } -void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) { +void timer_detach_interrupt(timer_dev_num timer_num, uint8 compare_num) { ASSERT(compare_num > 0 && compare_num <= 4); timer_port *timer = timer_dev_table[timer_num].base; @@ -342,6 +371,13 @@ void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) { timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums } +void timer_generate_update(timer_dev_num timer_num) { + /* cause update event by setting UG bit in EGR. updates prescaler + ratio etc. */ + timer_port *timer = timer_dev_table[timer_num].base; + timer->EGR |= 0x1; +} + /* The following are the actual interrupt handlers; 1 for each timer which must * determine which actual compare value (aka channel) was triggered. * diff --git a/libmaple/timers.h b/libmaple/timers.h index cbdf088..99bcab6 100644 --- a/libmaple/timers.h +++ b/libmaple/timers.h @@ -82,7 +82,7 @@ extern "C"{ #endif -typedef volatile uint32* TimerCCR; +typedef volatile uint16* TimerCCR; #define TIMER1_BASE 0x40012C00 #define TIMER2_BASE 0x40000000 @@ -96,47 +96,63 @@ typedef volatile uint32* TimerCCR; #define ARPE BIT(7) // Auto-reload preload enable #define NOT_A_TIMER 0 -#define TIMER_CCR(NUM,CHAN) TIMER ## NUM ## _CH ## CHAN ## _CRR +#define TIMER_CCR(NUM,CHAN) (TIMER ## NUM ## _CH ## CHAN ## _CRR) -#define TIMER1_CH1_CCR (TimerCCR)(TIMER1_BASE + 0x34) -#define TIMER1_CH2_CCR (TimerCCR)(TIMER1_BASE + 0x38) -#define TIMER1_CH3_CCR (TimerCCR)(TIMER1_BASE + 0x3C) -#define TIMER1_CH4_CCR (TimerCCR)(TIMER1_BASE + 0x40) +/* Timers 1-4 are present on the entire STM32 line. */ -#define TIMER2_CH1_CCR (TimerCCR)(TIMER2_BASE + 0x34) -#define TIMER2_CH2_CCR (TimerCCR)(TIMER2_BASE + 0x38) -#define TIMER2_CH3_CCR (TimerCCR)(TIMER2_BASE + 0x3C) -#define TIMER2_CH4_CCR (TimerCCR)(TIMER2_BASE + 0x40) +#define TIMER1_CH1_CCR ((TimerCCR)(TIMER1_BASE + 0x34)) +#define TIMER1_CH2_CCR ((TimerCCR)(TIMER1_BASE + 0x38)) +#define TIMER1_CH3_CCR ((TimerCCR)(TIMER1_BASE + 0x3C)) +#define TIMER1_CH4_CCR ((TimerCCR)(TIMER1_BASE + 0x40)) -#define TIMER3_CH1_CCR (TimerCCR)(TIMER3_BASE + 0x34) -#define TIMER3_CH2_CCR (TimerCCR)(TIMER3_BASE + 0x38) -#define TIMER3_CH3_CCR (TimerCCR)(TIMER3_BASE + 0x3C) -#define TIMER3_CH4_CCR (TimerCCR)(TIMER3_BASE + 0x40) +#define TIMER2_CH1_CCR ((TimerCCR)(TIMER2_BASE + 0x34)) +#define TIMER2_CH2_CCR ((TimerCCR)(TIMER2_BASE + 0x38)) +#define TIMER2_CH3_CCR ((TimerCCR)(TIMER2_BASE + 0x3C)) +#define TIMER2_CH4_CCR ((TimerCCR)(TIMER2_BASE + 0x40)) -#define TIMER4_CH1_CCR (TimerCCR)(TIMER4_BASE + 0x34) -#define TIMER4_CH2_CCR (TimerCCR)(TIMER4_BASE + 0x38) -#define TIMER4_CH3_CCR (TimerCCR)(TIMER4_BASE + 0x3C) -#define TIMER4_CH4_CCR (TimerCCR)(TIMER4_BASE + 0x40) +#define TIMER3_CH1_CCR ((TimerCCR)(TIMER3_BASE + 0x34)) +#define TIMER3_CH2_CCR ((TimerCCR)(TIMER3_BASE + 0x38)) +#define TIMER3_CH3_CCR ((TimerCCR)(TIMER3_BASE + 0x3C)) +#define TIMER3_CH4_CCR ((TimerCCR)(TIMER3_BASE + 0x40)) -/* Timer5 and Timer8 are in high-density devices only (such as Maple - Native). Timer6 and Timer7 in these devices have no output compare +#define TIMER4_CH1_CCR ((TimerCCR)(TIMER4_BASE + 0x34)) +#define TIMER4_CH2_CCR ((TimerCCR)(TIMER4_BASE + 0x38)) +#define TIMER4_CH3_CCR ((TimerCCR)(TIMER4_BASE + 0x3C)) +#define TIMER4_CH4_CCR ((TimerCCR)(TIMER4_BASE + 0x40)) + +/* Timers 5 and 8 are in high-density devices only (such as Maple + Native). Timers 6 and 7 in these devices have no output compare pins. */ -#define TIMER5_CH1_CCR (TimerCCR)(TIMER5_BASE + 0x34) -#define TIMER5_CH2_CCR (TimerCCR)(TIMER5_BASE + 0x38) -#define TIMER5_CH3_CCR (TimerCCR)(TIMER5_BASE + 0x3C) -#define TIMER5_CH4_CCR (TimerCCR)(TIMER5_BASE + 0x40) +#define TIMER5_CH1_CCR ((TimerCCR)(TIMER5_BASE + 0x34)) +#define TIMER5_CH2_CCR ((TimerCCR)(TIMER5_BASE + 0x38)) +#define TIMER5_CH3_CCR ((TimerCCR)(TIMER5_BASE + 0x3C)) +#define TIMER5_CH4_CCR ((TimerCCR)(TIMER5_BASE + 0x40)) -#define TIMER8_CH1_CCR (TimerCCR)(TIMER8_BASE + 0x34) -#define TIMER8_CH2_CCR (TimerCCR)(TIMER8_BASE + 0x38) -#define TIMER8_CH3_CCR (TimerCCR)(TIMER8_BASE + 0x3C) -#define TIMER8_CH4_CCR (TimerCCR)(TIMER8_BASE + 0x40) +#define TIMER8_CH1_CCR ((TimerCCR)(TIMER8_BASE + 0x34)) +#define TIMER8_CH2_CCR ((TimerCCR)(TIMER8_BASE + 0x38)) +#define TIMER8_CH3_CCR ((TimerCCR)(TIMER8_BASE + 0x3C)) +#define TIMER8_CH4_CCR ((TimerCCR)(TIMER8_BASE + 0x40)) -#define TIMER_DISABLED 0 -#define TIMER_PWM 1 -#define TIMER_OUTPUTCOMPARE 2 +/** + * Used to configure the behavior of a timer. + */ +typedef enum TimerMode { + TIMER_DISABLED, /**< In this mode, the timer stops counting, + interrupts are not called, and no state changes + are output. */ + TIMER_PWM, /**< This is the default mode for pins after + initialization. */ + TIMER_OUTPUTCOMPARE, /**< In this mode, the timer counts from 0 to + its reload value repeatedly; every time + the counter value reaches one of the + channel compare values, the corresponding + interrupt is fired. */ +} TimerMode; typedef struct { + /* Fields up to ARR common to general purpose (2,3,4,5), advanced + control (1,8) and basic (6, 7) timers: */ volatile uint16 CR1; uint16 RESERVED0; volatile uint16 CR2; @@ -161,8 +177,9 @@ typedef struct { uint16 RESERVED10; volatile uint16 ARR; uint16 RESERVED11; - volatile uint16 RCR; - uint16 RESERVED12; + /* Basic timers have none of the following: */ + volatile uint16 RCR; /* Advanced control timers only */ + uint16 RESERVED12; /* Advanced control timers only */ volatile uint16 CCR1; uint16 RESERVED13; volatile uint16 CCR2; @@ -171,25 +188,34 @@ typedef struct { uint16 RESERVED15; volatile uint16 CCR4; uint16 RESERVED16; - volatile uint16 BDTR; // Not used in general purpose timers - uint16 RESERVED17; // Not used in general purpose timers + volatile uint16 BDTR; /* Advanced control timers only */ + uint16 RESERVED17; /* Advanced control timers only */ volatile uint16 DCR; uint16 RESERVED18; volatile uint16 DMAR; uint16 RESERVED19; } timer_port; -/* timer device numbers */ -enum { - TIMER1, - TIMER2, - TIMER3, - TIMER4, - TIMER5, // High density only - TIMER6, // High density only; no compare - TIMER7, // High density only; no compare - TIMER8, // High density only -}; +/** + * Timer device numbers. See STM32 reference manual, chapters 13-15. + */ +/* several locations depend on TIMER1=0, etc.; don't change the + enumerator values to start at 1. */ +typedef enum { + TIMER1, /*< Advanced control timer TIM1 */ + TIMER2, /*< General purpose timer TIM2 */ + TIMER3, /*< General purpose timer TIM3 */ + TIMER4, /*< General purpose timer TIM4 */ +#if NR_TIMERS >= 8 + TIMER5, /*< General purpose timer TIM5; high density only */ + /* FIXME maple native: put timers 6 and 7 back in and make the + corresponding changes to timers.c */ + /* TIMER6, /\*< Basic timer TIM6; high density only *\/ */ + /* TIMER7, /\*< Basic timer TIM7; high density only *\/ */ + TIMER8, /*< Advanced control timer TIM8; high density only */ +#endif + TIMER_INVALID /* FIXME: this is starting to seem like a bad idea */ +} timer_dev_num; /* timer descriptor */ struct timer_dev { @@ -201,40 +227,203 @@ struct timer_dev { extern struct timer_dev timer_dev_table[]; -/* Turn on timer with prescale as the divisor - * void timer_init(uint32 timer, uint16 prescale) - * timer -> {1-4} - * prescale -> {1-65535} +/** + * Initializes timer with prescale as the clock divisor. + * + * @param timer_num Timer number. + * + * @param prescale value in the range 1--65535 to use as a prescaler + * for timer counter increment frequency. + * + * @see timer_dev_num + * @see timer_set_prescaler() + * @see timer_set_mode() + */ +void timer_init(timer_dev_num timer_num, uint16 prescale); + +/** + * Quickly disable all timers. Calling this function is faster than, + * e.g., calling timer_set_mode() for all available timers/channels. */ -void timer_init(uint8, uint16); void timer_disable_all(void); -uint16 timer_get_count(uint8); -void timer_set_count(uint8,uint16); -void timer_pause(uint8); -void timer_resume(uint8); -void timer_set_prescaler(uint8 timer_num, uint16 prescale); -void timer_set_reload(uint8 timer_num, uint16 max_reload); -void timer_set_mode(uint8 timer_num, uint8 compare_num, uint8 mode); -void timer_set_compare_value(uint8 timer_num, uint8 compare_num, uint16 value); -void timer_attach_interrupt(uint8 timer_num, uint8 compare_num, + +/** + * Returns the timer's counter value. Due to function call overhead, + * this value is likely to be inaccurate if the counter is running + * with a low prescaler. + * + * @param timer_num the timer whose counter to return. + * + * @pre Timer has been initialized. + */ +uint16 timer_get_count(timer_dev_num timer_num); + +/** + * Sets the counter value for the given timer. + * + * @param timer_num the timer whose counter to set. + * + * @param value the new counter value. + * + * @pre Timer has been initialized. + */ +void timer_set_count(timer_dev_num timer_num, uint16 value); + +/** + * Stops the timer's counter from incrementing. Does not modify the + * timer's mode or settings. + * + * @param timer_num the timer to pause. + * + * @see timer_resume() + * + * @pre Timer has been initialized. + */ +void timer_pause(timer_dev_num timer_num); + +/** + * Starts the counter for the given timer. Does not modify the + * timer's mode or settings. The timer will begin counting on the + * first rising clock cycle after it has been re-enabled using this + * function. + * + * @param timer_num the timer to resume. + * + * @see timer_pause() + * + * @pre Timer has been initialized. + */ +void timer_resume(timer_dev_num timer_num); + +/** + * Returns the prescaler for the given timer. + * + * @param timer_num the timer whose prescaler to return. + * + * @see timer_set_prescaler() + * + * @pre Timer has been initialized. + */ +uint16 timer_get_prescaler(timer_dev_num timer_num); + +/** + * Sets the prescaler for the given timer. This value goes into the + * PSC register, so it's 0-based (i.e., a prescale of 0 counts 1 tick + * per clock cycle). This prescale does not take effect until the + * next update event. + * + * @param timer_num the timer whose prescaler to set. + * + * @param prescale the new prescaler. + * + * @pre Timer has been initialized. + */ +void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale); + +/** + * Gets the reload value for the timer. + * + * @see timer_set_reload() + * + * @pre Timer has been initialized. + */ +uint16 timer_get_reload(timer_dev_num timer_num); + +/** + * Sets the reload value for the timer. + * + * After this function returns, the timer's counter will reset to 0 + * after it has reached the value max_reload. + * + * @pre Timer has been initialized. + */ +void timer_set_reload(timer_dev_num timer_num, uint16 max_reload); + +/* TODO: timer_get_mode */ + +/** + * Set the mode of an individual timer channel. + * + * @see timer_disable_all() + * @see TimerMode + * @see timer_dev_num + * @pre Timer has been initialized. + */ +void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode); + +/** + * Get the compare value for the given timer channel. + * @see timer_set_compare_value() + * @see timer_dev_num + * @pre Timer has been initialized. + */ +uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel); + +/** + * Sets the compare value for a given timer channel. Useful for + * scheduling when interrupt handlers will be called. + * + * @see timer_attach_interrupt() + * @see timer_detach_interrupt() + * @see timer_set_reload() + * @see timer_dev_num + * @pre Timer has been initialized. + */ +void timer_set_compare_value(timer_dev_num timer_num, uint8 channel, + uint16 value); + +/** + * Detach the interrupt handler for the given timer channel, if any. + * After this function returns, any handler attached to the given + * channel will no longer be called. + * + * @see timer_attach_interrupt() + * @pre Timer has been initialized. + * @see timer_dev_num + */ +void timer_detach_interrupt(timer_dev_num timer_num, uint8 channel); + +/** + * Attach an interrupt handler for the given timer and channel. The + * given ISR, handler, will be called whenever the timer's counter + * reaches the compare value for the given timer and channel. + * + * @see timer_set_compare_value() + * @see timer_detach_interrupt() + * @see timer_set_mode() + * @see timer_dev_num + * @see voidFuncPtr + * @pre Timer has been initialized. + * @pre The channel's mode must be set to TIMER_OUTPUTCOMPARE, or the + * interrupt handler will not get called. + */ +void timer_attach_interrupt(timer_dev_num timer_num, uint8 channel, voidFuncPtr handler); -void timer_detach_interrupt(uint8 timer_num, uint8 compare_num); -/* Turn on PWM with duty_cycle on the specified channel in timer. - * This function takes in a pointer to the corresponding CCR - * register for the pin cause it saves pwmWrite() a couple of - * cycles. +/** + * Programmatically generate an update event on the given timer. This + * updates the prescaler, reloads the compare value (in upcounting + * mode, etc.). + * + * @pre Timer has been initialized. + */ +void timer_generate_update(timer_dev_num timer_num); + +/** + * Turn on PWM with duty_cycle. + * + * @param ccr TIMERx_CHn_CCR, where x goes from 1 to NR_TIMERS, + * and n goes from 1 to 4. + * + * @param duty_cycle: A number between 0 and + * timer_get_compare_value(TIMERx, y), where x and y are as above. * - * void timer_pwm(uint8 channel, uint8 duty_cycle); - * channel -> {TIMERx_CHn_CCR} - * duty_cycle -> {0-65535} + * @pre Pin has been set to alternate function output. * - * PRECONDITIONS: - * pin has been set to alternate function output - * timer has been initialized + * @pre Timer has been initialized. */ -static inline void timer_pwm_write_ccr(TimerCCR CCR, uint16 duty_cycle) { - *CCR = duty_cycle; +static inline void timer_pwm_write_ccr(TimerCCR ccr, uint16 duty_cycle) { + *ccr = duty_cycle; } #ifdef __cplusplus diff --git a/libmaple/usart.c b/libmaple/usart.c index 27aab49..44a5c92 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -23,8 +23,6 @@ *****************************************************************************/ /** - * @file usart.c - * * @brief USART control routines */ @@ -78,22 +76,25 @@ struct usart_dev usart_dev_table[] = { #endif }; -/* usart interrupt handlers. +/* + * Usart interrupt handlers. + */ - Use of rb_safe_insert() implies that a full buffer ignores new - bytes. */ -__attribute__((always_inline)) static inline void usart_irq(int usart_num) { - /* TODO: use attributes to let GCC know it's always called with - constants, just to force the inliner to do its thing */ +static inline void usart_irq(int usart_num) { #ifdef USART_SAFE_INSERT + /* Ignore old bytes if the user defines USART_SAFE_INSERT. */ rb_safe_insert(&(usart_dev_table[usart_num].rb), (uint8)((usart_dev_table[usart_num].base)->DR)); #else + /* By default, push bytes around in the ring buffer. */ rb_push_insert(&(usart_dev_table[usart_num].rb), (uint8)((usart_dev_table[usart_num].base)->DR)); #endif } +/* TODO: Check the disassembly for the following functions to make + sure GCC inlined properly. */ + void USART1_IRQHandler(void) { usart_irq(USART1); } diff --git a/libmaple/usart.h b/libmaple/usart.h index cbc7bde..0ca3f55 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -23,6 +23,7 @@ *****************************************************************************/ /** + * @file usart.h * @brief USART definitions and prototypes */ diff --git a/libmaple/usb/README b/libmaple/usb/README index f3970b6..540b1ea 100644 --- a/libmaple/usb/README +++ b/libmaple/usb/README @@ -5,16 +5,19 @@ The USB submodule of libmaple is responsible for: the USB isr, resetting the USB disc pin (used to tell the host were alive). Additionally, the USB submodule defines the virtual com port USB applications that is available to all user sketches - via Usb.print() and others. + via SerialUSB.print() and others. To use it: - Call Usb.init() to enable the IRQ channel, configure the clocks, - pull down usb_disc, and setup the vcom buffers - Usb.print/ln, available(), read(), write() implement the same + + [This section is out of date. Does SerialUSB.begin() do the same + thing as the old Usb.init()?] + + SerialUSB.print/ln, available(), read(), write() implement the same interface as Serial1/2/3 - - + + Current Status: + Currently, the USB submodule relies on the low level core library provided by ST to access the USB peripheral registers and implement the USB transfer protocol for control endpoint @@ -22,23 +25,27 @@ Current Status: unfortunately hard to untangle from this low level dependence, and when a new USB core library is written (to nix ST dependence) changes will likely have to be made to virtual com application - code. Ideally, the new core library should mimick the form of - MyUSB (LUFA), since this library (USB for AVR) is growing in - popularity and in example applications. Additionally, the USB lib - here relies on low level hardware functions that were just ripped - out of the bootloader code (for simplicity) but clearly this - should be replaced with direct accesses to functions provided - elsewhere in libmaple. - - The virtual com port serves two important purposes. 1) is allows - serial data transfers between user sketches an a host computer. 2) - is allows the host machine to issue a system reset by asserting - the DTR signal. After reset, Maple will run the DFU bootloader for - a few seconds, during which the user can begin a DFU download - operation ('downloads' application binary into RAM/FLASH). This - without this virtual com port, it would be necessary to find an - alternative means to reset the chip in order to enable the - bootloader. + code. Ideally, the new core library should mimic the form of MyUSB + (LUFA), since this library (USB for AVR) is growing in popularity + and in example applications. Additionally, the USB lib here relies + on low level hardware functions that were just ripped out of the + bootloader code (for simplicity) but clearly this should be + replaced with direct accesses to functions provided elsewhere in + libmaple. + + The virtual com port serves two important purposes. + + 1) It allows serial data transfers between user sketches an a + host computer. + + 2) It allows the host machine to issue a system reset by + asserting the DTR signal. + + After reset, Maple will run the DFU bootloader for a few seconds, + during which the user can begin a DFU upload operation (uploads + application binary into RAM/FLASH). Thus, without this virtual com + port, it would be necessary to find an alternative means to reset + the chip in order to enable the bootloader. If you would like to develop your own USB application for whatever reason (uses faster isochronous enpoints for streaming audio, or @@ -51,19 +58,19 @@ Current Status: It would be possible to build a compound USB device, that implements endpoints for both the virtual COM port as well as some - other components (mass sotrage etc.) however this turns out to be - a burden from the host driver side, as windows and *nix handle + other components (mass storage etc.). However, this turns out to + be a burden from the host driver side, as Windows and *nix handle compound USB devices quite differently. - Be mindful that running the USB application isnt "free." The + Be mindful that enabling the USB peripheral isnt "free." The device must respond to periodic bus activity (every few - milliseconds) by servicing an ISR. Therefore the USB application + milliseconds) by servicing an ISR. Therefore, the USB application should be disabled inside of timing critical applications. In order to disconnect the device from the host, the USB_DISC pin can - be asserted (on Maple v1,2,3 this is GPIOC,12). Alternatively, the - NVIC can be directly configured to disable the USB LP/HP IRQ's + be asserted (on Maple this is GPIO C12). Alternatively, the NVIC + can be directly configured to disable the USB LP/HP IRQ's. - This library should exposed through usb.h, do not include any + This library should exposed through usb.h; do not include any other files direcly in your application. The files inside of usb_lib were provided by ST and are subject to @@ -72,21 +79,22 @@ Current Status: Integration with libmaple: - The current USB lib is ported directly from the maple bootloader - code, adapted to be a virtual com rather than a DFU device. That - means several functions are redefined locally that could have been - pulled from elsewhere in libmaple. Thus, ths USB module depends - absolutely zero on libmaple, it even ensures that clocks are - configured correctly for its operation. + The current USB lib is ported from the Maple bootloader code, + adapted to be a virtual com rather than a DFU device. That means + several functions are redefined locally that could have been + pulled from elsewhere in libmaple. Thus, ths USB module doesn't + have too many dependencies on libmaple. It even ensures that + clocks are configured correctly for its operation. However, over + time, some libmaple dependencies have crept in. Todo: - write custom low level USB stack to strip out any remaining dependence on ST code - remove dependence on hardware.c, since any functions here really - should have their own analogues elsewhere inside libmaple + should have their own analogs elsewhere inside libmaple - add a high level USB application library that would allow users to make their own HID/Mass Storage/Audio/Video devices. - - implement a Usb.link(SerialX) that forces a passthrough + - implement a SerialUSB.link(SerialX) that forces a passthrough the host computer virtual com to SerialX, and utilizes the line_config commands correctly (sets baud etc) diff --git a/libmaple/usb/descriptors.c b/libmaple/usb/descriptors.c index 5038709..360e6dd 100644 --- a/libmaple/usb/descriptors.c +++ b/libmaple/usb/descriptors.c @@ -1,12 +1,35 @@ -/* insert license */ - +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ #include "descriptors.h" #include "libmaple.h" #include "usb_config.h" const USB_Descriptor_Device usbVcomDescriptor_Device = { - bLength: sizeof(USB_Descriptor_Device), + bLength: sizeof(USB_Descriptor_Device), bDescriptorType: USB_DESCRIPTOR_TYPE_DEVICE, bcdUSB: 0x0200, bDeviceClass: USB_DEVICE_CLASS_CDC, @@ -29,7 +52,8 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = { bNumInterfaces: 0x02, bConfigurationValue: 0x01, iConfiguration: 0x00, - bmAttributes: (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED), + bmAttributes: (USB_CONFIG_ATTR_BUSPOWERED | + USB_CONFIG_ATTR_SELF_POWERED), bMaxPower: USB_CONFIG_MAX_POWER, CCI_Interface: @@ -77,7 +101,7 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = { Data: {0x00, 0x01} }, - // ManagementEndpoint: + // ManagementEndpoint: // { EP1_bLength: 0x07,//sizeof(USB_Descriptor_Endpoint), EP1_bDescriptorType: USB_DESCRIPTOR_TYPE_ENDPOINT, @@ -126,12 +150,12 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = { // } }; -/* +/* String Identifiers: we may choose to specify any or none of the following string identifiers: - + iManufacturer: LeafLabs iProduct: Maple R3 iSerialNumber: NONE @@ -143,7 +167,7 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = { which is 0x0409 for US English */ -const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = +const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = { USB_DESCRIPTOR_STRING_LEN(1), USB_DESCRIPTOR_TYPE_STRING, @@ -151,18 +175,18 @@ const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = 0x04 }; -const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = +const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = { USB_DESCRIPTOR_STRING_LEN(8), USB_DESCRIPTOR_TYPE_STRING, - 'L', 0, 'e', 0, 'a', 0, 'f', 0, + 'L', 0, 'e', 0, 'a', 0, 'f', 0, 'L', 0, 'a', 0, 'b', 0, 's', 0 }; -const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = +const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = { USB_DESCRIPTOR_STRING_LEN(8), USB_DESCRIPTOR_TYPE_STRING, - 'M', 0, 'a', 0, 'p', 0, 'l', 0, + 'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0, ' ', 0, 'R', 0, '3', 0 }; diff --git a/libmaple/usb/descriptors.h b/libmaple/usb/descriptors.h index 6652942..6f7d08b 100644 --- a/libmaple/usb/descriptors.h +++ b/libmaple/usb/descriptors.h @@ -1,4 +1,27 @@ -/* insert license */ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ****************************************************************************/ + #ifndef __DESCRIPTORS_H #define __DESCRIPTORS_H diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index 026d7f0..d875785 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -1,30 +1,30 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 LeafLabs LLC. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * ****************************************************************************/ + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ /** - * @file usb.c - * * @brief usb-specific hardware setup, NVIC, clocks, and usb activities * in the pre-attached state. includes some of the lower level callbacks * needed by the usb library, like suspend,resume,init,etc @@ -47,87 +47,75 @@ volatile uint16 wIstr = 0; volatile bIntPackSOF = 0; DEVICE Device_Table = - { - NUM_ENDPTS, - 1 - }; + {NUM_ENDPTS, + 1}; DEVICE_PROP Device_Property = - { - usbInit, - usbReset, - usbStatusIn, - usbStatusOut, - usbDataSetup, - usbNoDataSetup, - usbGetInterfaceSetting, - usbGetDeviceDescriptor, - usbGetConfigDescriptor, - usbGetStringDescriptor, - 0, - bMaxPacketSize - }; + {usbInit, + usbReset, + usbStatusIn, + usbStatusOut, + usbDataSetup, + usbNoDataSetup, + usbGetInterfaceSetting, + usbGetDeviceDescriptor, + usbGetConfigDescriptor, + usbGetStringDescriptor, + 0, + bMaxPacketSize}; USER_STANDARD_REQUESTS User_Standard_Requests = - { - NOP_Process, - usbSetConfiguration, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - usbSetDeviceAddress - }; + {NOP_Process, + usbSetConfiguration, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + usbSetDeviceAddress}; void (*pEpInt_IN[7])(void) = -{ - vcomDataTxCb, - vcomManagementCb, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, -}; + {vcomDataTxCb, + vcomManagementCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process}; void (*pEpInt_OUT[7])(void) = -{ - NOP_Process, - NOP_Process, - vcomDataRxCb, - NOP_Process, - NOP_Process, - NOP_Process, - NOP_Process, -}; - -struct -{ + {NOP_Process, + NOP_Process, + vcomDataRxCb, + NOP_Process, + NOP_Process, + NOP_Process, + NOP_Process}; + +struct { volatile RESUME_STATE eState; volatile uint8 bESOFcnt; } ResumeS; void setupUSB (void) { gpio_set_mode(USB_DISC_BANK, - USB_DISC_PIN, - GPIO_MODE_OUTPUT_PP); + USB_DISC_PIN, + GPIO_MODE_OUTPUT_PP); /* setup the apb1 clock for USB */ pRCC->APB1ENR |= 0x00800000; /* initialize the usb application */ - gpio_write_bit(USB_DISC_BANK, USB_DISC_PIN, 0); /* present ourselves to the host */ - - USB_Init(); /* low level init routine provided by st lib */ + gpio_write_bit(USB_DISC_BANK, USB_DISC_PIN, 0); // presents us to the host + USB_Init(); // low level init routine provided by the ST library } void disableUSB (void) { // These are just guesses about how to do this // TODO: real disable function usbDsbISR(); - gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,1); + gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,1); } void usbSuspend(void) { @@ -188,13 +176,12 @@ void usbResume(RESUME_STATE eResumeSetVal) { break; case RESUME_ON: ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) - { - wCNTR = _GetCNTR(); - wCNTR &= (~CNTR_RESUME); - _SetCNTR(wCNTR); - ResumeS.eState = RESUME_OFF; - } + if (ResumeS.bESOFcnt == 0) { + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_RESUME); + _SetCNTR(wCNTR); + ResumeS.eState = RESUME_OFF; + } break; case RESUME_OFF: case RESUME_ESOF: @@ -213,7 +200,7 @@ RESULT usbPowerOn(void) { wInterrupt_Mask = 0; _SetCNTR(wInterrupt_Mask); _SetISTR(0); - wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; /* the bare minimum */ + wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; // the bare minimum _SetCNTR(wInterrupt_Mask); return USB_SUCCESS; @@ -284,60 +271,51 @@ if (wIstr & ISTR_ERR & wInterrupt_Mask) #if (ISR_MSK & ISTR_WKUP) -if (wIstr & ISTR_WKUP & wInterrupt_Mask) - { +if (wIstr & ISTR_WKUP & wInterrupt_Mask) { _SetISTR((u16)CLR_WKUP); usbResume(RESUME_EXTERNAL); - } +} #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (ISR_MSK & ISTR_SUSP) -if (wIstr & ISTR_SUSP & wInterrupt_Mask) - { - +if (wIstr & ISTR_SUSP & wInterrupt_Mask) { /* check if SUSPEND is possible */ - if (F_SUSPEND_ENABLED) - { - usbSuspend(); - } - else - { - /* if not possible then resume after xx ms */ - usbResume(RESUME_LATER); - } + if (F_SUSPEND_ENABLED) { + usbSuspend(); + } else { + /* if not possible then resume after xx ms */ + usbResume(RESUME_LATER); + } /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ _SetISTR((u16)CLR_SUSP); - } +} #endif #if (ISR_MSK & ISTR_SOF) -if (wIstr & ISTR_SOF & wInterrupt_Mask) - { +if (wIstr & ISTR_SOF & wInterrupt_Mask) { _SetISTR((u16)CLR_SOF); bIntPackSOF++; - } + } #endif #if (ISR_MSK & ISTR_ESOF) -if (wIstr & ISTR_ESOF & wInterrupt_Mask) - { +if (wIstr & ISTR_ESOF & wInterrupt_Mask) { _SetISTR((u16)CLR_ESOF); /* resume handling timing is made with ESOFs */ usbResume(RESUME_ESOF); /* request without change of the machine state */ - } + } #endif /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ #if (ISR_MSK & ISTR_CTR) -if (wIstr & ISTR_CTR & wInterrupt_Mask) - { +if (wIstr & ISTR_CTR & wInterrupt_Mask) { /* servicing of the endpoint correct transfer interrupt */ /* clear of the CTR flag into the sub */ CTR_LP(); /* low priority ISR defined in the usb core lib */ - } + } #endif } @@ -349,87 +327,73 @@ void usbWaitReset(void) { /* This low-level send bytes function is NON-BLOCKING; blocking behavior, with * a timeout, is implemented in usercode (or in the Wirish C++ high level - * implementation). + * implementation). * * This function will quickly copy up to 64 bytes of data (out of an * arbitrarily large buffer) into the USB peripheral TX buffer and return the * number placed in that buffer. It is up to usercode to divide larger packets - * into 64-byte chunks to guarantee delivery. Use usbGetCountTx() to determine - * whether the bytes were ACTUALLY recieved by the host or just transfered to - * the buffer. + * into 64-byte chunks to guarantee delivery. * - * The function will return -1 if it doesn't think that the USB host is - * "connected", but it can't detect this state robustly. "Connected" in this - * context means that an actual program on the Host operating system is - * connected to the virtual COM/ttyACM device and is recieving the bytes; the - * Host operating system is almost always configured and keeping this endpoint - * alive, but the bytes never get read out of the endpoint buffer. * - * The behavior of this function is subtle and frustrating; it has gone through - * many simpler and cleaner implementation that frustratingly don't work cross - * platform. - * - * */ -uint16 usbSendBytes(uint8* sendBuf, uint16 len) { - - uint16 loaded = 0; - - if (bDeviceState != CONFIGURED || (!usbGetDTR() && !usbGetRTS())) { - // Indicates to caller to stop trying, were not configured/connected - // The DTR and RTS lines are handled differently on major platforms, so - // the above logic is unreliable - return 0; - } + */ +void usbBlockingSendByte(char ch) { + while (countTx); + UserToPMABufferCopy(&ch,VCOM_TX_ADDR,1); + _SetEPTxCount(VCOM_TX_ENDP,1); + _SetEPTxValid(VCOM_TX_ENDP); + countTx = 1; + while (countTx); +} +uint32 usbSendBytes(uint8* sendBuf, uint32 len) { + /* any checks on connection (via dtr/rts) done upstream in wirish or + by user */ - // Due to a variety of shit this is how we roll; all buffering etc is pushed - // upstream - if (countTx) { - return 0; + /* last xmit hasnt finished, abort */ + if (countTx) { + return 0; } // We can only put VCOM_TX_EPSIZE bytes in the buffer - if(len > VCOM_TX_EPSIZE) { - loaded = VCOM_TX_EPSIZE; - } else { - loaded = len; + if(len > VCOM_TX_EPSIZE/2) { + len = VCOM_TX_EPSIZE/2; } // Try to load some bytes if we can - if (loaded) { - UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR + countTx, loaded); - _SetEPTxCount(VCOM_TX_ENDP, countTx+loaded); + if (len) { + UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR, len); + _SetEPTxCount(VCOM_TX_ENDP, len); + countTx += len; _SetEPTxValid(VCOM_TX_ENDP); - countTx += loaded; } - return loaded; + return len; } /* returns the number of available bytes are in the recv FIFO */ -uint8 usbBytesAvailable(void) { - return VCOM_RX_EPSIZE - maxNewBytes; +uint32 usbBytesAvailable(void) { + return newBytes; } /* copies len bytes from the local recieve FIFO (not usb packet buffer) into recvBuf and deq's the fifo. will only copy the minimum of len or the available bytes. returns the number of bytes copied */ -uint8 usbReceiveBytes(uint8* recvBuf, uint8 len) { - if (len > VCOM_RX_EPSIZE - maxNewBytes) { - len = VCOM_RX_EPSIZE - maxNewBytes; +uint32 usbReceiveBytes(uint8* recvBuf, uint32 len) { + if (len > newBytes) { + len = newBytes; } int i; for (i=0;i<len;i++) { - recvBuf[i] = (uint8)(vcomBufferRx[recvBufOut]); - recvBufOut = (recvBufOut + 1) % VCOM_RX_EPSIZE; + recvBuf[i] = (uint8)(vcomBufferRx[i]); } - maxNewBytes += len; + newBytes -= len; /* re-enable the rx endpoint which we had set to receive 0 bytes */ - if (maxNewBytes - len == 0) { - SetEPRxCount(VCOM_RX_ENDP,maxNewBytes); + if (newBytes == 0) { + SetEPRxCount(VCOM_RX_ENDP,VCOM_RX_EPSIZE); + SetEPRxStatus(VCOM_RX_ENDP,EP_RX_VALID); } return len; @@ -466,7 +430,7 @@ uint8 usbIsConfigured() { uint8 usbIsConnected() { return (bDeviceState != UNCONNECTED); -} +} uint16 usbGetPending() { return countTx; diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h index ec179b1..0ed02e5 100644 --- a/libmaple/usb/usb.h +++ b/libmaple/usb/usb.h @@ -1,8 +1,31 @@ -/* insert license */ - -#ifndef __USB_H -#define __USB_H +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ +#ifndef _USB_H_ +#define _USB_H_ #include "usb_lib.h" #include "libmaple.h" @@ -11,8 +34,7 @@ extern "C" { #endif -typedef enum - { +typedef enum { RESUME_EXTERNAL, RESUME_INTERNAL, RESUME_LATER, @@ -21,51 +43,50 @@ typedef enum RESUME_ON, RESUME_OFF, RESUME_ESOF - } RESUME_STATE; +} RESUME_STATE; -typedef enum - { +typedef enum { UNCONNECTED, ATTACHED, POWERED, SUSPENDED, ADDRESSED, CONFIGURED - } DEVICE_STATE; +} DEVICE_STATE; + +extern volatile uint32 bDeviceState; - extern volatile uint32 bDeviceState; +void setupUSB(void); +void disableUSB(void); +void usbSuspend(void); +void usbResumeInit(void); +void usbResume(RESUME_STATE); - void setupUSB(void); - void disableUSB(void); - void usbSuspend(void); - void usbResumeInit(void); - void usbResume(RESUME_STATE); - - RESULT usbPowerOn(void); - RESULT usbPowerOff(void); - - void usbDsbISR(void); - void usbEnbISR(void); +RESULT usbPowerOn(void); +RESULT usbPowerOff(void); - /* overloaded ISR routine, this is the main usb ISR */ - void usb_lpIRQHandler(void); - void usbWaitReset(void); +void usbDsbISR(void); +void usbEnbISR(void); - /* blocking functions for send/receive */ - uint16 usbSendBytes(uint8* sendBuf,uint16 len); - uint8 usbBytesAvailable(void); - uint8 usbReceiveBytes(uint8* recvBuf, uint8 len); - uint8 usbGetDTR(void); - uint8 usbGetRTS(void); - uint8 usbIsConnected(void); - uint8 usbIsConfigured(void); - uint16 usbGetPending(void); +/* overloaded ISR routine, this is the main usb ISR */ +void usb_lpIRQHandler(void); +void usbWaitReset(void); - void usbSendHello(void); +/* blocking functions for send/receive */ +void usbBlockingSendByte(char ch); +uint32 usbSendBytes(uint8* sendBuf,uint32 len); +uint32 usbBytesAvailable(void); +uint32 usbReceiveBytes(uint8* recvBuf, uint32 len); +uint8 usbGetDTR(void); +uint8 usbGetRTS(void); +uint8 usbIsConnected(void); +uint8 usbIsConfigured(void); +uint16 usbGetPending(void); +void usbSendHello(void); #ifdef __cplusplus } // extern "C" #endif -#endif //_USB_H +#endif // _USB_H_ diff --git a/libmaple/usb/usb_callbacks.c b/libmaple/usb/usb_callbacks.c index 4cdaf73..ccb0fdd 100644 --- a/libmaple/usb/usb_callbacks.c +++ b/libmaple/usb/usb_callbacks.c @@ -8,19 +8,19 @@ #include "usb_hardware.h" ONE_DESCRIPTOR Device_Descriptor = { - (uint8*)&usbVcomDescriptor_Device, - sizeof(USB_Descriptor_Device) + (uint8*)&usbVcomDescriptor_Device, + sizeof(USB_Descriptor_Device) }; ONE_DESCRIPTOR Config_Descriptor = { - (uint8*)&usbVcomDescriptor_Config, - 0x43//sizeof(USB_Descriptor_Config) + (uint8*)&usbVcomDescriptor_Config, + 0x43//sizeof(USB_Descriptor_Config) }; ONE_DESCRIPTOR String_Descriptor[3] = { - {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, - {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)}, - {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)} + {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)}, + {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)}, + {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)} }; uint8 last_request = 0; @@ -32,22 +32,22 @@ USB_Line_Coding line_coding = { datatype: 0x08 }; -uint8 vcomBufferRx[VCOM_RX_EPSIZE]; -volatile uint8 countTx = 0; -volatile uint8 recvBufIn = 0; -volatile uint8 recvBufOut = 0; -volatile uint8 maxNewBytes = VCOM_RX_EPSIZE; - +uint8 vcomBufferRx[VCOM_RX_BUFLEN]; +volatile uint32 countTx = 0; +volatile uint32 recvBufIn = 0; +volatile uint32 recvBufOut = 0; +volatile uint32 maxNewBytes = VCOM_RX_BUFLEN; +volatile uint32 newBytes = 0; RESET_STATE reset_state = DTR_UNSET; uint8 line_dtr_rts = 0; void vcomDataTxCb(void) { - /* do whatever after data has been sent to host */ - - /* allows usbSendBytes to stop blocking */ + /* do whatever after data has been sent to host */ + /* allows usbSendBytes to stop blocking */ - countTx = 0; + /* assumes tx transactions are atomic 64 bytes (nearly certain they are) */ + countTx = 0; } /* we could get arbitrarily complicated here for speed purposes @@ -60,11 +60,11 @@ void vcomDataRxCb(void) { /* setEPRxCount on the previous cycle should garuntee we havnt received more bytes than we can fit */ - uint8 newBytes = GetEPRxCount(VCOM_RX_ENDP); - /* assert (newBytes <= maxNewBytes); */ + newBytes = GetEPRxCount(VCOM_RX_ENDP); + SetEPRxStatus(VCOM_RX_ENDP,EP_RX_NAK); /* todo, not checking very carefully for edge cases. USUALLY, - if we emit the reset pulse and send 4 bytes, then newBytes + if we emit the reset pulse and send 4 bytes, then newBytes should be 4. But its POSSIBLE that this would be violated in some cases */ @@ -82,270 +82,251 @@ void vcomDataRxCb(void) { int i; USB_Bool cmpMatch = TRUE; for (i=0; i<4; i++) { - if (chkBuf[i] != cmpBuf[i]) { - cmpMatch = FALSE; - } + if (chkBuf[i] != cmpBuf[i]) { + cmpMatch = FALSE; + } } if (cmpMatch) { - asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack - "mov sp, r0 \n\t" - "mov r0, #1 \n\t" - "mov r1, %[target_addr] \n\t" - "mov r2, %[cpsr] \n\t" - "push {r2} \n\t" // Fake xPSR - "push {r1} \n\t" // Target address for PC - "push {r0} \n\t" // Fake LR - "push {r0} \n\t" // Fake R12 - "push {r0} \n\t" // Fake R3 - "push {r0} \n\t" // Fake R2 - "push {r0} \n\t" // Fake R1 - "push {r0} \n\t" // Fake R0 - "mov lr, %[exc_return] \n\t" - "bx lr" - : - : [stack_top] "r" (STACK_TOP), - [target_addr] "r" (target), - [exc_return] "r" (EXC_RETURN), - [cpsr] "r" (DEFAULT_CPSR) - : "r0", "r1", "r2"); - /* should never get here */ + asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack + "mov sp, r0 \n\t" + "mov r0, #1 \n\t" + "mov r1, %[target_addr] \n\t" + "mov r2, %[cpsr] \n\t" + "push {r2} \n\t" // Fake xPSR + "push {r1} \n\t" // Target address for PC + "push {r0} \n\t" // Fake LR + "push {r0} \n\t" // Fake R12 + "push {r0} \n\t" // Fake R3 + "push {r0} \n\t" // Fake R2 + "push {r0} \n\t" // Fake R1 + "push {r0} \n\t" // Fake R0 + "mov lr, %[exc_return] \n\t" + "bx lr" + : + : [stack_top] "r" (STACK_TOP), + [target_addr] "r" (target), + [exc_return] "r" (EXC_RETURN), + [cpsr] "r" (DEFAULT_CPSR) + : "r0", "r1", "r2"); + /* should never get here */ } } } - - - if (recvBufIn + newBytes < VCOM_RX_EPSIZE) { - PMAToUserBufferCopy(&vcomBufferRx[recvBufIn],VCOM_RX_ADDR,newBytes); - recvBufIn += newBytes; - } else { - /* we have to copy the data in two chunks because we roll over - the edge of the circular buffer */ - uint8 tailBytes = VCOM_RX_EPSIZE - recvBufIn; - uint8 remaining = newBytes - tailBytes; - - PMAToUserBufferCopy(&vcomBufferRx[recvBufIn],VCOM_RX_ADDR,tailBytes); - PMAToUserBufferCopy(&vcomBufferRx[0], VCOM_RX_ADDR,remaining); - - recvBufIn = (recvBufIn + newBytes ) % VCOM_RX_EPSIZE; - } - - maxNewBytes -= newBytes; - SetEPRxCount(VCOM_RX_ENDP,maxNewBytes); - SetEPRxValid(VCOM_RX_ENDP); + PMAToUserBufferCopy(&vcomBufferRx[0],VCOM_RX_ADDR,newBytes); } void vcomManagementCb(void) { -/* unused. This enpoint would callback if we had sent a linestate - changed notification */ + /* unused. This enpoint would callback if we had sent a linestate + changed notification */ } u8* vcomGetSetLineCoding(uint16 length) { - if (length == 0) { - pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding); - } - return (uint8*)&line_coding; + if (length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding); + } + return (uint8*)&line_coding; } vcomSetLineState(void) { } void usbInit(void) { - pInformation->Current_Configuration = 0; - usbPowerOn(); + pInformation->Current_Configuration = 0; + usbPowerOn(); - _SetISTR(0); - wInterrupt_Mask = ISR_MSK; - _SetCNTR(wInterrupt_Mask); + _SetISTR(0); + wInterrupt_Mask = ISR_MSK; + _SetCNTR(wInterrupt_Mask); - usbEnbISR(); - bDeviceState = UNCONNECTED; + usbEnbISR(); + bDeviceState = UNCONNECTED; } void usbReset(void) { - pInformation->Current_Configuration = 0; - - /* current feature is current bmAttributes */ - pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED); - - _SetBTABLE(USB_BTABLE_ADDRESS); - - /* setup control endpoint 0 */ - _SetEPType(ENDP0, EP_CONTROL); - _SetEPTxStatus(ENDP0, EP_TX_STALL); - _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR); - _SetEPTxAddr(ENDP0,VCOM_CTRL_TX_ADDR); - Clear_Status_Out(ENDP0); - - SetEPRxCount(ENDP0, pProperty->MaxPacketSize); - SetEPRxValid(ENDP0); - - /* setup management endpoint 1 */ - SetEPType (VCOM_NOTIFICATION_ENDP, EP_INTERRUPT); - SetEPTxAddr (VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR); - SetEPTxStatus (VCOM_NOTIFICATION_ENDP, EP_TX_NAK); - SetEPRxStatus (VCOM_NOTIFICATION_ENDP, EP_RX_DIS); - - /* setup data endpoint OUT (rx) */ -/* SetEPType (VCOM_RX_ENDP, EP_BULK); */ -/* SetEPRxAddr (VCOM_RX_ENDP, VCOM_RX_ADDR); */ -/* SetEPRxCount (VCOM_RX_ENDP, VCOM_RX_EPSIZE); */ -/* // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); */ -/* SetEPRxStatus (VCOM_RX_ENDP, EP_RX_VALID); */ - - SetEPType (3, EP_BULK); - SetEPRxAddr (3, 0x110); - SetEPRxCount (3,64); - // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); - SetEPRxStatus (3, EP_RX_VALID); - - /* setup data endpoint IN (tx) */ - SetEPType (VCOM_TX_ENDP, EP_BULK); - SetEPTxAddr (VCOM_TX_ENDP, VCOM_TX_ADDR); - SetEPTxStatus (VCOM_TX_ENDP, EP_TX_NAK); - SetEPRxStatus (VCOM_TX_ENDP, EP_RX_DIS); - - bDeviceState = ATTACHED; - SetDeviceAddress(0); - - /* reset the rx fifo */ - recvBufIn = 0; - recvBufOut = 0; - maxNewBytes = VCOM_RX_EPSIZE; - countTx = 0; + pInformation->Current_Configuration = 0; + + /* current feature is current bmAttributes */ + pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELF_POWERED); + + _SetBTABLE(USB_BTABLE_ADDRESS); + + /* setup control endpoint 0 */ + _SetEPType(ENDP0, EP_CONTROL); + _SetEPTxStatus(ENDP0, EP_TX_STALL); + _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR); + _SetEPTxAddr(ENDP0,VCOM_CTRL_TX_ADDR); + Clear_Status_Out(ENDP0); + + SetEPRxCount(ENDP0, pProperty->MaxPacketSize); + SetEPRxValid(ENDP0); + + /* setup management endpoint 1 */ + SetEPType (VCOM_NOTIFICATION_ENDP, EP_INTERRUPT); + SetEPTxAddr (VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR); + SetEPTxStatus (VCOM_NOTIFICATION_ENDP, EP_TX_NAK); + SetEPRxStatus (VCOM_NOTIFICATION_ENDP, EP_RX_DIS); + + /* setup data endpoint OUT (rx) */ + /* SetEPType (VCOM_RX_ENDP, EP_BULK); */ + /* SetEPRxAddr (VCOM_RX_ENDP, VCOM_RX_ADDR); */ + /* SetEPRxCount (VCOM_RX_ENDP, VCOM_RX_EPSIZE); */ + /* // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); */ + /* SetEPRxStatus (VCOM_RX_ENDP, EP_RX_VALID); */ + + SetEPType (3, EP_BULK); + SetEPRxAddr (3, 0x110); + SetEPRxCount (3,64); + // SetEPTxStatus (VCOM_RX_ENDP, EP_TX_DIS); + SetEPRxStatus (3, EP_RX_VALID); + + /* setup data endpoint IN (tx) */ + SetEPType (VCOM_TX_ENDP, EP_BULK); + SetEPTxAddr (VCOM_TX_ENDP, VCOM_TX_ADDR); + SetEPTxStatus (VCOM_TX_ENDP, EP_TX_NAK); + SetEPRxStatus (VCOM_TX_ENDP, EP_RX_DIS); + + bDeviceState = ATTACHED; + SetDeviceAddress(0); + + /* reset the rx fifo */ + recvBufIn = 0; + recvBufOut = 0; + maxNewBytes = VCOM_RX_EPSIZE; + countTx = 0; } void usbStatusIn(void) { - /* adjust the usart line coding - if we wish to couple the CDC line coding - with the real usart port */ + /* adjust the usart line coding + if we wish to couple the CDC line coding + with the real usart port */ } void usbStatusOut(void) { } RESULT usbDataSetup(uint8 request) { - uint8 *(*CopyRoutine)(uint16); - CopyRoutine = NULL; - - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { - switch (request) { - case (GET_LINE_CODING): - CopyRoutine = vcomGetSetLineCoding; - last_request = GET_LINE_CODING; - break; - case (SET_LINE_CODING): - CopyRoutine = vcomGetSetLineCoding; - last_request = SET_LINE_CODING; - break; - default: break; + uint8 *(*CopyRoutine)(uint16); + CopyRoutine = NULL; + + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + switch (request) { + case (GET_LINE_CODING): + CopyRoutine = vcomGetSetLineCoding; + last_request = GET_LINE_CODING; + break; + case (SET_LINE_CODING): + CopyRoutine = vcomGetSetLineCoding; + last_request = SET_LINE_CODING; + break; + default: break; + } } - } - if (CopyRoutine == NULL) { - return USB_UNSUPPORT; - } + if (CopyRoutine == NULL) { + return USB_UNSUPPORT; + } - pInformation->Ctrl_Info.CopyData = CopyRoutine; - pInformation->Ctrl_Info.Usb_wOffset = 0; - (*CopyRoutine)(0); - return USB_SUCCESS; + pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyRoutine)(0); + return USB_SUCCESS; } RESULT usbNoDataSetup(u8 request) { - uint8 new_signal; - - /* we support set com feature but dont handle it */ - if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { - - switch (request) { - case (SET_COMM_FEATURE): - return USB_SUCCESS; - case (SET_CONTROL_LINE_STATE): - /* to reset the board, pull both dtr and rts low - then pulse dtr by itself */ - new_signal = pInformation->USBwValues.bw.bb0 & (CONTROL_LINE_DTR | CONTROL_LINE_RTS); - line_dtr_rts = new_signal & 0x03; - - switch (reset_state) { - /* no default, covered enum */ - case DTR_UNSET: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_LOW; - } else { - reset_state = DTR_HIGH; - } - break; - - case DTR_HIGH: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_NEGEDGE; - } else { - reset_state = DTR_HIGH; - } - break; - - case DTR_NEGEDGE: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_LOW; - } else { - reset_state = DTR_HIGH; - } - break; - - case DTR_LOW: - if ((new_signal & CONTROL_LINE_DTR) == 0 ) { - reset_state = DTR_LOW; - } else { - reset_state = DTR_HIGH; - } - break; - } - - return USB_SUCCESS; + uint8 new_signal; + + /* we support set com feature but dont handle it */ + if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { + + switch (request) { + case (SET_COMM_FEATURE): + return USB_SUCCESS; + case (SET_CONTROL_LINE_STATE): + /* to reset the board, pull both dtr and rts low + then pulse dtr by itself */ + new_signal = pInformation->USBwValues.bw.bb0 & (CONTROL_LINE_DTR | CONTROL_LINE_RTS); + line_dtr_rts = new_signal & 0x03; + + switch (reset_state) { + /* no default, covered enum */ + case DTR_UNSET: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_LOW; + } else { + reset_state = DTR_HIGH; + } + break; + + case DTR_HIGH: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_NEGEDGE; + } else { + reset_state = DTR_HIGH; + } + break; + + case DTR_NEGEDGE: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_LOW; + } else { + reset_state = DTR_HIGH; + } + break; + + case DTR_LOW: + if ((new_signal & CONTROL_LINE_DTR) == 0 ) { + reset_state = DTR_LOW; + } else { + reset_state = DTR_HIGH; + } + break; + } + + return USB_SUCCESS; + } } - } - return USB_UNSUPPORT; + return USB_UNSUPPORT; } RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) { - if (alt_setting > 0) { - return USB_UNSUPPORT; - } else if (interface > 1) { - return USB_UNSUPPORT; - } + if (alt_setting > 0) { + return USB_UNSUPPORT; + } else if (interface > 1) { + return USB_UNSUPPORT; + } - return USB_SUCCESS; + return USB_SUCCESS; } u8* usbGetDeviceDescriptor(u16 length) { - return Standard_GetDescriptorData(length, &Device_Descriptor); + return Standard_GetDescriptorData(length, &Device_Descriptor); } u8* usbGetConfigDescriptor(u16 length) { - return Standard_GetDescriptorData(length, &Config_Descriptor); + return Standard_GetDescriptorData(length, &Config_Descriptor); } u8* usbGetStringDescriptor(u16 length) { - uint8 wValue0 = pInformation->USBwValue0; + uint8 wValue0 = pInformation->USBwValue0; - if (wValue0 > 2) { - return NULL; - } - return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); + if (wValue0 > 2) { + return NULL; + } + return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]); } /* internal callbacks to respond to standard requests */ void usbSetConfiguration(void) { - if (pInformation->Current_Configuration != 0) { - bDeviceState = CONFIGURED; - } + if (pInformation->Current_Configuration != 0) { + bDeviceState = CONFIGURED; + } } void usbSetDeviceAddress(void) { - bDeviceState = ADDRESSED; + bDeviceState = ADDRESSED; } diff --git a/libmaple/usb/usb_callbacks.h b/libmaple/usb/usb_callbacks.h index a94de11..20d2c13 100644 --- a/libmaple/usb/usb_callbacks.h +++ b/libmaple/usb/usb_callbacks.h @@ -34,11 +34,12 @@ typedef enum { extern RESET_STATE reset_state; /* tracks DTR/RTS */ extern uint8 line_dtr_rts; -extern volatile uint8 countTx; -extern uint8 vcomBufferRx[VCOM_RX_EPSIZE]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */ -extern volatile uint8 recvBufIn; /* the FIFO in index to the recvbuffer */ -extern volatile uint8 recvBufOut; /* the FIFO out index to the recvbuffer */ -extern volatile uint8 maxNewBytes; +extern volatile uint32 countTx; +extern uint8 vcomBufferRx[VCOM_RX_BUFLEN]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */ +extern volatile uint32 recvBufIn; /* the FIFO in index to the recvbuffer */ +extern volatile uint32 recvBufOut; /* the FIFO out index to the recvbuffer */ +extern volatile uint32 maxNewBytes; +extern volatile uint32 newBytes; void vcomDataTxCb(void); void vcomDataRxCb(void); diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index ba05d42..e5f3979 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -26,6 +26,7 @@ #define VCOM_RX_EPNUM 0x03 #define VCOM_RX_ADDR 0x110 #define VCOM_RX_EPSIZE 0x40 +#define VCOM_RX_BUFLEN (VCOM_RX_EPSIZE*3) #define bMaxPacketSize 0x40 /* 64B, maximum for USB FS Devices */ diff --git a/libmaple/usb/usb_hardware.c b/libmaple/usb/usb_hardware.c index 2f37df6..505dcf1 100644 --- a/libmaple/usb/usb_hardware.c +++ b/libmaple/usb/usb_hardware.c @@ -1,29 +1,31 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 LeafLabs LLC. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * ****************************************************************************/ + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ /** - * @file hardware.c + * @file usb_hardware.c * * @brief init routines to setup clocks and interrupts for usb. * @@ -32,97 +34,106 @@ #include "usb_hardware.h" void setPin(u32 bank, u8 pin) { - u32 pinMask = 0x1 << (pin); - SET_REG(GPIO_BSRR(bank),pinMask); + u32 pinMask = 0x1 << (pin); + SET_REG(GPIO_BSRR(bank),pinMask); } void resetPin(u32 bank, u8 pin) { - u32 pinMask = 0x1 << (16+pin); - SET_REG(GPIO_BSRR(bank),pinMask); + u32 pinMask = 0x1 << (16+pin); + SET_REG(GPIO_BSRR(bank),pinMask); } void systemReset(void) { - SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001); - SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000); - SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF); - SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF); - SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF); + SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001); + SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000); + SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF); + SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF); + SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF); - SET_REG(RCC_CIR, 0x00000000); /* disable all RCC interrupts */ + SET_REG(RCC_CIR, 0x00000000); // disable all RCC interrupts } void setupCLK (void) { - /* enable HSE */ - SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x00010001); - while ((GET_REG(RCC_CR) & 0x00020000) == 0); /* for it to come on */ - - /* Configure PLL */ - SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x001D0400); /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */ - SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x01000000); /* enable the pll */ - while ((GET_REG(RCC_CR) & 0x03000000) == 0); /* wait for it to come on */ - - /* Set SYSCLK as PLL */ - SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x00000002); - while ((GET_REG(RCC_CFGR) & 0x00000008) == 0); /* wait for it to come on */ + /* enable HSE */ + SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x00010001); + /* for it to come on */ + while ((GET_REG(RCC_CR) & 0x00020000) == 0); + + /* Configure PLL */ + /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */ + SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x001D0400); + /* enable the pll */ + SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x01000000); + /* wait for it to come on */ + while ((GET_REG(RCC_CR) & 0x03000000) == 0); + + /* Set SYSCLK as PLL */ + SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x00000002); + /* wait for it to come on */ + while ((GET_REG(RCC_CFGR) & 0x00000008) == 0); } void nvicInit(NVIC_InitTypeDef* NVIC_InitStruct) { - u32 tmppriority = 0x00; - u32 tmpreg = 0x00; - u32 tmpmask = 0x00; - u32 tmppre = 0; - u32 tmpsub = 0x0F; - - SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; - NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE; - - - /* Compute the Corresponding IRQ Priority --------------------------------*/ - tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700))>> 0x08; - tmppre = (0x4 - tmppriority); - tmpsub = tmpsub >> tmppriority; - - tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre; - tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub; - - tmppriority = tmppriority << 0x04; - tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08); - - tmpreg = rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)]; - tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08); - tmpreg &= ~tmpmask; - tmppriority &= tmpmask; - tmpreg |= tmppriority; - - rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg; - - /* Enable the Selected IRQ Channels --------------------------------------*/ - rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] = - (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F); + u32 tmppriority = 0x00; + u32 tmpreg = 0x00; + u32 tmpmask = 0x00; + u32 tmppre = 0; + u32 tmpsub = 0x0F; + + SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; + NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE; + + + /* Compute the Corresponding IRQ Priority -------------------------------*/ + tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700))>> 0x08; + tmppre = (0x4 - tmppriority); + tmpsub = tmpsub >> tmppriority; + + tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << + tmppre; + tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub; + + tmppriority = tmppriority << 0x04; + tmppriority = ((u32)tmppriority) << + ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08); + + tmpreg = rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)]; + tmpmask = (u32)0xFF << + ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08); + tmpreg &= ~tmpmask; + tmppriority &= tmpmask; + tmpreg |= tmppriority; + + rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg; + + /* Enable the Selected IRQ Channels -------------------------------------*/ + rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] = + (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F); } void nvicDisableInterrupts() { - NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE; - rNVIC->ICER[0] = 0xFFFFFFFF; - rNVIC->ICER[1] = 0xFFFFFFFF; - rNVIC->ICPR[0] = 0xFFFFFFFF; - rNVIC->ICPR[1] = 0xFFFFFFFF; - - SET_REG(STK_CTRL,0x04); /* disable the systick, which operates separately from nvic */ + NVIC_TypeDef* rNVIC = (NVIC_TypeDef *) NVIC_BASE; + rNVIC->ICER[0] = 0xFFFFFFFF; + rNVIC->ICER[1] = 0xFFFFFFFF; + rNVIC->ICPR[0] = 0xFFFFFFFF; + rNVIC->ICPR[1] = 0xFFFFFFFF; + + /* Disable the systick timer, which operates separately from NVIC */ + SET_REG(STK_CTRL,0x04); } void systemHardReset(void) { - SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; - typedef void (*funcPtr)(void); - - /* Reset */ - rSCB->AIRCR = (u32)AIRCR_RESET_REQ; - - /* should never get here */ - while (1) { - asm volatile("nop"); - } + SCB_TypeDef* rSCB = (SCB_TypeDef *) SCB_BASE; + typedef void (*funcPtr)(void); + + /* Reset */ + rSCB->AIRCR = (u32)AIRCR_RESET_REQ; + + /* Should never get here */ + while (1) { + asm volatile("nop"); + } } diff --git a/libmaple/util.c b/libmaple/util.c index be29e7e..135f005 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -23,8 +23,6 @@ *****************************************************************************/ /** - * @file util.h - * * @brief Utility procedures for debugging, mostly an error LED fade * and messages dumped over a uart for failed asserts. */ diff --git a/libmaple/util.h b/libmaple/util.h index b6074d8..64782d9 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -77,10 +77,6 @@ void throb(void); /* Asserts for sanity checks, redefine DEBUG_LEVEL in libmaple.h to * compile out these checks */ -#define DEBUG_NONE 0 -#define DEBUG_FAULT 1 -#define DEBUG_ALL 2 - #if DEBUG_LEVEL >= DEBUG_ALL #define ASSERT(exp) \ if (exp) { \ |