From c58c7dbe188509addf817dc208a234ddca6042fe Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Wed, 4 Aug 2010 04:38:58 -0400 Subject: New usart implementation: Fixed a bug where the maximum baud rate was incorrectly set to 225000 General cleanup Use new rcc and nvic APIs --- libmaple/nvic.h | 10 +- libmaple/ring_buffer.h | 57 +++++++++ libmaple/usart.c | 281 ++++++----------------------------------- libmaple/usart.h | 88 +++++++++++-- libmaple/util.h | 2 + wirish/comm/HardwareSerial.cpp | 88 +++++-------- wirish/comm/HardwareSerial.h | 17 ++- 7 files changed, 235 insertions(+), 308 deletions(-) create mode 100644 libmaple/ring_buffer.h diff --git a/libmaple/nvic.h b/libmaple/nvic.h index 8f18e4d..6cad48d 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -62,10 +62,16 @@ extern "C"{ #endif +enum { + NVIC_USART1 = 37, + NVIC_USART2 = 38, + NVIC_USART3 = 39, +}; + void nvic_init(void); void nvic_disable_interrupts(void); -void nvic_enable_interrupt(uint32); -void nvic_disable_interrupt(uint32); +void nvic_enable_interrupt(uint32 device); +void nvic_disable_interrupt(uint32 device); #ifdef __cplusplus } diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h new file mode 100644 index 0000000..95b9dd8 --- /dev/null +++ b/libmaple/ring_buffer.h @@ -0,0 +1,57 @@ +/** + * @brief simple circular buffer + */ + +#ifndef _RING_BUFFER_H_ +#define _RING_BUFFER_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* 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 + * One byte is left free to distinguish empty from full */ +typedef struct ring_buffer { + uint32 head; + uint32 tail; + uint8 size; + uint8 *buf; +} ring_buffer; + +static inline void rb_init(ring_buffer *rb, uint8 size, uint8 *buf) { + ASSERT(IS_POWER_OF_TWO(size)); + rb->head = 0; + rb->tail = 0; + rb->size = size; + rb->buf = buf; +} + +static inline void rb_insert(ring_buffer *rb, uint8 element) { + rb->buf[(rb->tail)++] = element; + rb->tail &= (rb->size - 1); +} + +static inline uint8 rb_remove(ring_buffer *rb) { + uint8 ch = rb->buf[rb->head++]; + rb->head &= (rb->size - 1); + return ch; +} + +static inline uint32 rb_full_count(ring_buffer *rb) { + return rb->tail - rb->head; +} + +static inline void rb_reset(ring_buffer *rb) { + rb->tail = rb->head; +} + +#ifdef __cplusplus +} // extern "C" +#endif + + + +#endif + diff --git a/libmaple/usart.c b/libmaple/usart.c index 2a587f3..53a6150 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -42,117 +42,66 @@ #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; - +/* usart descriptor table */ +struct usart_dev usart_dev_table[] = { + [USART1] = { + .base = (usart_port*)USART1_BASE, + .rcc_dev_num = RCC_USART1, + .nvic_dev_num = NVIC_USART1 + }, + [USART2] = { + .base = (usart_port*)USART2_BASE, + .rcc_dev_num = RCC_USART2, + .nvic_dev_num = NVIC_USART2 + }, + [USART3] = { + .base = (usart_port*)USART3_BASE, + .rcc_dev_num = RCC_USART3, + .nvic_dev_num = NVIC_USART3 + }, +}; + +/* usart interrupt handlers */ void USART1_IRQHandler(void) { - /* Read the data */ - ring_buf1.buf[ring_buf1.tail++] = (uint8)(((usart_port*)(USART1_BASE))->DR); - ring_buf1.tail %= USART_RECV_BUF_SIZE; + rb_insert(&(usart_dev_table[USART1].rb), (uint8)(((usart_port*)(USART1_BASE))->DR)); } -/* Don't overrun your buffer, seriously */ void USART2_IRQHandler(void) { - /* Read the data */ - ring_buf2.buf[ring_buf2.tail++] = (uint8)(((usart_port*)(USART2_BASE))->DR); - ring_buf2.tail %= USART_RECV_BUF_SIZE; + rb_insert(&(usart_dev_table[USART2].rb), (uint8)(((usart_port*)(USART2_BASE))->DR)); } -/* Don't overrun your buffer, seriously */ + void USART3_IRQHandler(void) { - /* Read the data */ - ring_buf3.buf[ring_buf3.tail++] = (uint8)(((usart_port*)(USART3_BASE))->DR); - ring_buf3.tail %= USART_RECV_BUF_SIZE; + rb_insert(&usart_dev_table[USART3].rb, (uint8)(((usart_port*)(USART3_BASE))->DR)); } /** * @brief Enable a USART in single buffer transmission mode, multibuffer - * receiver mode. - * + * 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; + ring_buffer *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_clk_enable(RCC_USART1); - REG_SET(NVIC_ISER1, BIT(5)); - break; - case 2: - port = (usart_port*)USART2_BASE; - ring_buf = &ring_buf2; - clk_speed = USART2_CLK; - rcc_clk_enable(RCC_USART2); - REG_SET(NVIC_ISER1, BIT(6)); - break; - case 3: - port = (usart_port*)USART3_BASE; - ring_buf = &ring_buf3; - clk_speed = USART3_CLK; - rcc_clk_enable(RCC_USART3); - REG_SET(NVIC_ISER1, BIT(7)); - break; - default: - /* should never get here */ - ASSERT(0); - } + port = usart_dev_table[usart_num].base; + rcc_clk_enable(usart_dev_table[usart_num].rcc_dev_num); + nvic_enable_interrupt(usart_dev_table[usart_num].nvic_dev_num); + + /* usart1 is mad fast */ + clk_speed = (usart_num == USART1) ? 72000000UL : 36000000UL; - /* Initialize ring buffer */ - ring_buf->head = 0; - ring_buf->tail = 0; + /* Initialize rx ring buffer */ + rb_init(&usart_dev_table[usart_num].rb, + sizeof (usart_dev_table[usart_num].rx_buf), + usart_dev_table[usart_num].rx_buf); /* Set baud rate */ integer_part = ((25 * clk_speed) / (4 * baud)); @@ -175,33 +124,10 @@ void usart_init(uint8 usart_num, uint32 baud) { /** * @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; + usart_port *port = usart_dev_table[usart_num].base; /* TC bit must be high before disabling the usart */ while ((port->SR & USART_TC) == 0) @@ -211,18 +137,17 @@ void usart_disable(uint8 usart_num) { port->CR1 = 0; /* Clean up buffer */ - usart_clear_buffer(usart_num); + usart_reset_rx(usart_num); } /** * @brief Print a null terminated string to the specified USART * - * @param[in] usart_num USART to send on - * @param[in] str String to send + * @param usart_num usart to send on + * @param 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') { @@ -233,11 +158,10 @@ void usart_putstr(uint8 usart_num, const char* str) { /** * @brief Print an unsigned integer to the specified usart * - * @param[in] usart_num usart to send on - * @param[in] val number to print + * @param usart_num usart to send on + * @param 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; @@ -249,125 +173,4 @@ void usart_putudec(uint8 usart_num, uint32 val) { 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; -} - -void usart_clear_buffer(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); - } - - 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 index 02fb6e0..beffa89 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -23,32 +23,98 @@ * ****************************************************************************/ /** - * @file usart.h - * - * @brief USART Definitions + * @brief USART definitions and prototypes */ #ifndef _USART_H_ #define _USART_H_ -#define NR_USARTS 0x3 +#include "ring_buffer.h" #ifdef __cplusplus extern "C"{ #endif -#define USART_MAX_BAUD 225000 +#define USART_TXE BIT(7) + +/* usart device numbers */ +enum { + USART1, + USART2, + USART3, +}; + +/* peripheral register struct */ +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; + +/* usart descriptor */ +struct usart_dev { + usart_port *base; + ring_buffer rb; + uint8 rx_buf[64]; + const uint8 rcc_dev_num; + const uint8 nvic_dev_num; +}; + +extern struct usart_dev usart_dev_table[]; + + +/** + * @brief send one character on a usart + * @param usart_num usart to send on + * @param byte byte to send + */ +static inline void usart_putc(uint8 usart_num, uint8 byte) { + usart_port *port = usart_dev_table[usart_num].base; + + port->DR = byte; + + /* Wait for transmission to complete */ + while ((port->SR & USART_TXE) == 0) + ; +} + + +/** + * @brief read one character from a usart + * @param usart_num usart to read from + * @return byte read + */ +static inline uint8 usart_getc(uint8 usart_num) { + return rb_remove(&usart_dev_table[usart_num].rb); +} + + +/** + * @brief return the amount of data available in the rx buffer + * @param usart_num which usart to check + * @return number of bytes in the rx buffer + */ +static inline uint32 usart_data_available(uint8 usart_num) { + return rb_full_count(&usart_dev_table[usart_num].rb); +} + + +/** + * @brief removes the contents of the rx fifo + * @param usart_num which usart to reset + */ +static inline void usart_reset_rx(uint8 usart_num) { + rb_reset(&usart_dev_table[usart_num].rb); +} 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); -void usart_clear_buffer(uint8 usart_num); #ifdef __cplusplus } // extern "C" diff --git a/libmaple/util.h b/libmaple/util.h index a18fa84..5b20088 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -65,6 +65,8 @@ #define __read(reg) *(volatile uint32*)(reg) #define __write(reg, value) *(volatile uint32*)(reg) = (value) +#define IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) + #ifdef __cplusplus extern "C"{ #endif diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index 7157e74..c1babff 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -34,77 +34,59 @@ #include "gpio.h" #include "timers.h" -#define USART1_TX_PORT GPIOA_BASE -#define USART1_TX_PIN 9 -#define USART1_RX_PORT GPIOA_BASE -#define USART1_RX_PIN 10 - -#define USART2_TX_PORT GPIOA_BASE -#define USART2_TX_PIN 2 -#define USART2_RX_PORT GPIOA_BASE -#define USART2_RX_PIN 3 - -#define USART3_TX_PORT GPIOB_BASE -#define USART3_TX_PIN 10 -#define USART3_RX_PORT GPIOB_BASE -#define USART3_RX_PIN 11 - -HardwareSerial::HardwareSerial(uint8 usartNum) { - ASSERT(usartNum == 1 || - usartNum == 2 || - usartNum == 3); - this->usartNum = usartNum; +HardwareSerial Serial1(USART1, 4500000UL, GPIOA_BASE, 9, 10, 1, 2); +HardwareSerial Serial2(USART2, 2250000UL, GPIOA_BASE, 2, 3, 2, 3); +HardwareSerial Serial3(USART3, 2250000UL, GPIOB_BASE, 10, 11, 0, 0); + +HardwareSerial::HardwareSerial(uint8 usart_num, + uint32 max_baud, + GPIO_Port *gpio_port, + uint8 tx_pin, + uint8 rx_pin, + uint8 timer_num, + uint8 compare_num) { + this->usart_num = usart_num; + this->max_baud = max_baud; + this->gpio_port = gpio_port; + this->tx_pin = tx_pin; + this->rx_pin = rx_pin; + this->timer_num = timer_num; + this->compare_num = compare_num; } uint8 HardwareSerial::read(void) { - return usart_getc(usartNum); + return usart_getc(usart_num); } uint32 HardwareSerial::available(void) { - - return usart_data_available(usartNum); + return usart_data_available(usart_num); } void HardwareSerial::write(unsigned char ch) { - usart_putc(usartNum, ch); + usart_putc(usart_num, ch); } void HardwareSerial::begin(uint32 baud) { - ASSERT(!(baud > USART_MAX_BAUD)); + if (baud > max_baud) { + return; + } + + gpio_set_mode(gpio_port, tx_pin, GPIO_MODE_AF_OUTPUT_PP); + gpio_set_mode(gpio_port, rx_pin, GPIO_MODE_INPUT_FLOATING); - /* Set appropriate pin modes */ - switch (usartNum) { - case 1: - gpio_set_mode(USART1_TX_PORT, USART1_TX_PIN, GPIO_MODE_AF_OUTPUT_PP); - gpio_set_mode(USART1_RX_PORT, USART1_RX_PIN, GPIO_MODE_INPUT_FLOATING); - /* Turn off any pwm */ - timer_set_mode(1, 2, TIMER_DISABLED); - break; - case 2: - gpio_set_mode(USART2_TX_PORT, USART2_TX_PIN, GPIO_MODE_AF_OUTPUT_PP); - gpio_set_mode(USART2_RX_PORT, USART2_RX_PIN, GPIO_MODE_INPUT_FLOATING); - /* Turn off any pwm */ - timer_set_mode(2, 3, TIMER_DISABLED); - break; - case 3: - gpio_set_mode(USART3_TX_PORT, USART3_TX_PIN, GPIO_MODE_AF_OUTPUT_PP); - gpio_set_mode(USART3_RX_PORT, USART3_RX_PIN, GPIO_MODE_INPUT_FLOATING); - break; - default: - ASSERT(0); - } + if ((usart_num == USART1) || + (usart_num == USART2)) { + /* turn off any pwm if there's a conflict on this usart */ + timer_set_mode(timer_num, compare_num, TIMER_DISABLED); + } - usart_init(usartNum, baud); + usart_init(usart_num, baud); } void HardwareSerial::end(void) { - usart_disable(usartNum); + usart_disable(usart_num); } void HardwareSerial::flush(void) { - usart_clear_buffer(usartNum); + usart_reset_rx(usart_num); } - -HardwareSerial Serial1(1); -HardwareSerial Serial2(2); -HardwareSerial Serial3(3); diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h index 5ed81cd..c2209ce 100644 --- a/wirish/comm/HardwareSerial.h +++ b/wirish/comm/HardwareSerial.h @@ -35,9 +35,21 @@ class HardwareSerial : public Print { private: - uint8 usartNum; + uint8 usart_num; + uint32 max_baud; + GPIO_Port *gpio_port; + uint8 tx_pin; + uint8 rx_pin; + uint8 timer_num; + uint8 compare_num; public: - HardwareSerial(uint8); + HardwareSerial(uint8 usart_num, + uint32 max_baud, + GPIO_Port *gpio_port, + uint8 tx_pin, + uint8 rx_pin, + uint8 timer_num, + uint8 compare_num); void begin(uint32); void end(void); uint32 available(void); @@ -46,7 +58,6 @@ class HardwareSerial : public Print { virtual void write(unsigned char); using Print::write; }; - extern HardwareSerial Serial1; extern HardwareSerial Serial2; extern HardwareSerial Serial3; -- cgit v1.2.3