aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPerry Hung <iperry@alum.mit.edu>2010-08-04 04:38:58 -0400
committerPerry Hung <iperry@alum.mit.edu>2010-08-04 04:38:58 -0400
commitc58c7dbe188509addf817dc208a234ddca6042fe (patch)
treeb4cb0d95935306985804f482ec8622a9dfee2c9d
parent57df5396fe83d0bb7aa55a9f4cd3a9eb2e4a6116 (diff)
downloadlibrambutan-c58c7dbe188509addf817dc208a234ddca6042fe.tar.gz
librambutan-c58c7dbe188509addf817dc208a234ddca6042fe.zip
New usart implementation:
Fixed a bug where the maximum baud rate was incorrectly set to 225000 General cleanup Use new rcc and nvic APIs
-rw-r--r--libmaple/nvic.h10
-rw-r--r--libmaple/ring_buffer.h57
-rw-r--r--libmaple/usart.c281
-rw-r--r--libmaple/usart.h88
-rw-r--r--libmaple/util.h2
-rw-r--r--wirish/comm/HardwareSerial.cpp88
-rw-r--r--wirish/comm/HardwareSerial.h17
7 files changed, 235 insertions, 308 deletions
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;