From e7d600494579ef319b20221769c3b2fe12962243 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Tue, 30 Mar 2010 20:52:45 -0400 Subject: Major hierarchy reorganization; see README. copy-to-ide and Makefile updated to conform; .gitignore added; LICENSE added --- libmaple/adc.c | 97 ++++++++ libmaple/adc.h | 93 ++++++++ libmaple/bootVect.h | 52 +++++ libmaple/exti.c | 279 +++++++++++++++++++++++ libmaple/exti.h | 152 +++++++++++++ libmaple/gpio.c | 55 +++++ libmaple/gpio.h | 97 ++++++++ libmaple/libmaple.h | 33 +++ libmaple/libmaple_types.h | 42 ++++ libmaple/nvic.c | 59 +++++ libmaple/nvic.h | 67 ++++++ libmaple/stm32f10x_conf.h | 132 +++++++++++ libmaple/stm32f10x_it.c | 252 +++++++++++++++++++++ libmaple/syscalls.c | 157 +++++++++++++ libmaple/systick.c | 52 +++++ libmaple/systick.h | 62 ++++++ libmaple/timers.c | 192 ++++++++++++++++ libmaple/timers.h | 145 ++++++++++++ libmaple/usart.c | 345 ++++++++++++++++++++++++++++ libmaple/usart.h | 53 +++++ libmaple/usb.c | 83 +++++++ libmaple/usb.h | 32 +++ libmaple/usb_regs.h | 555 ++++++++++++++++++++++++++++++++++++++++++++++ libmaple/util.c | 103 +++++++++ libmaple/util.h | 82 +++++++ 25 files changed, 3271 insertions(+) create mode 100644 libmaple/adc.c create mode 100644 libmaple/adc.h create mode 100644 libmaple/bootVect.h create mode 100644 libmaple/exti.c create mode 100644 libmaple/exti.h create mode 100644 libmaple/gpio.c create mode 100644 libmaple/gpio.h create mode 100644 libmaple/libmaple.h create mode 100644 libmaple/libmaple_types.h create mode 100644 libmaple/nvic.c create mode 100644 libmaple/nvic.h create mode 100644 libmaple/stm32f10x_conf.h create mode 100644 libmaple/stm32f10x_it.c create mode 100644 libmaple/syscalls.c create mode 100644 libmaple/systick.c create mode 100644 libmaple/systick.h create mode 100644 libmaple/timers.c create mode 100644 libmaple/timers.h create mode 100644 libmaple/usart.c create mode 100644 libmaple/usart.h create mode 100644 libmaple/usb.c create mode 100644 libmaple/usb.h create mode 100644 libmaple/usb_regs.h create mode 100644 libmaple/util.c create mode 100644 libmaple/util.h (limited to 'libmaple') diff --git a/libmaple/adc.c b/libmaple/adc.c new file mode 100644 index 0000000..7169824 --- /dev/null +++ b/libmaple/adc.c @@ -0,0 +1,97 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:34:47 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file adc.c + * + * @brief Analog to digital converter routines + */ + +#include "stm32f10x_rcc.h" +#include "adc.h" +#include +#include + +/* The ADC input clock is generated from PCLK2/APB2 divided by a prescaler + * and it must not exceed 14MHz. + * + * ADC1 and ADC2 are clocked by APB2 + * + * 1) Power on by setting ADON in ADC_CR2 + * Conversion starts when ADON is set for a second time after some + * time t > t_stab. + * + * Up to 16 selected conversion must be selected in ADC_SQRx + * + * Single conversion mode: + * Set the ADON bit in the ADC_CR2 register + * Once the conversion is complete: + * Converted data is stored in ADC_DR + * EOC flag is set + * Interrupt is generated if EOCIE is set + * + * Calibration: + * Calibration is started by setting the CAL bit in the ADC_CR2 register. + * Once calibration is over, the CAL bit is reset by hardware and normal + * conversion can be performed. Calibrate at power-on. + * + * ALIGN in ADC_CR2 selects the alignment of data + * + * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5 + * sample conversion time. + * + * At 55.5 cycles/sample, the external input impedance < 50kOhms*/ + +void adc_init(void) { + /* PCLK2 is the APB2 clock */ + RCC_ADCCLKConfig(RCC_PCLK2_Div6); + + /* Enable ADC1 clock so that we can talk to it */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); + + /* Put everything back to power-on defaults */ + RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE); + + ADC_CR1 = 0; + ADC_CR2 = CR2_EXTSEL_SWSTART | CR2_EXTTRIG; // Software triggers conversions + ADC_SQR1 = 0; + + /* Up the sample conversion time to 55.5 cycles/sec, see note above */ + /* TODO: fix magic numbers */ + ADC_SMPR1 = 0xB6DB6D; + ADC_SMPR2 = 0x2DB6DB6D; + + /* Enable the ADC */ + CR2_ADON_BIT = 1; + + /* Reset the calibration registers and then perform a reset */ + CR2_RSTCAL_BIT = 1; + while(CR2_RSTCAL_BIT) + ; + + CR2_CAL_BIT = 1; + while(CR2_CAL_BIT) + ; +} + + +void adc_disable(void) { + CR2_ADON_BIT = 0; +} diff --git a/libmaple/adc.h b/libmaple/adc.h new file mode 100644 index 0000000..d554b02 --- /dev/null +++ b/libmaple/adc.h @@ -0,0 +1,93 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:35:10 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file adc.h + * + * @brief ADC prototypes and defines + */ + +#ifndef _ADC_H_ +#define _ADC_H_ +#include +#include "util.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/* Notes: + * The maximum input impedance on each channel MUST be below .4kohms, + * or face the wrath of incorrect readings... + * This can be changed at the expense of sample time... see datasheet + * + * Need to up the sample time if otherwise... see datasheet */ + +/* We'll only use ADC1 for now... */ +#define ADC_BASE 0x40012400 +#define ADC_SR *(volatile uint32_t*)(ADC_BASE + 0) +#define ADC_CR1 *(volatile uint32_t*)(ADC_BASE + 0x4) +#define ADC_CR2 *(volatile uint32_t*)(ADC_BASE + 0x8) +#define ADC_SMPR1 *(volatile uint32_t*)(ADC_BASE + 0xC) +#define ADC_SMPR2 *(volatile uint32_t*)(ADC_BASE + 0x10) +#define ADC_SQR1 *(volatile uint32_t*)(ADC_BASE + 0x2C) +#define ADC_SQR3 *(volatile uint32_t*)(ADC_BASE + 0x34) +#define ADC_DR *(volatile uint32_t*)(ADC_BASE + 0x4C) + +#define CR2_EXTSEL_SWSTART (0xE << 16) +#define CR2_RSTCAL (BIT(3)) +#define CR2_EXTTRIG (BIT(20)) + +/* Bit banded bits */ +#define CR2_ADON_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8, 0)) +#define CR2_CAL_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8, 2)) +#define CR2_RSTCAL_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8, 3)) +#define CR2_SWSTART_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8 + 2, 6)) +#define SR_EOC_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0, 1)) + +#define NR_ANALOG_PINS 16 + +/* Initialize ADC1 to do one-shot conversions */ +void adc_init(void); +void adc_disable(void); + +/* Perform a single conversion on ADC[0-16], + * PRECONDITIONS: + * adc initialized */ +static inline int adc_read(int channel) { + /* Set channel */ + ADC_SQR3 = channel; + + /* Start the conversion */ + CR2_SWSTART_BIT = 1; + + /* Wait for it to finish */ + while(SR_EOC_BIT == 0) + ; + + return ADC_DR; +} + + + +#ifdef __cplusplus +} // extern "C" +#endif +#endif + diff --git a/libmaple/bootVect.h b/libmaple/bootVect.h new file mode 100644 index 0000000..5bcb42b --- /dev/null +++ b/libmaple/bootVect.h @@ -0,0 +1,52 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * ****************************************************************************/ + +/** + * @file HardwareUsb.h + * + * @brief Defines the maple boot vector structure + */ + +#ifndef _BOOTVECT_H_ +#define _BOOTVECT_H_ + +#define BOOTLOADER_VECT_TABLE ((uint32_t*)0x20000000) + +#ifdef __cplusplus +extern "C"{ +#endif + +typedef void (*FuncPtr)(void); + +typedef struct { + FuncPtr serial_tx_cb; + FuncPtr serial_rx_cb; + FuncPtr serial_linecoding_cb; + uint32_t* serial_count_in; + uint32_t* serial_count_out; + uint8_t* serial_buffer_out; + void* linecoding; + uint8_t major_rev; + uint8_t minor_rev; + void* usb_device_ptr; + void* usb_local_obj_ptr; +} BootVectTable; + +#ifdef __cplusplus +} +#endif + +#endif // _BOOTVECT_H_ diff --git a/libmaple/exti.c b/libmaple/exti.c new file mode 100644 index 0000000..bdaa204 --- /dev/null +++ b/libmaple/exti.c @@ -0,0 +1,279 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:35:22 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file exti.c + * + * @brief External interrupt control routines + */ + +#include "libmaple.h" +#include "exti.h" +#include "nvic.h" + +volatile static voidFuncPtr exti_handlers[NR_EXTI_CHANNELS]; + +static inline void clear_pending(int bit) { + REG_SET(EXTI_PR, BIT(bit)); + /* If the pending bit is cleared as the last instruction in an ISR, + * it won't actually be cleared in time and the ISR will fire again. + * Insert a 2-cycle buffer to allow it to take effect. */ + asm volatile("nop"); + asm volatile("nop"); +} + +/* For EXTI0 through EXTI4, only one handler + * is associated with each channel, so we + * don't have to keep track of which channel + * we came from */ +void EXTI0_IRQHandler(void) { + ASSERT(exti_handlers[EXTI0]); + if (exti_handlers[EXTI0]) { + exti_handlers[EXTI0](); + } + + /* Clear pending bit*/ + clear_pending(EXTI0); +} + +void EXTI1_IRQHandler(void) { + ASSERT(exti_handlers[EXTI1]); + /* Call registered handler */ + if (exti_handlers[EXTI1]) { + exti_handlers[EXTI1](); + } + + /* Clear pending bit*/ + clear_pending(EXTI1); +} + +void EXTI2_IRQHandler(void) { + ASSERT(exti_handlers[EXTI2]); + /* Call registered handler */ + if (exti_handlers[EXTI2]) { + exti_handlers[EXTI2](); + } + + /* Clear pending bit*/ + clear_pending(EXTI2); +} + +void EXTI3_IRQHandler(void) { + ASSERT(exti_handlers[EXTI3]); + /* Call registered handler */ + if (exti_handlers[EXTI3]) { + exti_handlers[EXTI3](); + } + + /* Clear pending bit*/ + clear_pending(EXTI3); +} + +void EXTI4_IRQHandler(void) { + ASSERT(exti_handlers[EXTI4]); + /* Call registered handler */ + if (exti_handlers[EXTI4]) { + exti_handlers[EXTI4](); + } + + /* Clear pending bit*/ + clear_pending(EXTI4); +} + +void EXTI9_5_IRQHandler(void) { + /* Figure out which channel it came from */ + uint32_t pending; + uint32_t i; + pending = REG_GET(EXTI_PR); + pending = GET_BITS(pending, 5, 9); + + /* Dispatch every handler if the pending bit is set */ + for (i = 0; i < 5; i++) { + if (pending & 0x1) { + ASSERT(exti_handlers[EXTI5 + i]); + exti_handlers[EXTI5 + i](); + clear_pending(EXTI5 + i); + } + pending >>= 1; + } +} + +void EXTI15_10_IRQHandler(void) { + /* Figure out which channel it came from */ + uint32_t pending; + uint32_t i; + pending = REG_GET(EXTI_PR); + pending = GET_BITS(pending, 10, 15); + + /* Dispatch every handler if the pending bit is set */ + for (i = 0; i < 6; i++) { + if (pending & 0x1) { + ASSERT(exti_handlers[EXTI10 + i]); + exti_handlers[EXTI10 + i](); + clear_pending(EXTI10 + i); + } + pending >>= 1; + } +} + + +void exti_attach_interrupt(uint8_t channel, uint8_t port, voidFuncPtr handler, uint8_t mode) { + ASSERT(channel < NR_EXTI_CHANNELS); + ASSERT(port < NR_EXTI_PORTS); + ASSERT(mode < NR_EXTI_MODES); + ASSERT(EXTI0 == 0); + ASSERT(handler); + + /* Note: All of the following code assumes that EXTI0 = 0 */ + + /* Map port to the correct EXTI channel */ + switch (channel) { + case EXTI0: + case EXTI1: + case EXTI2: + case EXTI3: + REG_SET_MASK(AFIO_EXTICR1, BIT_MASK_SHIFT(port, channel*4)); + break; + + case EXTI4: + case EXTI5: + case EXTI6: + case EXTI7: + REG_SET_MASK(AFIO_EXTICR2, BIT_MASK_SHIFT(port, (channel-4)*4)); + break; + + case EXTI8: + case EXTI9: + case EXTI10: + case EXTI11: + REG_SET_MASK(AFIO_EXTICR3, BIT_MASK_SHIFT(port, (channel-8)*4)); + break; + + case EXTI12: + case EXTI13: + case EXTI14: + case EXTI15: + REG_SET_MASK(AFIO_EXTICR4, BIT_MASK_SHIFT(port, (channel-12)*4)); + break; + } + + /* Unmask appropriate interrupt line */ + REG_SET_BIT(EXTI_IMR, channel); + + /* Set trigger mode */ + switch (mode) { + case EXTI_RISING: + REG_SET_BIT(EXTI_RTSR, channel); + break; + + case EXTI_FALLING: + REG_SET_BIT(EXTI_FTSR, channel); + break; + + case EXTI_RISING_FALLING: + REG_SET_BIT(EXTI_RTSR, channel); + REG_SET_BIT(EXTI_FTSR, channel); + break; + } + + /* Configure the enable interrupt bits for the NVIC */ + switch (channel) { + case EXTI0: + case EXTI1: + case EXTI2: + case EXTI3: + case EXTI4: + REG_SET(NVIC_ISER0, BIT(channel + 6)); + break; + + /* EXTI5-9 map to the same isr */ + case EXTI5: + case EXTI6: + case EXTI7: + case EXTI8: + case EXTI9: + REG_SET(NVIC_ISER0, BIT(23)); + break; + + /* EXTI10-15 map to the same isr */ + case EXTI10: + case EXTI11: + case EXTI12: + case EXTI13: + case EXTI14: + case EXTI15: + REG_SET(NVIC_ISER1, BIT(8)); + break; + } + + /* Register the handler */ + exti_handlers[channel] = handler; +} + + +void exti_detach_interrupt(uint8_t channel) { + ASSERT(channel < NR_EXTI_CHANNELS); + ASSERT(EXTI0 == 0); + /* Is this interrupt actually on? */ + ASSERT((REG_GET(EXTI_IMR) >> channel) & 0x01); + + /* Clear EXTI_IMR line */ + REG_CLEAR_BIT(EXTI_IMR, channel); + + /* Clear triggers */ + REG_CLEAR_BIT(EXTI_FTSR, channel); + REG_CLEAR_BIT(EXTI_RTSR, channel); + + /* Turn off the associated interrupt */ + switch (channel) { + case EXTI0: + case EXTI1: + case EXTI2: + case EXTI3: + case EXTI4: + REG_SET(NVIC_ICER0, BIT(channel + 6)); + break; + case EXTI5: + case EXTI6: + case EXTI7: + case EXTI8: + case EXTI9: + /* Are there any other channels enabled? + * If so, don't disable the interrupt handler */ + if (GET_BITS(REG_GET(EXTI_IMR), 5, 9) == 0) { + REG_SET(NVIC_ICER0, BIT(23)); + } + break; + case EXTI10: + case EXTI11: + case EXTI12: + case EXTI13: + case EXTI14: + case EXTI15: + /* Are there any other channels enabled? + * If so, don't disable the interrupt handler */ + if (GET_BITS(REG_GET(EXTI_IMR), 10, 15) == 0) { + REG_SET(NVIC_ICER1, BIT(8)); + } + break; + } + + /* Clear handler function pointer */ + exti_handlers[channel] = 0; +} diff --git a/libmaple/exti.h b/libmaple/exti.h new file mode 100644 index 0000000..c728454 --- /dev/null +++ b/libmaple/exti.h @@ -0,0 +1,152 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:35:33 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file exti.h + * + * @brief External interrupt control prototypes and defines + */ + +#ifndef _EXTI_H_ +#define _EXTI_H_ + +#include +/* Notes: + * + * To generate the interrupt, the interrupt line should be configured and + * enabled. This is done by programming the two trigger registers with the + * desired edge detection and by enabling the interrupt request by writing a + * '1' to the corresponding bit in the interrupt mask register. When the + * selected edge occurs on the external interrupt line, an interrupt request is + * generated. The pending bit corresponding to the interrupt line is also set. + * This request is reset by writing a '1' in the pending register. + * + * Hardware interrupt selection: + * To configure the 20 lines as interrupt sources, use the following procedure: + * 1) Configure AFIO_EXTIICR[y] to select the source input for EXTIx external + * interrupt + * 2) Configure the mask bits of the 20 interrupt lines (EXTI_IMR) + * 3) Configure the trigger selection bits of the interrupt lines (EXTI_RTSR and EXTI_FTSR) + * 4) Configure the enable and mask bits that control the NVIC_IRQ channel mapped to the External + * Interrupt Controller (EXTI) so that an inerrupt coming from one of the 20 lines + * can be correctly acknowledged. + * + * AFIO clock must be on. + * + * RM0008, page 107: "PD0, PD1 cannot be used for external interrupt/event generation + * on 36, 48, 64-bin packages." + * + * ---------------------------------------------------------------------------- + * Pin to EXTI Line Mappings: + * EXTI0 EXTI1 EXTI2 EXTI3 EXTI4 + * ---------------------------------------------------------------------------- + * D2/PA0 D3/PA1 D1/PA2 D0/A6/PA3 D10/A10/PA4 + * D26/EXT7/PB0 D27/EXT8/PB1 D16/A2/PC2 D17/A3/PC3 D18/A4/PC4 + * D14/A0/PC0 D15/PC1 D25/EXT5/PD2 + * + * EXTI5 EXTI6 EXTI7 EXTI8 EXTI9 + * ---------------------------------------------------------------------------- + * D13/A13/PA5 D12/A12/PA6 D11/A11/PA7 D6/PA8 D7/PA9 + * D4/PB5 D5/PB6 D9/PB7 D38/PB8 D23/EXT4/PB9 + * D19/A5/PC5 D34/EXTI15/PC6 D35/EXT16/PC7 D36/PC8 D37/EXT18/PC9 + * + * EXTI10 EXTI11 EXTI12 EXTI13 EXTI14 + * ---------------------------------------------------------------------------- + * D8/PA10 D29/EXT10/PB11 D30/EXTI1/PB12 D31/EXTI12/PB13 D32/EXT13/PB14 + * D28/PB10 D20/EXTI1/PC13 D21/EXT2/PC14 + * D25/PC10 + * + * EXTI15 + * ---------------------------------------------------------------------------- + * D33/EXTI14/PB15 + * D22/EXT3/PC15 + * + * + * The 16 EXTI interrupts are mapped to 7 interrupt handlers. + * + * EXTI Lines to Interrupt Mapping: + * EXTI0 -> EXTI0 + * EXTI1 -> EXTI1 + * EXTI2 -> EXTI2 + * EXTI3 -> EXTI3 + * EXTI4 -> EXTI4 + * EXTI[5-9] -> EXT9_5 + * EXTI[10-15] -> EXT15_10 + * + * + * */ + +#define NR_EXTI_CHANNELS 16 +#define NR_EXTI_PORTS 4 +#define NR_EXTI_MODES 3 + +#define EXTI_IMR 0x40010400 // Interrupt mask register +#define EXTI_EMR (EXTI_IMR + 0x04) // Event mask register +#define EXTI_RTSR (EXTI_IMR + 0x08) // Rising trigger selection register +#define EXTI_FTSR (EXTI_IMR + 0x0C) // Falling trigger selection register +#define EXTI_SWIER (EXTI_IMR + 0x10) // Software interrupt event register +#define EXTI_PR (EXTI_IMR + 0x14) // Pending register + +#define AFIO_EVCR 0x40010000 +#define AFIO_EXTICR1 (AFIO_EVCR + 0x08) +#define AFIO_EXTICR2 (AFIO_EVCR + 0x0C) +#define AFIO_EXTICR3 (AFIO_EVCR + 0x10) +#define AFIO_EXTICR4 (AFIO_EVCR + 0x14) + +#define EXTI_RISING 0 +#define EXTI_FALLING 1 +#define EXTI_RISING_FALLING 2 + +#define EXTI0 0 +#define EXTI1 1 +#define EXTI2 2 +#define EXTI3 3 +#define EXTI4 4 +#define EXTI5 5 +#define EXTI6 6 +#define EXTI7 7 +#define EXTI8 8 +#define EXTI9 9 +#define EXTI10 10 +#define EXTI11 11 +#define EXTI12 12 +#define EXTI13 13 +#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 + + +#ifdef __cplusplus +extern "C"{ +#endif + +void exti_attach_interrupt(uint8_t, uint8_t, voidFuncPtr, uint8_t); +void exti_detach_interrupt(uint8_t); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif + diff --git a/libmaple/gpio.c b/libmaple/gpio.c new file mode 100644 index 0000000..facb514 --- /dev/null +++ b/libmaple/gpio.c @@ -0,0 +1,55 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:35:49 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file gpio.c + * + * @brief GPIO initialization routine + */ + +#include "libmaple.h" +#include "stm32f10x_rcc.h" +#include "gpio.h" + +void gpio_init(void) { + /* Turn on clocks for GPIO */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | + RCC_APB2Periph_GPIOB | + RCC_APB2Periph_GPIOC | + RCC_APB2Periph_GPIOD | + RCC_APB2Periph_AFIO, + ENABLE); +} + +void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, uint8 mode) { + uint32_t tmp; + uint32_t shift = POS(gpio_pin % 8); + GPIOReg CR; + + ASSERT(port); + ASSERT(gpio_pin < 16); + + CR = (gpio_pin < 8) ? &(port->CRL) : &(port->CRH); + + tmp = *CR; + tmp &= POS_MASK(shift); + tmp |= mode << shift; + + *CR = tmp; +} diff --git a/libmaple/gpio.h b/libmaple/gpio.h new file mode 100644 index 0000000..5e7cf29 --- /dev/null +++ b/libmaple/gpio.h @@ -0,0 +1,97 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:36:01 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file gpio.h + * + * @brief GPIO prototypes, defines, and inlined access functions + */ + +#ifndef _GPIO_H +#define _GPIO_H + +/* Each of the GPIO port bits can be in the following modes (STM32 138/995): + * Input floating + * Input pull-up + * Input pull-down + * Analog Input + * Output open-drain + * Output push-pull + * Alternate function push-pull + * Alternate function open-drain + * + * - After reset, the alternate functions are not active and IO prts + * are set to Input Floating mode */ + +#define GPIOA_BASE (GPIO_Port*)0x40010800 +#define GPIOB_BASE (GPIO_Port*)0x40010C00 +#define GPIOC_BASE (GPIO_Port*)0x40011000 +#define GPIOD_BASE (GPIO_Port*)0x40011400 + +/* Pin modes are set by [CNFx[1:0] : MODEx[1:0]] */ +#define GPIO_SPEED_50MHZ (0x3) // Max output speed 50 MHz +#define GPIO_MODE_OUTPUT_PP ((0x00 << 2) | GPIO_SPEED_50MHZ) +#define GPIO_MODE_OUTPUT_OD ((0x01 << 2) | GPIO_SPEED_50MHZ) + +#define GPIO_MODE_AF_OUTPUT_PP ((0x02 << 2) | GPIO_SPEED_50MHZ) +#define GPIO_MODE_AF_OUTPUT_OD ((0x03 << 2) | GPIO_SPEED_50MHZ) + +/* Note: mode bits must be set to zero for input mode */ +#define GPIO_MODE_INPUT_ANALOG (0x00 << 2) +#define GPIO_MODE_INPUT_FLOATING (0x01 << 2) +#define GPIO_MODE_INPUT_PD (0x02 << 2) +#define GPIO_MODE_INPUT_PU (0x02 << 2) + +typedef struct { + volatile uint32 CRL; // Port configuration register low + volatile uint32 CRH; // Port configuration register high + volatile uint32 IDR; // Port input data register + volatile uint32 ODR; // Port output data register + volatile uint32 BSRR; // Port bit set/reset register + volatile uint32 BRR; // Port bit reset register + volatile uint32 LCKR; // Port configuration lock register +} GPIO_Port; + +typedef volatile uint32* GPIOReg; + +#define POS_MASK(shift) (~(0xF << shift)) +#define POS(val) (val << 2) + +#ifdef __cplusplus +extern "C"{ +#endif + +void gpio_init(void); +void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, uint8 mode); + +static inline void gpio_write_bit(GPIO_Port *port, uint8 gpio_pin, uint8 val) { + if (val){ + port->BSRR = BIT(gpio_pin); + } else { + port->BRR = BIT(gpio_pin); + } +} + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif + diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h new file mode 100644 index 0000000..dc9ffd2 --- /dev/null +++ b/libmaple/libmaple.h @@ -0,0 +1,33 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/19/09 02:37:22 EST + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file libmaple.h + * + * @brief general include file for libmaple + */ + +#ifndef _LIBMAPLE_H_ +#define _LIBMAPLE_H_ + +#include "libmaple_types.h" +#include "util.h" + +#endif + diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h new file mode 100644 index 0000000..b798587 --- /dev/null +++ b/libmaple/libmaple_types.h @@ -0,0 +1,42 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/19/09 02:35:14 EST + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file libmaple_types.h + * + * @brief libmaple types + */ + +#ifndef _LIBMAPLE_TYPES_H_ +#define _LIBMAPLE_TYPES_H_ + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef signed char int8; +typedef short int16; +typedef int int32; +typedef long long int64; + +typedef void (*voidFuncPtr)(void); + +#endif + diff --git a/libmaple/nvic.c b/libmaple/nvic.c new file mode 100644 index 0000000..9b8c84f --- /dev/null +++ b/libmaple/nvic.c @@ -0,0 +1,59 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:36:19 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file nvic.c + * + * @brief Nested interrupt controller routines + */ + +#include "libmaple.h" +#include "nvic.h" +#include "systick.h" + +void nvic_disable_interrupts(void) { + /* Turn off all interrupts */ + REG_SET(NVIC_ICER0, 0xFFFFFFFF); + REG_SET(NVIC_ICER1, 0xFFFFFFFF); + + /* Turn off systick exception */ + REG_CLEAR_BIT(SYSTICK_CSR, 0); +} + + +void nvic_set_vector_table(uint32_t *addr, uint32_t offset) { +// SCB->VTOR = NVIC_VectTab | (Offset & (u32)0x1FFFFF80); +} + + +/** + * @brief turn on interrupt number n + * @param[in] n interrupt number + */ +void nvic_enable_interrupt(uint32 n) { + if (n >= NVIC_NR_INTERRUPTS) { + return; + } + + if (n < 32) { + REG_SET_BIT(NVIC_ISER0, n); + } else { + REG_SET_BIT(NVIC_ISER1, n - 32); + } +} diff --git a/libmaple/nvic.h b/libmaple/nvic.h new file mode 100644 index 0000000..5908e9c --- /dev/null +++ b/libmaple/nvic.h @@ -0,0 +1,67 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:36:47 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file nvic.h + * + * @brief Nested interrupt controller defines and prototypes + */ + +#ifndef _NVIC_H_ +#define _NVIC_H_ + +#define NVIC_INT_USBHP 19 +#define NVIC_INT_USBLP 20 +#define NVIC_EXTI1_OFFSET (NVIC_ISER0 + 0x07) +#define NVIC_EXTI9_5_OFFSET (NVIC_ISER0 + 0x17) + +/* NVIC Interrupt Enable registers */ +#define NVIC_ISER0 0xE000E100 +#define NVIC_ISER1 0xE000E104 +#define NVIC_ISER2 0xE000E108 +#define NVIC_ISER3 0xE000E10C + +/* NVIC Interrupt Clear registers */ +#define NVIC_ICER0 0xE000E180 +#define NVIC_ICER1 0xE000E184 +#define NVIC_ICER2 0xE000E188 +#define NVIC_ICER3 0xE000E18C + +/* System control registers */ +#define SCB_VTOR 0xE000ED08 // Vector table offset register + +#define NVIC_VectTab_RAM ((u32)0x20000000) +#define NVIC_VectTab_FLASH ((u32)0x08000000) + +#define NVIC_NR_INTERRUPTS 60 + +#ifdef __cplusplus +extern "C"{ +#endif + +void nvic_disable_interrupts(void); +void nvic_enable_interrupt(uint32); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/libmaple/stm32f10x_conf.h b/libmaple/stm32f10x_conf.h new file mode 100644 index 0000000..ddd1833 --- /dev/null +++ b/libmaple/stm32f10x_conf.h @@ -0,0 +1,132 @@ +/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** +* File Name : stm32f10x_conf.h +* Author : MCD Application Team +* Version : V2.0.2 +* Date : 07/11/2008 +* Description : Library configuration file. +******************************************************************************** +* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F10x_CONF_H +#define __STM32F10x_CONF_H + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f10x_type.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Uncomment the line below to compile the library in DEBUG mode, this will expanse + the "assert_param" macro in the firmware library code (see "Exported macro" + section below) */ +/* #define DEBUG 1*/ + +/* Comment the line below to disable the specific peripheral inclusion */ +/************************************* ADC ************************************/ +//#define _ADC +//#define _ADC1 +//#define _ADC2 +//#define _ADC3 +//#define _BKP +//#define _CAN +//#define _CRC +//#define _DAC +//#define _DBGMCU +//#define _DMA +//#define _DMA1_Channel1 +//#define _DMA1_Channel2 +//#define _DMA1_Channel3 +//#define _DMA1_Channel4 +//#define _DMA1_Channel5 +//#define _DMA1_Channel6 +//#define _DMA1_Channel7 +//#define _DMA2_Channel1 +//#define _DMA2_Channel2 +//#define _DMA2_Channel3 +//#define _DMA2_Channel4 +//#define _DMA2_Channel5 +#define _EXTI +#define _FLASH + +/* Uncomment the line below to enable FLASH program/erase/protections functions, + otherwise only FLASH configuration (latency, prefetch, half cycle) functions + are enabled */ +/* #define _FLASH_PROG */ + +#if 0 +#define _FSMC +#define _GPIO +#define _GPIOA +#define _GPIOB +#define _GPIOC +#define _GPIOD +#define _GPIOE +#define _GPIOF +#define _GPIOG +#define _I2C +#define _I2C1 +#define _I2C2 +#define _IWDG +#define _PWR +#define _RTC +#define _SDIO +#define _SPI +#define _SPI1 +#define _SPI2 +#define _SPI3 +#define _SysTick +#define _TIM +#define _TIM1 +#define _TIM2 +#define _TIM3 +#define _TIM4 +#define _TIM5 +#define _TIM6 +#define _TIM7 +#define _TIM8 +#define _USART +#define _USART1 +#define _USART3 +#define _UART4 +#define _UART5 +#endif +#define _USART2 +#define _NVIC +#define _RCC +#define _AFIO + +/************************************* WWDG ***********************************/ +#define _WWDG + +/* In the following line adjust the value of External High Speed oscillator (HSE) + used in your application */ +#define HSE_Value ((u32)8000000) /* Value of the External oscillator in Hz*/ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef DEBUG +/******************************************************************************* +* Macro Name : assert_param +* Description : The assert_param macro is used for function's parameters check. +* It is used only if the library is compiled in DEBUG mode. +* Input : - expr: If expr is false, it calls assert_failed function +* which reports the name of the source file and the source +* line number of the call that failed. +* If expr is true, it returns no value. +* Return : None +*******************************************************************************/ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((u8 *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(u8* file, u32 line); +#else + #define assert_param(expr) ((void)0) +#endif /* DEBUG */ + +#endif /* __STM32F10x_CONF_H */ + +/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/libmaple/stm32f10x_it.c b/libmaple/stm32f10x_it.c new file mode 100644 index 0000000..70d3269 --- /dev/null +++ b/libmaple/stm32f10x_it.c @@ -0,0 +1,252 @@ +void NMIException(void) { +} +void HardFaultException(void) { + while (1) { + } +} + +void MemManageException(void) { + while (1) { + } +} + +void BusFaultException(void) { + while (1) { + } +} + +void UsageFaultException(void) { + while (1) { + } +} + +#if 0 +void DebugMonitor(void) { +} + +void SVCHandler(void) { +} + +void PendSVC(void) { +} + +void WWDG_IRQHandler(void) { +} + +void PVD_IRQHandler(void) { +} + +void TAMPER_IRQHandler(void) { +} + +void RTC_IRQHandler(void) { +} + +void FLASH_IRQHandler(void) { +} + +void RCC_IRQHandler(void) { +} + +void DMA1_Channel1_IRQHandler(void) { +} + +void DMA1_Channel2_IRQHandler(void) { +} + +void DMA1_Channel3_IRQHandler(void) { +} + +void DMA1_Channel4_IRQHandler(void) { +} + +void DMA1_Channel5_IRQHandler(void) { +} + +void DMA1_Channel6_IRQHandler(void) { +} + +void DMA1_Channel7_IRQHandler(void) { +} + +void ADC1_2_IRQHandler(void) { +} + +void USB_HP_CAN_TX_IRQHandler(void) { +} + +void USB_LP_CAN_RX0_IRQHandler(void) { +} + +void CAN_RX1_IRQHandler(void) { +} + +void CAN_SCE_IRQHandler(void) { +} + +void TIM1_BRK_IRQHandler(void) { +} + +void TIM1_UP_IRQHandler(void) { + while(1) { + } +} + +void TIM1_TRG_COM_IRQHandler(void) { +} + +void TIM1_CC_IRQHandler(void) { + while(1) + ; +} + +void TIM2_IRQHandler(void) { +} + +void TIM3_IRQHandler(void) { +} + +void TIM4_IRQHandler(void) { +} + +void I2C1_EV_IRQHandler(void) { +} + +void I2C1_ER_IRQHandler(void) { +} + +void I2C2_EV_IRQHandler(void) { +} + +void I2C2_ER_IRQHandler(void) { +} + +void SPI1_IRQHandler(void) { +} + +void SPI2_IRQHandler(void) { +} + +void USART1_IRQHandler(void) { +#if 0 + if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) + { + /* Read one byte from the receive data register */ + RxBuffer[RxCounter++] = (USART_ReceiveData(USART1) & 0x7F); + + if(RxCounter == NbrOfDataToRead) + { + /* Disable the USART Receive interrupt */ + USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); + } + } + + if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) + { + /* Write one byte to the transmit data register */ + USART_SendData(USART1, TxBuffer[TxCounter++]); + + if(TxCounter == NbrOfDataToTransfer) + { + /* Disable the USART1 Transmit interrupt */ + USART_ITConfig(USART1, USART_IT_TXE, DISABLE); + } + } +#endif +} + +void USART2_IRQHandler(void) { +#if 0 + if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) + { + /* Echo the character back */ + RxBuffer[0] = (USART_ReceiveData(USART2) & 0x7F); + USART_SendData(USART2, RxBuffer[0]); + // /* Read one byte from the receive data register */ + // RxBuffer[RxCounter++] = (USART_ReceiveData(USART2) & 0x7F); + + // if(RxCounter == NbrOfDataToRead) + // { + // /* Disable the USART Receive interrupt */ + // USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); + // } + } + +#endif + +#if 0 + if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET) + { + /* Write one byte to the transmit data register */ + USART_SendData(USART2, 'Y'); + TxCounter++; +// USART_SendData(USART2, TxBuffer[TxCounter++]); + + if(TxCounter == NbrOfDataToTransfer) { + /* Disable the USART1 Transmit interrupt */ + USART_ITConfig(USART2, USART_IT_TXE, DISABLE); + } + } +#endif +} + +void USART3_IRQHandler(void) { +} + +void RTCAlarm_IRQHandler(void) { +} + +void USBWakeUp_IRQHandler(void) { +} + +void TIM8_BRK_IRQHandler(void) { +} + +void TIM8_UP_IRQHandler(void) { +} + +void TIM8_TRG_COM_IRQHandler(void) { +} + +void TIM8_CC_IRQHandler(void) { +} + +void ADC3_IRQHandler(void) { +} + +void FSMC_IRQHandler(void) { +} + +void SDIO_IRQHandler(void) { +} + +void TIM5_IRQHandler(void) { +} + +void SPI3_IRQHandler(void) { +} + +void UART4_IRQHandler(void) { +} + +void UART5_IRQHandler(void) { +} + +void TIM6_IRQHandler(void) { +} + +void TIM7_IRQHandler(void) { +} + +void DMA2_Channel1_IRQHandler(void) { +} + +void DMA2_Channel2_IRQHandler(void) { +} + +void DMA2_Channel3_IRQHandler(void) { +} + +void DMA2_Channel4_5_IRQHandler(void) { +} +#endif diff --git a/libmaple/syscalls.c b/libmaple/syscalls.c new file mode 100644 index 0000000..390cecd --- /dev/null +++ b/libmaple/syscalls.c @@ -0,0 +1,157 @@ +#include "libmaple.h" +#include + +/* _end is set in the linker command file */ +extern caddr_t _end; + +/* just in case, most boards have at least some memory */ +#ifndef RAMSIZE +# define RAMSIZE (caddr_t)0x50000 +#endif + +#define STACK_TOP 0x20000800 + +void uart_send(const char*str); + +/* + * sbrk -- changes heap size size. Get nbytes more + * RAM. We just increment a pointer in what's + * left of memory on the board. + */ +caddr_t +_sbrk(nbytes) +int nbytes; +{ + static caddr_t heap_ptr = NULL; + caddr_t base; + + if (heap_ptr == NULL) { + heap_ptr = (caddr_t)&_end; + } + + if ((STACK_TOP - (unsigned int)heap_ptr) >= 0) { + base = heap_ptr; + heap_ptr += nbytes; + return (base); + } else { + uart_send("heap full!\r\n"); + return ((caddr_t)-1); + } +} + +int _open(const char *path, int flags, ...) +{ + return 1; +} + +int _close(int fd) +{ + return 0; +} + +int _fstat(int fd, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int fd) +{ + return 1; +} + +int isatty(int fd) +{ + return 1; +} + +int _lseek(int fd, off_t pos, int whence) +{ + return -1; +} + +unsigned char getch(void) +{ +// while (!(USART2->SR & USART_FLAG_RXNE)); +// return USART2->DR; + return 0; +} + + +int _read(int fd, char *buf, size_t cnt) +{ + *buf = getch(); + + return 1; +} + +void putch(unsigned char c) +{ +// if (c == '\n') putch('\r'); + +// while (!(USART2->SR & USART_FLAG_TXE)); +// USART2->DR = c; +} + +void cgets(char *s, int bufsize) +{ + char *p; + int c; + int i; + + for (i = 0; i < bufsize; i++) { + *(s+i) = 0; + } +// memset(s, 0, bufsize); + + p = s; + + for (p = s; p < s + bufsize-1;) + { + c = getch(); + switch (c) + { + case '\r' : + case '\n' : + putch('\r'); + putch('\n'); + *p = '\n'; + return; + + case '\b' : + if (p > s) + { + *p-- = 0; + putch('\b'); + putch(' '); + putch('\b'); + } + break; + + default : + putch(c); + *p++ = c; + break; + } + } + return; +} + +int _write(int fd, const char *buf, size_t cnt) +{ + int i; +// uart_send("_write\r\n"); + + for (i = 0; i < cnt; i++) + putch(buf[i]); + + return cnt; +} + +/* Override fgets() in newlib with a version that does line editing */ +char *fgets(char *s, int bufsize, void *f) +{ +// uart_send("fgets\r\n"); + cgets(s, bufsize); + return s; +} diff --git a/libmaple/systick.c b/libmaple/systick.c new file mode 100644 index 0000000..47be69e --- /dev/null +++ b/libmaple/systick.c @@ -0,0 +1,52 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:37:24 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file systick.c + * + * @brief System timer interrupt handler and initialization routines + */ + +#include "libmaple.h" +#include "systick.h" + +#define MILLIS_INC 1 + +volatile uint32_t systick_timer_millis = 0; + +void systick_init(void) { + /* Set the reload counter to tick every 1ms */ + REG_SET_MASK(SYSTICK_RELOAD, MAPLE_RELOAD_VAL); +// SYSTICK_RELOAD = MAPLE_RELOAD_VAL; + + /* Clock the system timer with the core clock + * and turn it on, interrrupt every 1ms to keep track of millis()*/ + REG_SET(SYSTICK_CSR, SYSTICK_SRC_HCLK | + SYSTICK_ENABLE | + SYSTICK_TICKINT); +// SYSTICK_CSR = SYSTICK_SRC_HCLK | +// SYSTICK_ENABLE | +// SYSTICK_TICKINT; +} + +void SysTickHandler(void) { + systick_timer_millis++; +} + + diff --git a/libmaple/systick.h b/libmaple/systick.h new file mode 100644 index 0000000..61789c4 --- /dev/null +++ b/libmaple/systick.h @@ -0,0 +1,62 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:37:37 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file systick.h + * + * @brief Various system timer definitions + */ + +#ifndef _SYSTICK_H_ +#define _SYSTICK_H_ + +#include "libmaple.h" + +/* To the ARM technical manual... there's nearly nothing on the systick + * timer in the stm32 manual */ + +#define SYSTICK_CSR 0xE000E010 // Control and status register +#define SYSTICK_RELOAD 0xE000E014 // Reload value register +#define SYSTICK_CNT 0xE000E018 // Current value register +#define SYSTICK_CALIB 0xE000E01C // Calibration value register + +#define SYSTICK_SRC_HCLK BIT(2) // Use core clock +#define SYSTICK_TICKINT BIT(1) // Interrupt on systick countdown +#define SYSTICK_ENABLE BIT(0) // Turn on the counter + +/* We use the systick timer to tick once + * every millisecond */ +#define MAPLE_RELOAD_VAL 72000 + +#ifdef __cplusplus +extern "C"{ +#endif + +void systick_init(void); + +static inline uint32_t systick_get_count(void) { + return (uint32_t)*(volatile uint32*)SYSTICK_CNT; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif + diff --git a/libmaple/timers.c b/libmaple/timers.c new file mode 100644 index 0000000..773ae36 --- /dev/null +++ b/libmaple/timers.c @@ -0,0 +1,192 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:37:54 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file timers.c + * + * @brief General timer routines + */ + +#include "libmaple.h" +#include "stm32f10x_rcc.h" +#include "timers.h" + +typedef struct { + volatile uint16_t CR1; + uint16_t RESERVED0; + volatile uint16_t CR2; + uint16_t RESERVED1; + volatile uint16_t SMCR; + uint16_t RESERVED2; + volatile uint16_t DIER; + uint16_t RESERVED3; + volatile uint16_t SR; + uint16_t RESERVED4; + volatile uint16_t EGR; + uint16_t RESERVED5; + volatile uint16_t CCMR1; + uint16_t RESERVED6; + volatile uint16_t CCMR2; + uint16_t RESERVED7; + volatile uint16_t CCER; + uint16_t RESERVED8; + volatile uint16_t CNT; + uint16_t RESERVED9; + volatile uint16_t PSC; + uint16_t RESERVED10; + volatile uint16_t ARR; + uint16_t RESERVED11; + volatile uint16_t RCR; + uint16_t RESERVED12; + volatile uint16_t CCR1; + uint16_t RESERVED13; + volatile uint16_t CCR2; + uint16_t RESERVED14; + volatile uint16_t CCR3; + uint16_t RESERVED15; + volatile uint16_t CCR4; + uint16_t RESERVED16; + volatile uint16_t BDTR; // Not used in general purpose timers + uint16_t RESERVED17; // Not used in general purpose timers + volatile uint16_t DCR; + uint16_t RESERVED18; + volatile uint16_t DMAR; + uint16_t RESERVED19; +} Timer; + +void timer_init(uint8_t timer_num, uint16_t prescale) { + Timer *timer; + uint32_t is_advanced = 0; + + ASSERT(timer_num > 0 && timer_num <= 4); + + switch(timer_num) { + case 1: + timer = (Timer*)TIMER1_BASE; + RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); + is_advanced = 1; + break; + case 2: + timer = (Timer*)TIMER2_BASE; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + break; + case 3: + timer = (Timer*)TIMER3_BASE; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); + break; + case 4: + timer = (Timer*)TIMER4_BASE; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); + break; + } + + timer->CR1 = ARPE; // No clock division + // Do not buffer auto-reload preload + // Edge aligned + // Upcounter + // Do not stop counter at update event + // Update events enabled (etc, see bits [1:2]) + // Counter disabled for now + + timer->PSC = prescale; // Prescaling by prescale (duh) + timer->ARR = 0xFFFF; // Max reload cont + + /* initialize all the channels to 50% duty cycle, + * TODO: none of them actually get output unless the gpio pin + * is set, this will probably consume a bit more power but + * 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) { + timer->BDTR = 0x8000; // moe enable + } + + timer->DIER = 0; // disable update interrupt + timer->EGR = 1; // Initialize update event and shadow registers + timer->CR1 |= 1; // Enable timer +} + +void timers_disable(void) { + Timer *timer; + int i; + Timer *timers[4] = { + (Timer*)TIMER1_BASE, + (Timer*)TIMER2_BASE, + (Timer*)TIMER3_BASE, + (Timer*)TIMER4_BASE, + }; + + for (i = 0; i < 4; i++) { + timer = timers[i]; + timer->CR1 = 0; + timer->CCER = 0; + } +} + +void timers_disable_channel(uint8 timer_num, uint8 channel) { + Timer *timer; + switch (timer_num) { + case 1: + timer = (Timer*)TIMER1_BASE; + break; + case 2: + timer = (Timer*)TIMER2_BASE; + break; + case 3: + timer = (Timer*)TIMER3_BASE; + break; + case 4: + timer = (Timer*)TIMER4_BASE; + break; + default: + ASSERT(0); + } + + switch (channel) { + case 1: + timer->CCER &= ~(0x1); + break; + case 2: + timer->CCER &= ~(0x10); + break; + case 3: + timer->CCER &= ~(0x100); + break; + case 4: + timer->CCER &= ~(0x1000); + break; + default: + ASSERT(0); + } +} diff --git a/libmaple/timers.h b/libmaple/timers.h new file mode 100644 index 0000000..18b0afb --- /dev/null +++ b/libmaple/timers.h @@ -0,0 +1,145 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:38:10 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file timers.h + * + * @brief Timer prototypes and various definitions + */ + +/* Note to self: + * The timer clock frequencies are automatically fixed by hardware. + * There are two cases: + * 1. if the APB prescaler is 1, the timer clock frequencies are + * set to the same frequency as that of the APB domain to which + * the timers are connected. + * 2. otherwise, they are set to twice (x2) the frequency of the + * APB domain to which the timers are connected. + * See stm32 manual, 77/995 + * + * hence, 72 mhz timers + * */ + +/* Maple Timer channels: + * Timer Maple Pin STM32 Pin Type + * TIM1_CH1 D6 PA8 Advanced + * TIM1_CH2 D7 PA9 Advanced + * TIM1_CH3 D8 PA10 Advanced + * + * TIM2_CH1 D2 PA0 + * TIM2_CH2 D3 PA1 + * TIM2_CH3 D1 PA2 + * TIM2_CH4 D0 PA3 + * + * TIM3_CH1 D12 PA6 + * TIM3_CH2 D11 PA7 + * TIM3_CH3 EXT7 PB0 + * TIM3_CH4 EXT8 PB1 + * + * TIM4_CH1 EXT5 PB6 + * TIM4_CH1 EXT9 PB7 + * TIM4_CH1 EXT15 PB8 + * TIM4_CH1 EXT4 PB9 + * + * Not supported: + * TIM1_CH4 USBDM, not available PA11 Advanced + * TIM1_CH1_N EXT12 PB13 + * TIM1_CH2_N EXT13 PB14 + * TIM1_CH3_N EXT14 PB15 + * */ + +/* I don't like the Arduino API for dealing with pin modes. + * How about... + * + * pinMode(digitalPin, PWM); + * pwmWrite(digitalPin) */ + + +#ifndef _TIMERS_H_ +#define _TIMERS_H_ +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +typedef volatile uint32_t* TimerCCR; + +#define TIMER1_BASE 0x40012C00 +#define TIMER2_BASE 0x40000000 +#define TIMER3_BASE 0x40000400 +#define TIMER4_BASE 0x40000800 + +#define ARPE BIT(7) // Auto-reload preload enable +#define NOT_A_TIMER 0 + +#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 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 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 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) + + +/* Turn on timer with prescale as the divisor + * void timer_init(uint32_t timer, uint16_t prescale) + * timer -> {1-4} + * prescale -> {1-65535} + * */ +void timer_init(uint8_t, uint16_t); +void timers_disable(void); +void timers_disable_channel(uint8, uint8); + +/* 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. + * + * void timer_pwm(uint8_t channel, uint8_t duty_cycle); + * channel -> {TIMERx_CHn_CCR} + * duty_cycle -> {0-65535} + * + * PRECONDITIONS: + * pin has been set to alternate function output + * timer has been initialized + */ +static inline void timer_pwm_write_ccr(TimerCCR CCR, uint16_t duty_cycle) { + *CCR = duty_cycle; +} + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif + diff --git a/libmaple/usart.c b/libmaple/usart.c new file mode 100644 index 0000000..9987641 --- /dev/null +++ b/libmaple/usart.c @@ -0,0 +1,345 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:38:26 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file usart.c + * + * @brief USART control routines + */ + +#include "libmaple.h" +#include "stm32f10x_rcc.h" +#include "usart.h" +#include "nvic.h" + +#define USART1_BASE 0x40013800 +#define USART2_BASE 0x40004400 +#define USART3_BASE 0x40004800 + +#define USART_UE BIT(13) +#define USART_M BIT(12) +#define USART_TE BIT(3) +#define USART_RE BIT(2) +#define USART_RXNEIE BIT(5) // read data register not empty interrupt enable +#define USART_TXE BIT(7) +#define USART_TC BIT(6) + +#define USART_STOP_BITS_1 BIT_MASK_SHIFT(0b0, 12) +#define USART_STOP_BITS_05 BIT_MASK_SHIFT(0b01, 12) +#define USART_STOP_BITS_2 BIT_MASK_SHIFT(0b02, 12) +#define USART_STOP_BITS_15 BIT_MASK_SHIFT(0b02, 12) + +#define USART1_CLK 72000000UL +#define USART2_CLK 36000000UL +#define USART3_CLK 36000000UL + +#define USART_RECV_BUF_SIZE 64 + +/* Ring buffer notes: + * The buffer is empty when head == tail. + * The buffer is full when the head is one byte in front of the tail + * The total buffer size must be a power of two + * Note, one byte is necessarily left free with this scheme */ +typedef struct usart_ring_buf { + uint32 head; + uint32 tail; + uint8 buf[USART_RECV_BUF_SIZE]; +} usart_ring_buf; + +static usart_ring_buf ring_buf1; +static usart_ring_buf ring_buf2; +static usart_ring_buf ring_buf3; + +typedef struct usart_port { + volatile uint32 SR; // Status register + volatile uint32 DR; // Data register + volatile uint32 BRR; // Baud rate register + volatile uint32 CR1; // Control register 1 + volatile uint32 CR2; // Control register 2 + volatile uint32 CR3; // Control register 3 + volatile uint32 GTPR; // Guard time and prescaler register +} usart_port; + +void USART1_IRQHandler(void) { + /* Read the data */ + ring_buf1.buf[ring_buf1.tail++] = (uint8_t)(((usart_port*)(USART1_BASE))->DR); + ring_buf1.tail %= USART_RECV_BUF_SIZE; +} + +/* Don't overrun your buffer, seriously */ +void USART2_IRQHandler(void) { + /* Read the data */ + ring_buf2.buf[ring_buf2.tail++] = (uint8_t)(((usart_port*)(USART2_BASE))->DR); + ring_buf2.tail %= USART_RECV_BUF_SIZE; +} +/* Don't overrun your buffer, seriously */ +void USART3_IRQHandler(void) { + /* Read the data */ + ring_buf3.buf[ring_buf3.tail++] = (uint8_t)(((usart_port*)(USART3_BASE))->DR); + ring_buf3.tail %= USART_RECV_BUF_SIZE; +} + +/** + * @brief Enable a USART in single buffer transmission mode, multibuffer + * receiver mode. + * + * @param usart_num USART to be initialized + * @param baud Baud rate to be set at + * @param recvBuf buf buffer for receiver + * @param len size of recvBuf + * + * @sideeffect Turns on the specified USART + */ +void usart_init(uint8 usart_num, uint32 baud) { + ASSERT((usart_num <= NR_USARTS) && (usart_num > 0)); + ASSERT(baud && (baud < USART_MAX_BAUD)); + + usart_port *port; + usart_ring_buf *ring_buf; + + uint32 clk_speed; + uint32 integer_part; + uint32 fractional_part; + uint32 tmp; + + switch (usart_num) { + case 1: + port = (usart_port*)USART1_BASE; + ring_buf = &ring_buf1; + clk_speed = USART1_CLK; + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); + REG_SET(NVIC_ISER1, BIT(5)); + break; + case 2: + port = (usart_port*)USART2_BASE; + ring_buf = &ring_buf2; + clk_speed = USART2_CLK; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); + REG_SET(NVIC_ISER1, BIT(6)); + break; + case 3: + port = (usart_port*)USART3_BASE; + ring_buf = &ring_buf3; + clk_speed = USART3_CLK; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); + REG_SET(NVIC_ISER1, BIT(7)); + break; + default: + /* should never get here */ + ASSERT(0); + } + + /* Initialize ring buffer */ + ring_buf->head = 0; + ring_buf->tail = 0; + + /* Set baud rate */ + integer_part = ((25 * clk_speed) / (4 * baud)); + tmp = (integer_part / 100) << 4; + + fractional_part = integer_part - (100 * (tmp >> 4)); + tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F); + + port->BRR = (uint16_t)tmp; + + port->CR1 = USART_TE | // transmitter enable + USART_RE | // receiver enable + USART_RXNEIE; // receive interrupt enable + + + /* Enable the USART and set mode to 8n1 */ + port->CR1 |= USART_UE; +} + + +/** + * @brief Turn off a USART. + * + * @param USART to be disabled + * + * @sideeffect Turns off the specified USART + */ +void usart_disable(uint8 usart_num) { + ASSERT((usart_num <= NR_USARTS) && (usart_num > 0)); + usart_port *port; + + switch (usart_num) { + case 1: + port = (usart_port*)USART1_BASE; + break; + case 2: + port = (usart_port*)USART2_BASE; + break; + case 3: + port = (usart_port*)USART3_BASE; + break; + default: + /* should never get here */ + ASSERT(0); + } + + /* Is this usart enabled? */ + if (!(port->SR & USART_UE)) + return; + + /* TC bit must be high before disabling the usart */ + while ((port->SR & USART_TC) == 0) + ; + + /* Disable UE */ + port->CR1 = 0; +} + + +/** + * @brief Print a null terminated string to the specified USART + * + * @param[in] usart_num USART to send on + * @param[in] str String to send + */ +void usart_putstr(uint8 usart_num, const char* str) { + ASSERT((usart_num <= NR_USARTS) && (usart_num > 0)); + char ch; + + while((ch = *(str++)) != '\0') { + usart_putc(usart_num, ch); + } +} + +/** + * @brief Print an unsigned integer to the specified usart + * + * @param[in] usart_num usart to send on + * @param[in] val number to print + */ +void usart_putudec(uint8 usart_num, uint32 val) { + ASSERT((usart_num <= NR_USARTS) && (usart_num > 0)); + char digits[12]; + int i; + + i = 0; + do { + digits[i++] = val % 10 + '0'; + val /= 10; + } while (val > 0); + while (--i >= 0) { + usart_putc(usart_num, digits[i]); + } + +} + + +/** + * @brief Return one character from the receive buffer. Assumes + * that there is data available. + * + * @param[in] usart_num number of the usart to read from + * + * @return character from ring buffer + * + * @sideeffect may update the head pointer of the recv buffer + */ +uint8 usart_getc(uint8 usart_num) { + uint8 ch; + usart_ring_buf *rb; + + switch (usart_num) { + case 1: + rb = &ring_buf1; + break; + case 2: + rb = &ring_buf2; + break; + case 3: + rb = &ring_buf3; + break; + default: + ASSERT(0); + } + + /* Make sure there's actually data to be read */ + ASSERT(rb->head != rb->tail); + + /* Read the data and check for wraparound */ + ch = rb->buf[rb->head++]; + rb->head %= USART_RECV_BUF_SIZE; + + return ch; +} + +uint32 usart_data_available(uint8 usart_num) { + usart_ring_buf *rb; + + switch (usart_num) { + case 1: + rb = &ring_buf1; + break; + case 2: + rb = &ring_buf2; + break; + case 3: + rb = &ring_buf3; + break; + default: + ASSERT(0); + } + + return rb->tail - rb->head; +} + + + +/** + * @brief Output a byte out the uart + * + * @param[in] usart_num usart number to output on + * @param[in] byte byte to send + * + */ +void usart_putc(uint8 usart_num, uint8 byte) { + ASSERT((usart_num <= NR_USARTS) && (usart_num > 0)); + usart_port *port; + + switch (usart_num) { + case 1: + port = (usart_port*)USART1_BASE; + break; + case 2: + port = (usart_port*)USART2_BASE; + break; + case 3: + port = (usart_port*)USART3_BASE; + break; + default: + /* Should never get here */ + ASSERT(0); + } + +// if (ch == '\n') { +// usart_putc(usart_num, '\r'); +// } + + port->DR = byte; + + /* Wait for transmission to complete */ + while ((port->SR & USART_TXE) == 0) + ; +} + + diff --git a/libmaple/usart.h b/libmaple/usart.h new file mode 100644 index 0000000..b9efdd5 --- /dev/null +++ b/libmaple/usart.h @@ -0,0 +1,53 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:38:35 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file usart.h + * + * @brief USART Definitions + */ + +#ifndef _USART_H_ +#define _USART_H_ + +#define NR_USARTS 0x3 + +#ifdef __cplusplus +extern "C"{ +#endif + +#define USART_MAX_BAUD 225000 + +void usart_init(uint8 usart_num, uint32 baud); +void usart_disable(uint8 usart_num); + +void usart_putstr(uint8 usart_num, const char*); +void usart_putudec(uint8 usart_num, uint32 val); +void usart_putc(uint8 usart_num, uint8 ch); + +uint32 usart_data_available(uint8 usart_num); +uint8 usart_getc(uint8 usart_num); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif + diff --git a/libmaple/usb.c b/libmaple/usb.c new file mode 100644 index 0000000..8c312f8 --- /dev/null +++ b/libmaple/usb.c @@ -0,0 +1,83 @@ +#include +#include "usb.h" + +void usb_lpIRQHandler(void) +{ + typedef void (*funcPtr)(void); + + const uint32_t usbIsrAddr = *(uint32_t*)(USB_ISR_ADDR); + void (*ptrToUsbISR)(void) = (funcPtr) usbIsrAddr; + ptrToUsbISR(); +} + +void usb_userToPMABufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes) +{ + u32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ + u32 i, temp1, temp2; + u16 *pdwVal; + pdwVal = (u16 *)(wPMABufAddr * 2 + PMAAddr); + for (i = n; i != 0; i--) + { + temp1 = (u16) * pbUsrBuf; + pbUsrBuf++; + temp2 = temp1 | (u16) * pbUsrBuf << 8; + *pdwVal++ = temp2; + pdwVal++; + pbUsrBuf++; + } +} + +void usb_PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes) +{ + u32 n = (wNBytes + 1) >> 1;/* /2*/ + u32 i; + u32 *pdwVal; + pdwVal = (u32 *)(wPMABufAddr * 2 + PMAAddr); + for (i = n; i != 0; i--) + { + *(u16*)pbUsrBuf++ = *pdwVal++; + pbUsrBuf++; + } +} + +void usb_serialWriteStr(const char* outStr) { + u8 offset=0; + BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE); + + while ((outStr[offset] != '\0') + && (offset < USB_SERIAL_BUF_SIZE)) { + offset++; + } + + delay(offset*1); + + bootVector->serial_count_in = (u32*) &offset; + usb_userToPMABufferCopy((u8*)outStr,USB_SERIAL_ENDP_TXADDR,offset); + _SetEPTxCount(USB_SERIAL_ENDP_TX,offset); + _SetEPTxValid(USB_SERIAL_ENDP_TX); + +} + +void usb_serialWriteChar(unsigned char ch) { + BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE); + + delay(1); + + *(bootVector->serial_count_in) = 1; + usb_userToPMABufferCopy((u8*)(&ch),USB_SERIAL_ENDP_TXADDR,1); + _SetEPTxCount(USB_SERIAL_ENDP_TX,1); + _SetEPTxValid(USB_SERIAL_ENDP_TX); + +} + +uint8_t usb_serialGetRecvLen() { + uint8_t count_out =_GetEPRxCount(USB_SERIAL_ENDP_RX); + return count_out; +} + +void usb_copyRecvBuffer(unsigned char* dest, uint8_t len) { + ASSERT(len < USB_SERIAL_BUF_SIZE); + usb_PMAToUserBufferCopy((u8*)(dest),USB_SERIAL_ENDP_RXADDR,len); + _SetEPRxValid(USB_SERIAL_ENDP_RX); +} + diff --git a/libmaple/usb.h b/libmaple/usb.h new file mode 100644 index 0000000..3b7a971 --- /dev/null +++ b/libmaple/usb.h @@ -0,0 +1,32 @@ +#ifndef _USB_H_ +#define _USB_H_ + +#include +#include "util.h" +#include "cortexm3_macro.h" +#include "usb_regs.h" +#include "bootVect.h" + +#define USB_ISR_ADDR (0x08000090) +#define USB_SERIAL_ENDP_TXADDR ((uint32_t) 0xC0) +#define USB_SERIAL_ENDP_RXADDR ((uint32_t) 0x110) +#define USB_SERIAL_ENDP_TX ((uint16_t) 0x1) +#define USB_SERIAL_ENDP_RX ((uint16_t) 0x3) +#define USB_SERIAL_BUF_SIZE (0x40) + +#ifdef __cplusplus +extern "C" { +#endif + +void usb_lpIRQHandler(void); +void usb_userToPMABufferCopy(u8 *pbUsrBuf,u16 wPMABufAddr,u16 wNBytes); +void usb_PMAToUserBufferCopy(u8 *pbUsrBuf,u16 wPMABufAddr,u16 wNBytes); +void usb_serialWriteStr(const char *outStr); +void usb_serialWriteChar(unsigned char ch); +uint8_t usb_serialGetRecvLen(); +void usb_copyRecvBuffer(unsigned char* dest, uint8_t len); + +#ifdef __cplusplus +} // extern "C" +#endif +#endif //_USB_H diff --git a/libmaple/usb_regs.h b/libmaple/usb_regs.h new file mode 100644 index 0000000..135d645 --- /dev/null +++ b/libmaple/usb_regs.h @@ -0,0 +1,555 @@ +/******************** (C) COPYRIGHT 2008 STMicroelectronics ******************** +* File Name : usb_regs.h +* Author : MCD Application Team +* Version : V2.2.1 +* Date : 09/22/2008 +* Description : Interface prototype functions to USB cell registers +******************************************************************************** +* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_REGS_H +#define __USB_REGS_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +#include "stm32f10x_type.h" + +typedef enum _EP_DBUF_DIR +{ + /* double buffered endpoint direction */ + EP_DBUF_ERR, + EP_DBUF_OUT, + EP_DBUF_IN +}EP_DBUF_DIR; + +/* endpoint buffer number */ +enum EP_BUF_NUM +{ + EP_NOBUF, + EP_BUF0, + EP_BUF1 +}; + +/* Exported constants --------------------------------------------------------*/ +#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */ +#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */ + +/******************************************************************************/ +/* General registers */ +/******************************************************************************/ + +/* Control register */ +#define CNTR ((volatile unsigned *)(RegBase + 0x40)) +/* Interrupt status register */ +#define ISTR ((volatile unsigned *)(RegBase + 0x44)) +/* Frame number register */ +#define FNR ((volatile unsigned *)(RegBase + 0x48)) +/* Device address register */ +#define DADDR ((volatile unsigned *)(RegBase + 0x4C)) +/* Buffer Table address register */ +#define BTABLE ((volatile unsigned *)(RegBase + 0x50)) +/******************************************************************************/ +/* Endpoint registers */ +/******************************************************************************/ +#define EP0REG ((volatile unsigned *)(RegBase)) /* endpoint 0 register address */ + +/* endpoints enumeration */ +#define ENDP0 ((u8)0) +#define ENDP1 ((u8)1) +#define ENDP2 ((u8)2) +#define ENDP3 ((u8)3) +#define ENDP4 ((u8)4) +#define ENDP5 ((u8)5) +#define ENDP6 ((u8)6) +#define ENDP7 ((u8)7) +/******************************************************************************/ +/* ISTR interrupt events */ +/******************************************************************************/ +#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ +#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ +#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ +#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ +#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ +#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ +#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ +#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ + + +#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ +#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ + +#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ +#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ +#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ +#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ +#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ +#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ +#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ +#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ + +/******************************************************************************/ +/* CNTR control register bits definitions */ +/******************************************************************************/ +#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ +#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ +#define CNTR_ERRM (0x2000) /* ERRor Mask */ +#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ +#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ +#define CNTR_RESETM (0x0400) /* RESET Mask */ +#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ +#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ + + +#define CNTR_RESUME (0x0010) /* RESUME request */ +#define CNTR_FSUSP (0x0008) /* Force SUSPend */ +#define CNTR_LPMODE (0x0004) /* Low-power MODE */ +#define CNTR_PDWN (0x0002) /* Power DoWN */ +#define CNTR_FRES (0x0001) /* Force USB RESet */ + +/******************************************************************************/ +/* FNR Frame Number Register bit definitions */ +/******************************************************************************/ +#define FNR_RXDP (0x8000) /* status of D+ data line */ +#define FNR_RXDM (0x4000) /* status of D- data line */ +#define FNR_LCK (0x2000) /* LoCKed */ +#define FNR_LSOF (0x1800) /* Lost SOF */ +#define FNR_FN (0x07FF) /* Frame Number */ +/******************************************************************************/ +/* DADDR Device ADDRess bit definitions */ +/******************************************************************************/ +#define DADDR_EF (0x80) +#define DADDR_ADD (0x7F) +/******************************************************************************/ +/* Endpoint register */ +/******************************************************************************/ +/* bit positions */ +#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ +#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ +#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ +#define EP_SETUP (0x0800) /* EndPoint SETUP */ +#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ +#define EP_KIND (0x0100) /* EndPoint KIND */ +#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ +#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ +#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ +#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ + +/* EndPoint REGister MASK (no toggle fields) */ +#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) + +/* EP_TYPE[1:0] EndPoint TYPE */ +#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */ +#define EP_BULK (0x0000) /* EndPoint BULK */ +#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ +#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ +#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ +#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK) + + +/* EP_KIND EndPoint KIND */ +#define EPKIND_MASK (~EP_KIND & EPREG_MASK) + +/* STAT_TX[1:0] STATus for TX transfer */ +#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ +#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ +#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ +#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ +#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ +#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ +#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK) + +/* STAT_RX[1:0] STATus for RX transfer */ +#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ +#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ +#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ +#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ +#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK) +/* Exported macro ------------------------------------------------------------*/ +/* SetCNTR */ +#define _SetCNTR(wRegValue) (*CNTR = (u16)wRegValue) + +/* SetISTR */ +#define _SetISTR(wRegValue) (*ISTR = (u16)wRegValue) + +/* SetDADDR */ +#define _SetDADDR(wRegValue) (*DADDR = (u16)wRegValue) + +/* SetBTABLE */ +#define _SetBTABLE(wRegValue)(*BTABLE = (u16)(wRegValue & 0xFFF8)) + +/* GetCNTR */ +#define _GetCNTR() ((u16) *CNTR) + +/* GetISTR */ +#define _GetISTR() ((u16) *ISTR) + +/* GetFNR */ +#define _GetFNR() ((u16) *FNR) + +/* GetDADDR */ +#define _GetDADDR() ((u16) *DADDR) + +/* GetBTABLE */ +#define _GetBTABLE() ((u16) *BTABLE) + +/* SetENDPOINT */ +#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \ + (u16)wRegValue) + +/* GetENDPOINT */ +#define _GetENDPOINT(bEpNum) ((u16)(*(EP0REG + bEpNum))) + +/******************************************************************************* +* Macro Name : SetEPType +* Description : sets the type in the endpoint register(bits EP_TYPE[1:0]) +* Input : bEpNum: Endpoint Number. +* wType +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\ + ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType))) + +/******************************************************************************* +* Macro Name : GetEPType +* Description : gets the type in the endpoint register(bits EP_TYPE[1:0]) +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Type +*******************************************************************************/ +#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD) + +/******************************************************************************* +* Macro Name : SetEPTxStatus +* Description : sets the status for tx transfer (bits STAT_TX[1:0]). +* Input : bEpNum: Endpoint Number. +* wState: new state +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxStatus(bEpNum,wState) {\ + register u16 _wRegVal; \ + _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\ + /* toggle first bit ? */ \ + if((EPTX_DTOG1 & wState)!= 0) \ + _wRegVal ^= EPTX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPTX_DTOG2 & wState)!= 0) \ + _wRegVal ^= EPTX_DTOG2; \ + _SetENDPOINT(bEpNum, _wRegVal); \ + } /* _SetEPTxStatus */ + +/******************************************************************************* +* Macro Name : SetEPRxStatus +* Description : sets the status for rx transfer (bits STAT_TX[1:0]) +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPRxStatus(bEpNum,wState) {\ + register u16 _wRegVal; \ + \ + _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\ + /* toggle first bit ? */ \ + if((EPRX_DTOG1 & wState)!= 0) \ + _wRegVal ^= EPRX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPRX_DTOG2 & wState)!= 0) \ + _wRegVal ^= EPRX_DTOG2; \ + _SetENDPOINT(bEpNum, _wRegVal); \ + } /* _SetEPRxStatus */ +/******************************************************************************* +* Macro Name : GetEPTxStatus / GetEPRxStatus +* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0] +* /STAT_RX[1:0]) +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : status . +*******************************************************************************/ +#define _GetEPTxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPTX_STAT) + +#define _GetEPRxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPRX_STAT) + +/******************************************************************************* +* Macro Name : SetEPTxValid / SetEPRxValid +* Description : sets directly the VALID tx/rx-status into the enpoint register +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID)) + +#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID)) + +/******************************************************************************* +* Macro Name : GetTxStallStatus / GetRxStallStatus. +* Description : checks stall condition in an endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : TRUE = endpoint in stall condition. +*******************************************************************************/ +#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \ + == EP_TX_STALL) +#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \ + == EP_RX_STALL) + +/******************************************************************************* +* Macro Name : SetEP_KIND / ClearEP_KIND. +* Description : set & clear EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ + (_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK)) +#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ + (_GetENDPOINT(bEpNum) & EPKIND_MASK))) + +/******************************************************************************* +* Macro Name : Set_Status_Out / Clear_Status_Out. +* Description : Sets/clears directly STATUS_OUT bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum) +#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum) + +/******************************************************************************* +* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff. +* Description : Sets/clears directly EP_KIND bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum) +#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum) + +/******************************************************************************* +* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX. +* Description : Clears bit CTR_RX / CTR_TX in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK)) +#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK)) + +/******************************************************************************* +* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX . +* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \ + EP_DTOG_RX | _GetENDPOINT(bEpNum) & EPREG_MASK)) +#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \ + EP_DTOG_TX | _GetENDPOINT(bEpNum) & EPREG_MASK)) + +/******************************************************************************* +* Macro Name : ClearDTOG_RX / ClearDTOG_TX. +* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\ + _ToggleDTOG_RX(bEpNum) +#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\ + _ToggleDTOG_TX(bEpNum) +/******************************************************************************* +* Macro Name : SetEPAddress. +* Description : Sets address in an endpoint register. +* Input : bEpNum: Endpoint Number. +* bAddr: Address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & EPREG_MASK | bAddr) + +/******************************************************************************* +* Macro Name : GetEPAddress. +* Description : Gets address in an endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPAddress(bEpNum) ((u8)(_GetENDPOINT(bEpNum) & EPADDR_FIELD)) + +#define _pEPTxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) +#define _pEPTxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) +#define _pEPRxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) +#define _pEPRxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) + +/******************************************************************************* +* Macro Name : SetEPTxAddr / SetEPRxAddr. +* Description : sets address of the tx/rx buffer. +* Input : bEpNum: Endpoint Number. +* wAddr: address to be set (must be word aligned). +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1)) +#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1)) + +/******************************************************************************* +* Macro Name : GetEPTxAddr / GetEPRxAddr. +* Description : Gets address of the tx/rx buffer. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : address of the buffer. +*******************************************************************************/ +#define _GetEPTxAddr(bEpNum) ((u16)*_pEPTxAddr(bEpNum)) +#define _GetEPRxAddr(bEpNum) ((u16)*_pEPRxAddr(bEpNum)) + +/******************************************************************************* +* Macro Name : SetEPCountRxReg. +* Description : Sets counter of rx buffer with no. of blocks. +* Input : pdwReg: pointer to counter. +* wCount: Counter. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _BlocksOf32(dwReg,wCount,wNBlocks) {\ + wNBlocks = wCount >> 5;\ + if((wCount & 0x1f) == 0)\ + wNBlocks--;\ + *pdwReg = (u32)((wNBlocks << 10) | 0x8000);\ + }/* _BlocksOf32 */ + +#define _BlocksOf2(dwReg,wCount,wNBlocks) {\ + wNBlocks = wCount >> 1;\ + if((wCount & 0x1) != 0)\ + wNBlocks++;\ + *pdwReg = (u32)(wNBlocks << 10);\ + }/* _BlocksOf2 */ + +#define _SetEPCountRxReg(dwReg,wCount) {\ + u16 wNBlocks;\ + if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\ + else {_BlocksOf2(dwReg,wCount,wNBlocks);}\ + }/* _SetEPCountRxReg */ + + + +#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\ + u32 *pdwReg = _pEPTxCount(bEpNum); \ + _SetEPCountRxReg(pdwReg, wCount);\ + } +/******************************************************************************* +* Macro Name : SetEPTxCount / SetEPRxCount. +* Description : sets counter for the tx/rx buffer. +* Input : bEpNum: endpoint number. +* wCount: Counter value. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount) +#define _SetEPRxCount(bEpNum,wCount) {\ + u32 *pdwReg = _pEPRxCount(bEpNum); \ + _SetEPCountRxReg(pdwReg, wCount);\ + } +/******************************************************************************* +* Macro Name : GetEPTxCount / GetEPRxCount. +* Description : gets counter of the tx buffer. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : Counter value. +*******************************************************************************/ +#define _GetEPTxCount(bEpNum)((u16)(*_pEPTxCount(bEpNum)) & 0x3ff) +#define _GetEPRxCount(bEpNum)((u16)(*_pEPRxCount(bEpNum)) & 0x3ff) + +/******************************************************************************* +* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr. +* Description : Sets buffer 0/1 address in a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : wBuf0Addr: buffer 0 address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);} +#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);} + +/******************************************************************************* +* Macro Name : SetEPDblBuffAddr. +* Description : Sets addresses in a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : wBuf0Addr: buffer 0 address. +* : wBuf1Addr = buffer 1 address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \ + _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\ + _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\ + } /* _SetEPDblBuffAddr */ + +/******************************************************************************* +* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr. +* Description : Gets buffer 0/1 address of a double buffer endpoint. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum)) +#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum)) + +/******************************************************************************* +* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count. +* Description : Gets buffer 0/1 address of a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : bDir: endpoint dir EP_DBUF_OUT = OUT +* EP_DBUF_IN = IN +* : wCount: Counter value +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \ + if(bDir == EP_DBUF_OUT)\ + /* OUT endpoint */ \ + {_SetEPRxDblBuf0Count(bEpNum,wCount);} \ + else if(bDir == EP_DBUF_IN)\ + /* IN endpoint */ \ + *_pEPTxCount(bEpNum) = (u32)wCount; \ + } /* SetEPDblBuf0Count*/ + +#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \ + if(bDir == EP_DBUF_OUT)\ + /* OUT endpoint */ \ + {_SetEPRxCount(bEpNum,wCount);}\ + else if(bDir == EP_DBUF_IN)\ + /* IN endpoint */\ + *_pEPRxCount(bEpNum) = (u32)wCount; \ + } /* SetEPDblBuf1Count */ + +#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\ + _SetEPDblBuf0Count(bEpNum, bDir, wCount); \ + _SetEPDblBuf1Count(bEpNum, bDir, wCount); \ + } /* _SetEPDblBuffCount */ + +/******************************************************************************* +* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count. +* Description : Gets buffer 0/1 rx/tx counter for double buffering. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum)) +#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum)) + +#endif +/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/ diff --git a/libmaple/util.c b/libmaple/util.c new file mode 100644 index 0000000..d323611 --- /dev/null +++ b/libmaple/util.c @@ -0,0 +1,103 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:38:44 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file util.h + * + * @brief Utility procedures for debugging, mostly an error LED fade and + * messages dumped over a uart for failed asserts. + */ + +#include "libmaple.h" +#include "usart.h" +#include "gpio.h" +#include "nvic.h" +#include "adc.h" +#include "timers.h" + +#define ERROR_LED_PORT GPIOA_BASE +#define ERROR_LED_PIN 5 +#define ERROR_USART_NUM 2 +#define ERROR_USART_BAUD 9600 +#define ERROR_TX_PIN 2 +#define ERROR_TX_PORT GPIOA_BASE + +/* Error assert + fade */ +void _fail(const char* file, int line, const char* exp) { + int32_t slope = 1; + int32_t CC = 0x0000; + int32_t TOP_CNT = 0x02FF; + int32_t i = 0; + + /* Turn off interrupts */ + nvic_disable_interrupts(); + + /* Turn off timers */ + timers_disable(); + + /* Turn off ADC */ + adc_disable(); + + /* Turn off all usarts */ + usart_disable(1); + usart_disable(2); + usart_disable(3); + + /* Initialize the error usart */ + gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_MODE_AF_OUTPUT_PP); + usart_init(ERROR_USART_NUM, ERROR_USART_BAUD); + + /* Print failed assert message */ + usart_putstr(ERROR_USART_NUM, "ERROR: FAILED ASSERT("); + usart_putstr(ERROR_USART_NUM, exp); + usart_putstr(ERROR_USART_NUM, "): "); + usart_putstr(ERROR_USART_NUM, file); + usart_putstr(ERROR_USART_NUM, ": "); + usart_putudec(ERROR_USART_NUM, line); + usart_putc(ERROR_USART_NUM, '\n'); + + /* Turn on the error LED */ + gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT_PP); + + /* Turn the USB interrupt back on so the bootloader keeps on functioning */ + nvic_enable_interrupt(NVIC_INT_USBHP); + nvic_enable_interrupt(NVIC_INT_USBLP); + + /* Error fade */ + while (1) { + if (CC == TOP_CNT) { + slope = -1; + } else if (CC == 0) { + slope = 1; + } + + if (i == TOP_CNT) { + CC += slope; + i = 0; + } + + if (i < CC) { + gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1); + } else { + gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0); + } + i++; + } +} + diff --git a/libmaple/util.h b/libmaple/util.h new file mode 100644 index 0000000..e425cc0 --- /dev/null +++ b/libmaple/util.h @@ -0,0 +1,82 @@ +/* ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Created: 12/18/09 02:39:27 + * Copyright (c) 2009 Perry L. Hung. All rights reserved. + * + * ****************************************************************************/ + +/** + * @file util.h + * + * @brief Various macros and utility procedures. + */ + +/* Generally "useful" utility procedures */ +#ifndef _UTIL_H_ +#define _UTIL_H_ +#include + +#define MAPLE_DEBUG 1 + +#define BIT(shift) (1 << (shift)) +#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) + +/* Return bits m to n of x */ +#define GET_BITS(x, m, n) ((((uint32_t)x) << (31 - (n))) >> ((31 - (n)) + (m))) + +/* Bit-banding macros */ +#define BITBAND_SRAM_REF 0x20000000 +#define BITBAND_SRAM_BASE 0x22000000 +#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) // Convert SRAM address +#define BITBAND_PERI_REF 0x40000000 +#define BITBAND_PERI_BASE 0x42000000 +#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32 + (b*4))) // Convert PERI address + +#define COUNTFLAG *((volatile unsigned char*) (BITBAND_PERI(SYSTICK_CSR,2))) + +#define REG_SET(reg, val) (*(volatile uint32_t*)(reg) = (val)) +#define REG_SET_BIT(reg, bit) (*(volatile uint32_t*)(reg) |= BIT(bit)) +#define REG_CLEAR_BIT(reg, bit) (*(volatile uint32_t*)(reg) &= ~BIT(bit)) +#define REG_SET_MASK(reg, mask) (*(volatile uint32_t*)(reg) |= (uint32_t)(mask)) +#define REG_CLEAR_MASK(reg, mask) (*(volatile uint32_t*)(reg) &= (uint32_t)~(mask)) + +#define REG_GET(reg) *(volatile uint32_t*)(reg) + + +#ifdef __cplusplus +extern "C"{ +#endif + +void _fail(const char*, int, const char*); + +#ifdef __cplusplus +} // extern "C" +#endif + + +/* Assert for sanity checks, undefine MAPLE_DEBUG to compile + * out these checks */ +#if MAPLE_DEBUG +#define ASSERT(exp) \ + if (exp) \ + {} \ + else \ + _fail(__FILE__, __LINE__, #exp) +#else +#define ASSERT(exp) (void)((0)) +#endif + +#endif + -- cgit v1.2.3