From 52f5a56d71599811c96d5b4c317fafc07ea847a9 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sun, 12 Jul 2015 18:16:09 +0200 Subject: [PATCH] ARM: move serial handling code directly into serial-arm.c. This makes another seven mbed files obsolete and reduces binary size by another 100 bytes Flash and 16 bytes RAM: SIZES ARM... lpc1114 FLASH : 1624 bytes 5% RAM : 140 bytes 4% EEPROM : 0 bytes 0% --- Makefile-ARM | 2 +- mbed-PeripheralNames.h | 77 ----------- mbed-PortNames.h | 42 ------ mbed-device.h | 71 ----------- mbed-gpio_object.h | 62 --------- mbed-objects.h | 86 ------------- mbed-serial_api.c | 284 ----------------------------------------- mbed-serial_api.h | 89 ------------- serial-arm.c | 143 +++++++++++++++++++-- 9 files changed, 135 insertions(+), 721 deletions(-) delete mode 100644 mbed-PeripheralNames.h delete mode 100644 mbed-PortNames.h delete mode 100644 mbed-device.h delete mode 100644 mbed-gpio_object.h delete mode 100644 mbed-objects.h delete mode 100644 mbed-serial_api.c delete mode 100644 mbed-serial_api.h diff --git a/Makefile-ARM b/Makefile-ARM index a88b45a..4bb7fed 100644 --- a/Makefile-ARM +++ b/Makefile-ARM @@ -98,7 +98,7 @@ TARGET = $(PROGRAM).hex # Until the generic ARM port is completed, we'd have to wrap all sources # in #ifdef __AVR__. To avoid this, build only a selection for now: SOURCES = mendel.c cpu.c serial.c -SOURCES += mbed-serial_api.c mbed-pinmap.c +SOURCES += mbed-pinmap.c ifeq ($(MCU), lpc1114) SOURCES += mbed-system_LPC11xx.c endif diff --git a/mbed-PeripheralNames.h b/mbed-PeripheralNames.h deleted file mode 100644 index 050843e..0000000 --- a/mbed-PeripheralNames.h +++ /dev/null @@ -1,77 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Notes for Teacup: - - Copied from $(MBED)/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/PeripheralNames.h. - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. - - - Prefixed names of #include files with mbed- to match the names of the - copies in the Teacup repo. -*/ -#ifndef MBED_PERIPHERALNAMES_H -#define MBED_PERIPHERALNAMES_H - -#include "mbed-cmsis.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - UART_0 = (int)LPC_UART_BASE -} UARTName; - -typedef enum { - I2C_0 = (int)LPC_I2C_BASE -} I2CName; - -typedef enum { - ADC0_0 = 0, - ADC0_1, - ADC0_2, - ADC0_3, - ADC0_4, - ADC0_5, - ADC0_6, - ADC0_7 -} ADCName; - -typedef enum { - SPI_0 = (int)LPC_SSP0_BASE, - SPI_1 = (int)LPC_SSP1_BASE -} SPIName; - -typedef enum { - PWM_1 = 0, - PWM_2, - PWM_3, - PWM_4, - PWM_5 -} PWMName; - -#define STDIO_UART_TX USBTX -#define STDIO_UART_RX USBRX -#define STDIO_UART UART_0 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/mbed-PortNames.h b/mbed-PortNames.h deleted file mode 100644 index 24059c6..0000000 --- a/mbed-PortNames.h +++ /dev/null @@ -1,42 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Notes for Teacup: - - Copied from $(MBED)/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/PortNames.h. - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. -*/ -#ifndef MBED_PORTNAMES_H -#define MBED_PORTNAMES_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - Port0 = 0, - Port1 = 1, - Port2 = 2, - Port3 = 3 -} PortName; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/mbed-device.h b/mbed-device.h deleted file mode 100644 index d8a1bc6..0000000 --- a/mbed-device.h +++ /dev/null @@ -1,71 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Notes for Teacup: - - Copied from $(MBED)/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/TARGET_LPC11XX/device.h - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. - - - Prefixed names of #include files with mbed- to match the names of the - copies in the Teacup repo. -*/ -#ifndef MBED_DEVICE_H -#define MBED_DEVICE_H - -#define DEVICE_PORTIN 1 -#define DEVICE_PORTOUT 1 -#define DEVICE_PORTINOUT 1 - -#define DEVICE_INTERRUPTIN 1 - -#define DEVICE_ANALOGIN 1 -#define DEVICE_ANALOGOUT 0 - -#define DEVICE_SERIAL 1 - -#define DEVICE_I2C 1 -#define DEVICE_I2CSLAVE 1 - -#define DEVICE_SPI 1 -#define DEVICE_SPISLAVE 1 - -#define DEVICE_CAN 0 - -#define DEVICE_RTC 0 - -#define DEVICE_ETHERNET 0 - -#define DEVICE_PWMOUT 1 - -#define DEVICE_SEMIHOST 0 -#define DEVICE_LOCALFILESYSTEM 0 -#define DEVICE_ID_LENGTH 32 -#define DEVICE_MAC_OFFSET 20 - -#define DEVICE_SLEEP 1 - -#define DEVICE_DEBUG_AWARENESS 0 - -#define DEVICE_STDIO_MESSAGES 1 - -#define DEVICE_ERROR_PATTERN 1 - -#include "mbed-objects.h" - -#endif diff --git a/mbed-gpio_object.h b/mbed-gpio_object.h deleted file mode 100644 index 63546b3..0000000 --- a/mbed-gpio_object.h +++ /dev/null @@ -1,62 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Notes for Teacup: - - Copied from $(MBED)/mbed/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/gpio_object.h. - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. - - - Prefixed names of #include files with mbed- to match the names of the - copies in the Teacup repo. -*/ -#ifndef MBED_GPIO_OBJECT_H -#define MBED_GPIO_OBJECT_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PinName pin; - __I uint32_t *reg_mask_read; - __IO uint32_t *reg_dir; - __IO uint32_t *reg_write; -} gpio_t; - -static inline void gpio_write(gpio_t *obj, int value) { - uint32_t pin_number = ((obj->pin & 0x0F00) >> 8); - if (value) - *obj->reg_write |= (1 << pin_number); - else - *obj->reg_write &= ~(1 << pin_number); -} - -static inline int gpio_read(gpio_t *obj) { - return ((*obj->reg_mask_read) ? 1 : 0); -} - -static inline int gpio_is_connected(const gpio_t *obj) { - return obj->pin != (PinName)NC; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/mbed-objects.h b/mbed-objects.h deleted file mode 100644 index 52dc8ab..0000000 --- a/mbed-objects.h +++ /dev/null @@ -1,86 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Notes for Teacup: - - Copied from $(MBED)/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/objects.h. - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. - - - Prefixed names of #include files with mbed- to match the names of the - copies in the Teacup repo. -*/ -#ifndef MBED_OBJECTS_H -#define MBED_OBJECTS_H - -#include "mbed-cmsis.h" -#include "mbed-PortNames.h" -#include "mbed-PeripheralNames.h" -#include "mbed-PinNames.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct gpio_irq_s { - uint32_t ch; - PinName pin; - __I uint32_t *reg_mask_read; -}; - -struct port_s { - __IO uint32_t *reg_dir; - __IO uint32_t *reg_data; - PortName port; - uint32_t mask; -}; - -struct pwmout_s { - PWMName pwm; -}; - -struct serial_s { - LPC_UART_TypeDef *uart; - int index; -}; - -struct analogin_s { - ADCName adc; -}; - -struct i2c_s { - LPC_I2C_TypeDef *i2c; -}; - -struct spi_s { - LPC_SSP_TypeDef *spi; -}; - -#if DEVICE_CAN -struct can_s { - int index; -}; -#endif - -#include "mbed-gpio_object.h" - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/mbed-serial_api.c b/mbed-serial_api.c deleted file mode 100644 index d356464..0000000 --- a/mbed-serial_api.c +++ /dev/null @@ -1,284 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// math.h required for floating point operations for baud rate calculation -/* - Notes for Teacup: - - Copied from $(MBED)/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/serial_api.c. - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. - - - Prefixed names of #include files with mbed- to match the names of the - copies in the Teacup repo. - - Wrapped the whole file in #ifdef __ARMEL__ to not cause conflicts with - AVR builds. - - Prefixed function names with mbed_ to not conflict with Teacup names. - - Fixed mbed_uart0_irq() function prototype. -*/ -#ifdef __ARMEL__ -#include -#include -#include - -#include "mbed-serial_api.h" -#include "mbed-cmsis.h" -#include "mbed-pinmap.h" - -/****************************************************************************** - * INITIALIZATION - ******************************************************************************/ -#define UART_NUM 1 - -static uint32_t serial_irq_ids[UART_NUM] = {0}; -static uart_irq_handler irq_handler; - -int stdio_uart_inited = 0; -serial_t stdio_uart; - -void mbed_serial_init(serial_t *obj, PinName tx, PinName rx) { - int is_stdio_uart = 0; - - UARTName uart = UART_0; - - obj->uart = (LPC_UART_TypeDef *)uart; - LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); - - // enable fifos and default rx trigger level - obj->uart->FCR = 1 << 0 // FIFO Enable - 0 = Disables, 1 = Enabled - | 0 << 1 // Rx Fifo Reset - | 0 << 2 // Tx Fifo Reset - | 0 << 6; // Rx irq trigger level - 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars - - // disable irqs - obj->uart->IER = 0 << 0 // Rx Data available irq enable - | 0 << 1 // Tx Fifo empty irq enable - | 0 << 2; // Rx Line Status irq enable - - // set default baud rate and format - mbed_serial_baud (obj, 9600); - mbed_serial_format(obj, 8, ParityNone, 1); - - // pinout the chosen uart - pin_function(tx, 0x01); - pin_mode(tx, PullUp); - pin_function(rx, 0x01); - pin_mode(rx, PullUp); - - switch (uart) { - case UART_0: obj->index = 0; break; - } - - is_stdio_uart = (uart == STDIO_UART) ? (1) : (0); - - if (is_stdio_uart) { - stdio_uart_inited = 1; - memcpy(&stdio_uart, obj, sizeof(serial_t)); - } -} - -void mbed_serial_free(serial_t *obj) { - serial_irq_ids[obj->index] = 0; -} - -// serial_baud -// set the baud rate, taking in to account the current SystemFrequency -void mbed_serial_baud(serial_t *obj, int baudrate) { - LPC_SYSCON->UARTCLKDIV = 0x1; - uint32_t PCLK = SystemCoreClock; - // First we check to see if the basic divide with no DivAddVal/MulVal - // ratio gives us an integer result. If it does, we set DivAddVal = 0, - // MulVal = 1. Otherwise, we search the valid ratio value range to find - // the closest match. This could be more elegant, using search methods - // and/or lookup tables, but the brute force method is not that much - // slower, and is more maintainable. - uint16_t DL = PCLK / (16 * baudrate); - - uint8_t DivAddVal = 0; - uint8_t MulVal = 1; - int hit = 0; - uint16_t dlv; - uint8_t mv, dav; - if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder - int err_best = baudrate, b; - for (mv = 1; mv < 16 && !hit; mv++) - { - for (dav = 0; dav < mv; dav++) - { - // baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul)) - // solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul)) - // mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding - // for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision - // note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding - - if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom - dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2; - else // 2 bits headroom, use more precision - dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2; - - // datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood - if (dlv == 0) - dlv = 1; - - // datasheet says if dav > 0 then DL must be >= 2 - if ((dav > 0) && (dlv < 2)) - dlv = 2; - - // integer rearrangement of the baudrate equation (with rounding) - b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2; - - // check to see how we went - b = abs(b - baudrate); - if (b < err_best) - { - err_best = b; - - DL = dlv; - MulVal = mv; - DivAddVal = dav; - - if (b == baudrate) - { - hit = 1; - break; - } - } - } - } - } - - // set LCR[DLAB] to enable writing to divider registers - obj->uart->LCR |= (1 << 7); - - // set divider values - obj->uart->DLM = (DL >> 8) & 0xFF; - obj->uart->DLL = (DL >> 0) & 0xFF; - obj->uart->FDR = (uint32_t) DivAddVal << 0 - | (uint32_t) MulVal << 4; - - // clear LCR[DLAB] - obj->uart->LCR &= ~(1 << 7); -} - -void mbed_serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) { - - stop_bits -= 1; - data_bits -= 5; - - int parity_enable, parity_select; - switch (parity) { - case ParityNone: parity_enable = 0; parity_select = 0; break; - case ParityOdd : parity_enable = 1; parity_select = 0; break; - case ParityEven: parity_enable = 1; parity_select = 1; break; - case ParityForced1: parity_enable = 1; parity_select = 2; break; - case ParityForced0: parity_enable = 1; parity_select = 3; break; - default: - break; - } - - obj->uart->LCR = data_bits << 0 - | stop_bits << 2 - | parity_enable << 3 - | parity_select << 4; -} - -/****************************************************************************** - * INTERRUPTS HANDLING - ******************************************************************************/ -static inline void mbed_uart_irq(uint32_t iir, uint32_t index) { - // [Chapter 14] LPC17xx UART0/2/3: UARTn Interrupt Handling - SerialIrq irq_type; - switch (iir) { - case 1: irq_type = TxIrq; break; - case 2: irq_type = RxIrq; break; - default: return; - } - - if (serial_irq_ids[index] != 0) - irq_handler(serial_irq_ids[index], irq_type); -} - -void mbed_uart0_irq(void) {mbed_uart_irq((LPC_UART->IIR >> 1) & 0x7, 0);} - -void mbed_serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { - irq_handler = handler; - serial_irq_ids[obj->index] = id; -} - -void mbed_serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { - IRQn_Type irq_n = (IRQn_Type)0; - uint32_t vector = 0; - switch ((int)obj->uart) { - case UART_0: - irq_n=UART_IRQn; - vector = (uint32_t)&mbed_uart0_irq; - break; - default: - return; - } - - if (enable) { - obj->uart->IER |= 1 << irq; - NVIC_SetVector(irq_n, vector); - NVIC_EnableIRQ(irq_n); - } else { // disable - int all_disabled = 0; - SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq); - - obj->uart->IER &= ~(1 << irq); - all_disabled = (obj->uart->IER & (1 << other_irq)) == 0; - - if (all_disabled) - NVIC_DisableIRQ(irq_n); - } -} - -/****************************************************************************** - * READ/WRITE - ******************************************************************************/ -int mbed_serial_getc(serial_t *obj) { - while (!mbed_serial_readable(obj)); - return obj->uart->RBR; -} - -void mbed_serial_putc(serial_t *obj, int c) { - while (!mbed_serial_writable(obj)); - obj->uart->THR = c; -} - -int mbed_serial_readable(serial_t *obj) { - return obj->uart->LSR & 0x01; -} - -int mbed_serial_writable(serial_t *obj) { - return obj->uart->LSR & 0x20; -} - -void mbed_serial_clear(serial_t *obj) { - obj->uart->FCR = 1 << 1 // rx FIFO reset - | 1 << 2 // tx FIFO reset - | 0 << 6; // interrupt depth -} - -void mbed_serial_break_clear(serial_t *obj) { - obj->uart->LCR &= ~(1 << 6); -} - -void mbed_serial_break_set(serial_t *obj) { - obj->uart->LCR |= 1 << 6; -} -#endif /* __ARMEL__ */ diff --git a/mbed-serial_api.h b/mbed-serial_api.h deleted file mode 100644 index 2a1834e..0000000 --- a/mbed-serial_api.h +++ /dev/null @@ -1,89 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Notes for Teacup: - - Copied from $(MBED)/libraries/mbed/hal/serial_api.h. - - Used only to get things running quickly. Without serial it's almost - impossible to see wether code changes work. Should go away soon, because - all this MBED stuff is too bloated for Teacup's purposes. - - - Prefixed names of #include files with mbed- to match the names of the - copies in the Teacup repo. - - Prefixed function names with mbed_ to not conflict with Teacup names. -*/ -#ifndef MBED_SERIAL_API_H -#define MBED_SERIAL_API_H - -#include "mbed-device.h" - -#if DEVICE_SERIAL - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - ParityNone = 0, - ParityOdd = 1, - ParityEven = 2, - ParityForced1 = 3, - ParityForced0 = 4 -} SerialParity; - -typedef enum { - RxIrq, - TxIrq -} SerialIrq; - -typedef enum { - FlowControlNone, - FlowControlRTS, - FlowControlCTS, - FlowControlRTSCTS -} FlowControl; - -typedef void (*uart_irq_handler)(uint32_t id, SerialIrq event); - -typedef struct serial_s serial_t; - -void mbed_serial_init (serial_t *obj, PinName tx, PinName rx); -void mbed_serial_free (serial_t *obj); -void mbed_serial_baud (serial_t *obj, int baudrate); -void mbed_serial_format (serial_t *obj, int data_bits, SerialParity parity, int stop_bits); - -void mbed_serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id); -void mbed_serial_irq_set (serial_t *obj, SerialIrq irq, uint32_t enable); - -int mbed_serial_getc (serial_t *obj); -void mbed_serial_putc (serial_t *obj, int c); -int mbed_serial_readable (serial_t *obj); -int mbed_serial_writable (serial_t *obj); -void mbed_serial_clear (serial_t *obj); - -void mbed_serial_break_set (serial_t *obj); -void mbed_serial_break_clear(serial_t *obj); - -void mbed_serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow); - -#ifdef __cplusplus -} -#endif - -#endif - -#endif diff --git a/serial-arm.c b/serial-arm.c index 069ab43..9f90651 100644 --- a/serial-arm.c +++ b/serial-arm.c @@ -2,25 +2,143 @@ /** \file \brief Serial subsystem, ARM specific part. - To be included from serial.c, for details see there. + To be included from serial.c, for more details see there. + + Other than AVRs, ARMs feature a serial buffer in hardware, so we can get + away without a software buffer and also without(!) interrupts. + + Code here is heavily inspired by serial_api.c of MBED, found in + mbed/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/. */ #if defined TEACUP_C_INCLUDE && defined __ARMEL__ #include "arduino.h" -#include "mbed-serial_api.h" +#include "mbed-pinmap.h" + +#ifdef XONXOFF + #error XON/XOFF protocol not yet implemented for ARM. \ + See serial-avr.c for inspiration. +#endif -serial_t serial_line; +LPC_UART_TypeDef *port = LPC_UART; /** Initialise serial subsystem. Set up baud generator and interrupts, clear buffers. */ void serial_init() { - mbed_serial_init(&serial_line, USBTX, USBRX); - mbed_serial_baud(&serial_line, 115200); - mbed_serial_format(&serial_line, 8, ParityNone, 1); + + // Turn on UART power. + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 12); + + // Enable fifos and default RX trigger level. + port->FCR = 1 << 0 // FIFO Enable - 0 = Disabled, 1 = Enabled. + | 0 << 1 // Rx Fifo Reset. + | 0 << 2 // Tx Fifo Reset. + | 0 << 6; // Rx irq trigger level. + // 0 = 1 char, 1 = 4 chars, 2 = 8 chars, 3 = 14 chars. + + // Disable IRQs. + port->IER = 0 << 0 // Rx Data available irq enable. + | 0 << 1 // Tx Fifo empty irq enable. + | 0 << 2; // Rx Line Status irq enable. + + // Baud rate calculation - - - TO BE REFINED, we can calculate all this + // in the preprocessor or even hardcode it, because baud rate never changes. + { + uint32_t baudrate = BAUD; + + LPC_SYSCON->UARTCLKDIV = 0x1; + uint32_t PCLK = SystemCoreClock; + // First we check to see if the basic divide with no DivAddVal/MulVal + // ratio gives us an integer result. If it does, we set DivAddVal = 0, + // MulVal = 1. Otherwise, we search the valid ratio value range to find + // the closest match. This could be more elegant, using search methods + // and/or lookup tables, but the brute force method is not that much + // slower, and is more maintainable. + uint16_t DL = PCLK / (16 * baudrate); + + uint8_t DivAddVal = 0; + uint8_t MulVal = 1; + int hit = 0; + uint16_t dlv; + uint8_t mv, dav; + if ((PCLK % (16 * baudrate)) != 0) { // Checking for zero remainder + int err_best = baudrate, b; + for (mv = 1; mv < 16 && !hit; mv++) + { + for (dav = 0; dav < mv; dav++) + { + // baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul)) + // solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul)) + // mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding + // for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision + // note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding + + if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom + dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2; + else // 2 bits headroom, use more precision + dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2; + + // datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood + if (dlv == 0) + dlv = 1; + + // datasheet says if dav > 0 then DL must be >= 2 + if ((dav > 0) && (dlv < 2)) + dlv = 2; + + // integer rearrangement of the baudrate equation (with rounding) + b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2; + + // check to see how we went + b = b - baudrate; + if (b < 0) b = -b; + if (b < err_best) + { + err_best = b; + + DL = dlv; + MulVal = mv; + DivAddVal = dav; + + if (b == baudrate) + { + hit = 1; + break; + } + } + } + } + } + + // set LCR[DLAB] to enable writing to divider registers + port->LCR |= (1 << 7); + + // set divider values + port->DLM = (DL >> 8) & 0xFF; + port->DLL = (DL >> 0) & 0xFF; + port->FDR = (uint32_t) DivAddVal << 0 + | (uint32_t) MulVal << 4; + + // clear LCR[DLAB] + port->LCR &= ~(1 << 7); + + } /* End of baud rate calculation. */ + + // Serial format. + port->LCR = (8 - 5) << 0 // 8 data bits. + | (1 - 1) << 2 // 1 stop bit. + | 0 << 3 // Parity disabled. + | 0 << 4; // 0 = odd parity, 1 = even parity. + + // Pinout the UART. + pin_function(USBTX, 0x01); + pin_mode(USBTX, PullUp); + pin_function(USBRX, 0x01); + pin_mode(USBRX, PullUp); } /** Check wether characters can be read. @@ -29,19 +147,26 @@ void serial_init() { in the line, but only wether there is at least one or not. */ uint8_t serial_rxchars(void) { - return mbed_serial_readable(&serial_line); + return port->LSR & 0x01; } /** Read one character. */ uint8_t serial_popchar(void) { - return mbed_serial_getc(&serial_line); + uint8_t c = 0; + + if (serial_rxchars()) + c = port->RBR; + + return c; } /** Send one character. + + If the queue is full, too bad. Do NOT block. */ void serial_writechar(uint8_t data) { - mbed_serial_putc(&serial_line, data); + port->THR = data; } #endif /* defined TEACUP_C_INCLUDE && defined __ARMEL__ */