aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/usart.c
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2011-04-06 13:57:30 -0400
committerMarti Bolivar <mbolivar@leaflabs.com>2011-04-07 13:18:36 -0400
commit552b8882ef04cb0028ec30a04b5464b1a17bccad (patch)
tree27332e20a6b5cfad0629917eb257fad24a9589a4 /libmaple/usart.c
parent012d9ba1c2069d4d072685b990cbd01b611bb751 (diff)
downloadlibrambutan-552b8882ef04cb0028ec30a04b5464b1a17bccad.tar.gz
librambutan-552b8882ef04cb0028ec30a04b5464b1a17bccad.zip
USART refactor.
Diffstat (limited to 'libmaple/usart.c')
-rw-r--r--libmaple/usart.c302
1 files changed, 152 insertions, 150 deletions
diff --git a/libmaple/usart.c b/libmaple/usart.c
index 494a29f..df5e2c5 100644
--- a/libmaple/usart.c
+++ b/libmaple/usart.c
@@ -23,212 +23,214 @@
*****************************************************************************/
/**
+ * @file usart.c
* @brief USART control routines
*/
-#include "libmaple.h"
-#include "rcc.h"
-#include "nvic.h"
#include "usart.h"
-#define USART1_BASE 0x40013800
-#define USART2_BASE 0x40004400
-#define USART3_BASE 0x40004800
-#define UART4_BASE 0x40004C00 // High-density devices only (Maple Native)
-#define UART5_BASE 0x40005000 // High-density devices only (Maple Native)
-
-#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_TC BIT(6)
-
-/* 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
- },
-#ifdef STM32_HIGH_DENSITY
- /* TODO test */
- [UART4] = {
- .base = (usart_port*)UART4_BASE,
- .rcc_dev_num = RCC_UART4,
- .nvic_dev_num = NVIC_UART4
- },
- [UART5] = {
- .base = (usart_port*)UART5_BASE,
- .rcc_dev_num = RCC_UART5,
- .nvic_dev_num = NVIC_UART5
- },
-#endif
-};
-
/*
- * Usart interrupt handlers.
+ * Devices
*/
-static inline void usart_irq(int usart_num) {
-#ifdef USART_SAFE_INSERT
- /* Ignore old bytes if the user defines USART_SAFE_INSERT. */
- rb_safe_insert(&(usart_dev_table[usart_num].rb),
- (uint8)((usart_dev_table[usart_num].base)->DR));
-#else
- /* By default, push bytes around in the ring buffer. */
- rb_push_insert(&(usart_dev_table[usart_num].rb),
- (uint8)((usart_dev_table[usart_num].base)->DR));
-#endif
-}
-
-/* TODO: Check the disassembly for the following functions to make
- sure GCC inlined properly. */
-
-void __irq_usart1(void) {
- usart_irq(USART1);
-}
-
-void __irq_usart2(void) {
- usart_irq(USART2);
-}
-
-void __irq_usart3(void) {
- usart_irq(USART3);
-}
+static ring_buffer usart1_rb;
+static usart_dev usart1 = {
+ .regs = USART1_BASE,
+ .rb = &usart1_rb,
+ .max_baud = 4500000UL,
+ .clk_id = RCC_USART1,
+ .irq_num = NVIC_USART1
+};
+usart_dev *USART1 = &usart1;
+
+static ring_buffer usart2_rb;
+static usart_dev usart2 = {
+ .regs = USART2_BASE,
+ .rb = &usart2_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_USART2,
+ .irq_num = NVIC_USART2
+};
+usart_dev *USART2 = &usart2;
+
+static ring_buffer usart3_rb;
+static usart_dev usart3 = {
+ .regs = USART3_BASE,
+ .rb = &usart3_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_USART3,
+ .irq_num = NVIC_USART3
+};
+usart_dev *USART3 = &usart3;
#ifdef STM32_HIGH_DENSITY
-void __irq_uart4(void) {
- usart_irq(UART4);
-}
-
-void __irq_uart5(void) {
- usart_irq(UART5);
-}
+static ring_buffer uart4_rb;
+static usart_dev uart4 = {
+ .regs = UART4_BASE,
+ .rb = &uart4_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_UART4,
+ .irq_num = NVIC_UART4
+};
+usart_dev *UART4 = &uart4;
+
+static ring_buffer uart5_rb;
+static usart_dev uart5 = {
+ .regs = UART5_BASE,
+ .rb = &uart5_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_UART5,
+ .irq_num = NVIC_UART5
+};
+usart_dev *UART5 = &uart5;
#endif
/**
- * @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
+ * @brief Initialize a serial port.
+ * @param dev Serial port to be initialized
*/
-void usart_init(uint8 usart_num, uint32 baud) {
-#ifdef STM32_HIGH_DENSITY
- ASSERT(usart_num <= UART5);
-#else
- ASSERT(usart_num <= USART3);
-#endif
- usart_port *port;
- ring_buffer *ring_buf;
+void usart_init(usart_dev *dev) {
+ rb_init(dev->rb, USART_RX_BUF_SIZE, dev->rx_buf);
+ rcc_clk_enable(dev->clk_id);
+ nvic_irq_enable(dev->irq_num);
+}
- uint32 clk_speed;
+/**
+ * @brief Configure a serial port's baud rate.
+ *
+ * @param dev Serial port to be configured
+ * @param clock_speed MCU clock speed, in megahertz.
+ * @param baud Baud rate for transmit/receive.
+ */
+void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
uint32 integer_part;
uint32 fractional_part;
uint32 tmp;
- port = usart_dev_table[usart_num].base;
- rcc_clk_enable(usart_dev_table[usart_num].rcc_dev_num);
- nvic_irq_enable(usart_dev_table[usart_num].nvic_dev_num);
-
- /* usart1 is mad fast */
- clk_speed = (usart_num == USART1) ? 72000000UL : 36000000UL;
-
- /* 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));
+ /* See ST RM0008 for the details on configuring the baud rate register */
+ integer_part = (25 * clock_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)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;
+ dev->regs->BRR = (uint16)tmp;
}
/**
- * @brief Turn off all USARTs.
+ * @brief Enable a serial port.
+ *
+ * USART is enabled in single buffer transmission mode, multibuffer
+ * receiver mode, at the given baud rate, 8n1.
+ *
+ * Serial port must have a baud rate configured to work properly.
+ *
+ * @param dev Serial port to enable.
+ * @see usart_set_baud_rate()
*/
-void usart_disable_all() {
- usart_disable(USART1);
- usart_disable(USART2);
- usart_disable(USART3);
-#ifdef STM32_HIGH_DENSITY
- usart_disable(UART4);
- usart_disable(UART5);
-#endif
+void usart_enable(usart_dev *dev) {
+ usart_reg_map *regs = dev->regs;
+ regs->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
+ regs->CR1 |= USART_CR1_UE;
}
/**
- * @brief Turn off a USART.
- * @param USART to be disabled
+ * @brief Turn off a serial port.
+ * @param dev Serial port to be disabled
*/
-void usart_disable(uint8 usart_num) {
- usart_port *port = usart_dev_table[usart_num].base;
+void usart_disable(usart_dev *dev) {
+ /* FIXME this misbehaves if you try to use PWM on TX afterwards */
+ usart_reg_map *regs = dev->regs;
- /* TC bit must be high before disabling the usart */
- while((port->CR1 & USART_UE) && !(port->SR & USART_TC))
+ /* TC bit must be high before disabling the USART */
+ while((regs->CR1 & USART_CR1_UE) && !(regs->SR & USART_SR_TC))
;
/* Disable UE */
- port->CR1 = 0;
+ regs->CR1 = 0;
/* Clean up buffer */
- usart_reset_rx(usart_num);
+ usart_reset_rx(dev);
}
+/**
+ * @brief Call a function on each USART.
+ * @param fn Function to call.
+ */
+void usart_foreach(void (*fn)(usart_dev *dev)) {
+ fn(USART1);
+ fn(USART2);
+ fn(USART3);
+#ifdef STM32_HIGH_DENSITY
+ fn(UART4);
+ fn(UART5);
+#endif
+}
/**
- * @brief Print a null terminated string to the specified USART
- *
- * @param usart_num usart to send on
- * @param str string to send
+ * @brief Print a null-terminated string to the specified serial port.
+ * @param dev Serial port to send the string on
+ * @param str String to send
*/
-void usart_putstr(uint8 usart_num, const char* str) {
+void usart_putstr(usart_dev *dev, const char* str) {
char ch;
- while((ch = *(str++)) != '\0') {
- usart_putc(usart_num, ch);
+ while ((ch = *(str++)) != '\0') {
+ usart_putc(dev, ch);
}
}
/**
- * @brief Print an unsigned integer to the specified usart
+ * @brief Print an unsigned integer to the specified serial port.
*
- * @param usart_num usart to send on
- * @param val number to print
+ * @param dev Serial port to send on
+ * @param val Number to print
*/
-void usart_putudec(uint8 usart_num, uint32 val) {
+void usart_putudec(usart_dev *dev, uint32 val) {
char digits[12];
- int i;
+ int i = 0;
- i = 0;
do {
digits[i++] = val % 10 + '0';
val /= 10;
} while (val > 0);
+
while (--i >= 0) {
- usart_putc(usart_num, digits[i]);
+ usart_putc(dev, digits[i]);
}
}
+
+/*
+ * Interrupt handlers.
+ */
+
+static inline void usart_irq(usart_dev *dev) {
+#ifdef USART_SAFE_INSERT
+ /* Ignore new bytes if the user defines USART_SAFE_INSERT. */
+ rb_safe_insert(dev->rb, (uint8)dev->regs->DR);
+#else
+ /* By default, push bytes around in the ring buffer. */
+ rb_push_insert(dev->rb, (uint8)dev->regs->DR);
+#endif
+}
+
+void __irq_usart1(void) {
+ usart_irq(USART1);
+}
+
+void __irq_usart2(void) {
+ usart_irq(USART2);
+}
+
+void __irq_usart3(void) {
+ usart_irq(USART3);
+}
+
+#ifdef STM32_HIGH_DENSITY
+void __irq_uart4(void) {
+ usart_irq(UART4);
+}
+
+void __irq_uart5(void) {
+ usart_irq(UART5);
+}
+#endif