From 7598be3030d8759410929e4b682ad6ff447ec66d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Jun 2013 10:49:08 +0300 Subject: [PATCH 01/48] Add read/write interface. For usage with Console class for example. --- include/rtos/circular.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/rtos/circular.hpp b/include/rtos/circular.hpp index 502303c..05a1482 100644 --- a/include/rtos/circular.hpp +++ b/include/rtos/circular.hpp @@ -102,6 +102,11 @@ class CircularBuffer return 0; return pop(); } + + /* Read/write interface */ + void write(elem b) { push_checked(b); } + // Checking that buffer contains enough elements is on the caller + elem read() { return pop(); } }; } // namespace From 85ade100fd1c8a8ac2d748e7b80b52f39d92dd13 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Jun 2013 18:56:15 +0300 Subject: [PATCH 02/48] Reword comment for clarity. --- include/cortex-m/timer_cortexm_systick.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cortex-m/timer_cortexm_systick.hpp b/include/cortex-m/timer_cortexm_systick.hpp index 8c678dd..e30e477 100644 --- a/include/cortex-m/timer_cortexm_systick.hpp +++ b/include/cortex-m/timer_cortexm_systick.hpp @@ -33,8 +33,8 @@ class CSysTick : public ITimer static void free_run() { SysTick->LOAD = 0xffffff; - // Set CLKSOURCE to get same clock as CPU core. Clock in case - // CLKSOURCE unset is implementation-dependent actually. + // Set CLKSOURCE to get same clock as CPU core. In case CLKSOURCE + // is unset, the clock used is implementation-dependent. SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; } From be8479aedc546502410911f49a81f5122d4f23e1 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Jun 2013 21:40:31 +0300 Subject: [PATCH 03/48] Add initial enumeration of Cortex-M core blocks. --- include/cortex-m/cpu_cortexm.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/cortex-m/cpu_cortexm.hpp b/include/cortex-m/cpu_cortexm.hpp index e9a7314..587d53f 100644 --- a/include/cortex-m/cpu_cortexm.hpp +++ b/include/cortex-m/cpu_cortexm.hpp @@ -16,6 +16,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ +#ifndef _CPU_CORTEXM_HPP +#define _CPU_CORTEXM_HPP + #include #include // Declare Cortex-M IRQ handlers @@ -25,6 +28,9 @@ namespace PTL { class CortexMCPU {}; +// Various blocks of MCU +enum { CORTEXM_NONE, CORTEXM_SYSTICK }; + template <> class CPU : public ICPU { @@ -40,3 +46,5 @@ class CPU : public ICPU }; } // namespace + +#endif // _CPU_CORTEXM_HPP From 4fbac6f26b9ef5ec22ae1c09c23a86a32d2eee58 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 12:42:38 +0300 Subject: [PATCH 04/48] Contrib guidelines: elaborate/fix typos. --- docs/contributing.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/contributing.txt b/docs/contributing.txt index e906f57..d63aa88 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -1,5 +1,9 @@ Peripheral Template Library is currently licensed under the terms of LGPLv3, -though it's consider to either add linking exception clause or switch to +though it's considered to either add linking exception clause or switch to BSD-like license. To facilitate such change in the future, only BSD/MIT -licensed third-party code is merged. If you have suggestion regarding -licensing, please feel free to bring them up. +licensed third-party code is merged, and contributors are asked to license +their patches under dual LGPL3/BSD license (or alternatively, just under BSD +license). + +If you have suggestions regarding licensing, please feel free to bring them +up. From 7d260146541a2d16b08b9fc5f0763c31e155ee52 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 19:43:48 +0300 Subject: [PATCH 05/48] Mark .o as precious. --- Makefile.rules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.rules b/Makefile.rules index 661a6a0..bc6c02c 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -28,6 +28,8 @@ ALL_CXXFLAGS = $(ALL_CFLAGS) -fno-exceptions LDFLAGS = $(TARGET_LDFLAGS) -Wl,--gc-sections -Wl,-Map=$@.map,--cref +.PRECIOUS: $(TARGETDIR)/%.o + $(TARGETDIR)/%.o: %.cpp mkdir -p $(TARGETDIR) $(CXX) $(ALL_CXXFLAGS) -c $^ -o $@ From 2d8d401e4592de0cf7b4ec0ee1ca0faf0edda903 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 19:45:11 +0300 Subject: [PATCH 06/48] Add irq_reset() handler. --- include/cortex-m/timer_cortexm_systick.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/cortex-m/timer_cortexm_systick.hpp b/include/cortex-m/timer_cortexm_systick.hpp index e30e477..e8a3e5b 100644 --- a/include/cortex-m/timer_cortexm_systick.hpp +++ b/include/cortex-m/timer_cortexm_systick.hpp @@ -20,6 +20,7 @@ #define _TIMER_CORTEXM_SYSTICK_HPP #include +#include #include namespace PTL { @@ -27,6 +28,7 @@ namespace PTL { class CSysTick : public ITimer { public: + const static int block_type = CORTEXM_SYSTICK; typedef uint32_t width; static width value() { return SysTick->VAL; } @@ -40,6 +42,8 @@ class CSysTick : public ITimer static void enable_irq() { SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; } static void disable_irq() { SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; } + + static void irq_reset() {} }; typedef CSysTick timer; From f16956b59582a5044a49a3d379d70a95f8d0da09 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 23:12:34 +0300 Subject: [PATCH 07/48] "lm4" target was renamed to "tm4". --- examples/{hw_config_lm4.hpp => hw_config_tm4.hpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{hw_config_lm4.hpp => hw_config_tm4.hpp} (100%) diff --git a/examples/hw_config_lm4.hpp b/examples/hw_config_tm4.hpp similarity index 100% rename from examples/hw_config_lm4.hpp rename to examples/hw_config_tm4.hpp From 3e60b6dadb49ec3ac3e9ef8dfb9ec6dbd403a8ad Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 23:33:29 +0300 Subject: [PATCH 08/48] Initial support to enumerate TM4 blocks. Required for IRQ dispatch. --- include/cpu.hpp | 2 ++ include/tm4/cpu_tm4.hpp | 35 +++++++++++++++++++++++++++++++++++ include/tm4/uart_tm4.hpp | 3 +++ 3 files changed, 40 insertions(+) create mode 100644 include/tm4/cpu_tm4.hpp diff --git a/include/cpu.hpp b/include/cpu.hpp index 0964347..26f8e0c 100644 --- a/include/cpu.hpp +++ b/include/cpu.hpp @@ -24,6 +24,8 @@ #include #elif defined(__EFM32__) #include +#elif defined(__TM4__) +#include #elif defined(__thumb__) || defined(__thumb2__) #include namespace PTL { diff --git a/include/tm4/cpu_tm4.hpp b/include/tm4/cpu_tm4.hpp new file mode 100644 index 0000000..a0037fb --- /dev/null +++ b/include/tm4/cpu_tm4.hpp @@ -0,0 +1,35 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#pragma once +#include + +namespace PTL { + +class TM4CPU {}; + +enum { TM4_UART }; + +template <> +class CPU : public CPU +{ +}; + +typedef CPU cpu; + +} // namespace diff --git a/include/tm4/uart_tm4.hpp b/include/tm4/uart_tm4.hpp index 9c3f8ca..7657298 100644 --- a/include/tm4/uart_tm4.hpp +++ b/include/tm4/uart_tm4.hpp @@ -20,6 +20,7 @@ #define _UART_LM4_HPP #include +#include namespace PTL { @@ -35,6 +36,8 @@ class UART typedef Pin txpin; public: + const static int block_type = TM4_UART; + static void init() { SYSCTL->RCGCUART |= Bit0::value; From cb4366d0aebbd7921a6e0f3e1fa1e2404c9ffd36 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 23:36:49 +0300 Subject: [PATCH 09/48] Refactor and generalize IRQ dispatch support to be reusable for other MCUs. --- include/irq_dispatch.hpp | 25 ++++++++ include/irq_dispatch_base.hpp | 79 ++++++++++++++++++++++++++ include/msp430/irq_dispatch_msp430.hpp | 69 ++++++++++------------ 3 files changed, 133 insertions(+), 40 deletions(-) create mode 100644 include/irq_dispatch.hpp create mode 100644 include/irq_dispatch_base.hpp diff --git a/include/irq_dispatch.hpp b/include/irq_dispatch.hpp new file mode 100644 index 0000000..39ff482 --- /dev/null +++ b/include/irq_dispatch.hpp @@ -0,0 +1,25 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifdef __MSP430__ +#include +#elif defined(__ARM_ARCH_7M__) +#include +#else +#error Unknown platform in irq_dispatch.hpp +#endif diff --git a/include/irq_dispatch_base.hpp b/include/irq_dispatch_base.hpp new file mode 100644 index 0000000..840250f --- /dev/null +++ b/include/irq_dispatch_base.hpp @@ -0,0 +1,79 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _IRQ_DISPATCH_BASE_HPP +#define _IRQ_DISPATCH_BASE_HPP + +namespace PTL { + +/** + ** Device-independent helper macros/classes for interrupt dispatching + **/ + +/* Null MCU device block, used as a placeholder. */ +class NullBlock +{ +public: + const static int block_type = 0; +}; + +/* + * We want to declare a function whose body will be executed only + * when (static) condition is true. We have to use metaprog conditionals + * here, because if condition is false, func body may not compile at all + * (for example because class it opeartes on lacks specific methods). + * So, we use 2 complementary implementations of func: one with empty + * body for case of condition == false, and one with the given body + * in case it's true. All is wrapped with macros for readability. + */ + +#define IRQ_DISPATCH_HELPER(func_name, cond) \ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(!(cond))>::type* = 0) {} \ +\ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(cond)>::type* = 0) \ + +/* Apply templated function to list of template args. Note: this and other similar + funcs depend on particular number of arguments passed and must be updated to + pass more. */ +#define APPLY_TO_ALL(func, b1, b2, b3) { func(); func(); func(); } +/* Apply templated function to list of template args, also passing (runtime) argument + to a function. */ +#define APPLY_TO_ALL_ARG(func, arg, b1, b2, b3) { func(arg); func(arg); func(arg); } + +/* Define handler function for particular hardware IRQ. */ +#define HANDLER(vector, dispatch_func) \ + static void vector##Handler() \ + { \ + APPLY_TO_ALL(dispatch_func, b1, b2, b3); \ + } + +/* Define handler function for particular hardware IRQ, caching value + of a register allowing to demux multiplexed IRQs. This cached value + is passed to each PTL handler. */ +#define HANDLER_CACHE_REG(vector, dispatch_func, reg) \ + static void vector##Handler() \ + { \ + uint8_t cache = reg; \ + APPLY_TO_ALL_ARG(dispatch_func, cache, b1, b2, b3); \ + } + +} // namespace + +#endif // _IRQ_DISPATCH_BASE_HPP diff --git a/include/msp430/irq_dispatch_msp430.hpp b/include/msp430/irq_dispatch_msp430.hpp index 2ae535e..58906e7 100644 --- a/include/msp430/irq_dispatch_msp430.hpp +++ b/include/msp430/irq_dispatch_msp430.hpp @@ -22,32 +22,12 @@ #include // interrupt(X) define. TODO: get rid of? #include +#include namespace PTL { -class NullBlock -{ -public: - const static int block_type = 0; -}; - -/* - * We want to declare a function here whose body will be executed only - * when condition is true. We have to use metaprog conditionals here, - * because if condition is false, func body may not compile at all - * (for example because class it opeartes on lacks specific methods). - * So, we use 2 complementary implementations of func: one with empty - * body for case of condition == false, and one with the given body - * in case it's true. All is wrapped with macros for readability. - */ - -#define IRQ_DISPATCH_HELPER(func_name, cond) \ -template \ -inline void func_name(uint8_t val = 0, typename meta::enable_if<(!(cond))>::type* = 0) {} \ -\ -template \ -inline void func_name(uint8_t val = 0, typename meta::enable_if<(cond)>::type* = 0) \ - +/* Functions to dispatch specific hardware IRQ down to a specific + MCU block and its PTL irq events. */ IRQ_DISPATCH_HELPER(do_timer_main, block::block_type == MSP430_TIMER) { @@ -94,23 +74,8 @@ IRQ_DISPATCH_HELPER(do_usci_tx, block::block_type == MSP430_USCI) block::irq_tx(); } - -#define APPLY_TO_ALL(func, b1, b2, b3) { func(); func(); func(); } -#define APPLY_TO_ALL_ARG(func, arg, b1, b2, b3) { func(arg); func(arg); func(arg); } - -#define HANDLER(vector, dispatch_func) \ - static interrupt(vector) vector##_handler() \ - { \ - APPLY_TO_ALL(dispatch_func, b1, b2, b3); \ - } - -#define HANDLER_CACHE_REG(vector, dispatch_func, reg) \ - static interrupt(vector) vector##_handler() \ - { \ - uint8_t cache = reg; \ - APPLY_TO_ALL_ARG(dispatch_func, cache, b1, b2, b3); \ - } - +/* Class which encapsulates all hardware -> PTL dispatchers. Mostly + used to allow variable list of blocks to dispatch to. */ template class IrqDispatch { @@ -121,6 +86,30 @@ class IrqDispatch HANDLER_CACHE_REG(USCIAB0TX_VECTOR, do_usci_tx, IFG2); }; + +/* Dispatch IRQ from MCU and compiler specific "IRQ vector" function. This + is expected to be fully optimized out by inlining. + What to change when porting: name/attributes of function defined. */ +#define CALL_HANDLER(dispatcher, vector) \ + interrupt(vector) vector##Handler() \ + { \ + dispatcher::vector##Handler(); \ + } + +/* Global IRQ dispatch declaration macro - that's what user uses in the + application code. Note that there can be at most one IRQ_DISPATCH + per application. Specifying all irq-receiving classes at once allows + to suffle/sort/group irq handlers to produce optimal code - that's + what all fucntions/classes/macros above do actually. + What to change when porting: list of CALL_HANDLER calls. */ +#define IRQ_DISPATCH(blocks...) \ + template class IrqDispatch; \ + typedef IrqDispatch _irq_dispatch; \ + CALL_HANDLER(_irq_dispatch, TIMER0_A1_VECTOR); \ + CALL_HANDLER(_irq_dispatch, TIMER0_A0_VECTOR); \ + CALL_HANDLER(_irq_dispatch, USCIAB0RX_VECTOR); \ + CALL_HANDLER(_irq_dispatch, USCIAB0TX_VECTOR); + } // namespace #endif // _IRQ_DISPATCH_MSP430_HPP From 1ead7defd6b8ce9348cecb20835106c2b4d98f8f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 23:56:47 +0300 Subject: [PATCH 10/48] Add initial IRQ dispatching support for Cortex-M. --- include/cortex-m/irq_dispatch_cortexm.hpp | 66 +++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 include/cortex-m/irq_dispatch_cortexm.hpp diff --git a/include/cortex-m/irq_dispatch_cortexm.hpp b/include/cortex-m/irq_dispatch_cortexm.hpp new file mode 100644 index 0000000..8f9a4fd --- /dev/null +++ b/include/cortex-m/irq_dispatch_cortexm.hpp @@ -0,0 +1,66 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _IRQ_DISPATCH_CORTEXM_HPP +#define _IRQ_DISPATCH_CORTEXM_HPP + +#include + +namespace PTL { + +/** + ** Device-specific classes and macros for interrupt dispatching + **/ + +/* Implementation of function which will dispatch harware IRQ to all + blocks which have corresponding PTL handler. + What to change: name, condition, implementation. */ +IRQ_DISPATCH_HELPER(do_systick, block::block_type == CORTEXM_SYSTICK) +{ + block::irq_reset(); +} + +/* Class which encapsulates all hardware -> PTL dispatchers. Mostly + used to allow variable list of blocks to dispatch to. */ +template +class IrqDispatch +{ +public: + HANDLER(SysTick_, do_systick); +}; + +/* Dispatch IRQ from MCU and compiler specific "IRQ vector" function. This + is expected to be fully optimized out by inlining. + What to change: name/attributes of function defined. */ +#define CALL_HANDLER(dispatcher, vector) \ + void vector##Handler() \ + { \ + dispatcher::vector##Handler(); \ + } + +/* Macros to dispatch from MCU/compiler specific "IRQ vector function" + to IrqDispatch class. The latter should be passed in as a param. */ +#define IRQ_DISPATCH(blocks...) \ + template class IrqDispatch; \ + typedef IrqDispatch _irq_dispatch; \ + CALL_HANDLER(_irq_dispatch, SysTick_); + + +} // namespace + +#endif // _IRQ_DISPATCH_CORTEXM_HPP From f1864c20dcbd02e4cb4eca74b95bf9a2480295f4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 23:58:16 +0300 Subject: [PATCH 11/48] Add simplified (one handler) IRQ dispatch sample. --- examples/Makefile | 6 +++++- examples/hw_config_tm4.hpp | 2 ++ examples/irq_dispatch_simple.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 examples/irq_dispatch_simple.cpp diff --git a/examples/Makefile b/examples/Makefile index ed53414..c9375da 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -6,7 +6,7 @@ ALL = blink blink_static blink_dynamic blink_timer blink_ticks \ uart_echo uart_echo_irq uart_echo_async \ uart_printf \ spi i2c_24cxx 1wire adc \ - timer_irq timer_irq_dispatch irq_dispatch \ + timer_irq timer_irq_dispatch irq_dispatch irq_dispatch_simple \ flash \ perf_counter lcd lcd_nokia \ msp430_parse_tlv @@ -32,6 +32,7 @@ i2c_24cxx: $(TARGETDIR)/i2c_24cxx adc: $(TARGETDIR)/adc timer_irq: $(TARGETDIR)/timer_irq timer_irq_dispatch: $(TARGETDIR)/timer_irq_dispatch +irq_dispatch_simple: $(TARGETDIR)/irq_dispatch_simple irq_dispatch: $(TARGETDIR)/irq_dispatch flash: $(TARGETDIR)/flash perf_counter: $(TARGETDIR)/perf_counter @@ -74,3 +75,6 @@ $(TARGETDIR)/adc.o: adc.cpp $(TARGETDIR)/lcd: $(TARGETDIR)/lcd.o $(TARGETDIR)/lcd.o: lcd.cpp + +$(TARGETDIR)/irq_dispatch: $(TARGETDIR)/irq_dispatch.o +$(TARGETDIR)/irq_dispatch_simple: $(TARGETDIR)/irq_dispatch_simple.o diff --git a/examples/hw_config_tm4.hpp b/examples/hw_config_tm4.hpp index 713eb7d..e87891e 100644 --- a/examples/hw_config_tm4.hpp +++ b/examples/hw_config_tm4.hpp @@ -1,3 +1,5 @@ +#include + using namespace PTL; typedef UART<16 MHZ, 115200, UART0_> uart; diff --git a/examples/irq_dispatch_simple.cpp b/examples/irq_dispatch_simple.cpp new file mode 100644 index 0000000..5fce1f4 --- /dev/null +++ b/examples/irq_dispatch_simple.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +#include HW_CONFIG + +class mytimer : public timer +{ +public: + static void irq_reset() + { + board::LED::toggle(); + } +}; + +IRQ_DISPATCH(mytimer); + +int main() +{ + cpu::init(cpu::DEFAULT); + board::LED::port::enable(); + board::LED::output(); + mytimer::free_run(); + mytimer::enable_irq(); + cpu::enable_irq(); + while (true); +} From 44a4707d10cbb758c44f7f71edb197b6413de8d1 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Jun 2013 23:59:21 +0300 Subject: [PATCH 12/48] Update for IRQ dispatch refactor. --- examples/irq_dispatch.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/irq_dispatch.cpp b/examples/irq_dispatch.cpp index 016752a..0db73d4 100644 --- a/examples/irq_dispatch.cpp +++ b/examples/irq_dispatch.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include HW_CONFIG @@ -35,9 +35,7 @@ class myspi : public spi } }; -// Explicit instantiation of IRQ dispatcher class -template class IrqDispatch; - +IRQ_DISPATCH(mytimer, myuart, myspi); int main() { From 5f63b35c651f3b3fe742c9277d0292020061e7ed Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 21 Jun 2013 00:23:59 +0300 Subject: [PATCH 13/48] Add hwconfig for STM32. --- examples/hw_config_stm32.hpp | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/hw_config_stm32.hpp diff --git a/examples/hw_config_stm32.hpp b/examples/hw_config_stm32.hpp new file mode 100644 index 0000000..53081a1 --- /dev/null +++ b/examples/hw_config_stm32.hpp @@ -0,0 +1 @@ +using namespace PTL; From 1ebb6c329e08840271dc2c9a94710b45082ab231 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 22 Jun 2013 14:46:44 +0300 Subject: [PATCH 14/48] Add initial support for LLVM MSP430 target. --- Makefile.rules | 2 ++ Makefile.rules.msp430-llvm | 29 ++++++++++++++++++++++++++ include/msp430/delay_static_msp430.hpp | 13 +++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Makefile.rules.msp430-llvm diff --git a/Makefile.rules b/Makefile.rules index bc6c02c..9ac5a0b 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -30,6 +30,7 @@ LDFLAGS = $(TARGET_LDFLAGS) -Wl,--gc-sections -Wl,-Map=$@.map,--cref .PRECIOUS: $(TARGETDIR)/%.o +ifneq ($(OVERRIDE_RULES),1) $(TARGETDIR)/%.o: %.cpp mkdir -p $(TARGETDIR) $(CXX) $(ALL_CXXFLAGS) -c $^ -o $@ @@ -37,6 +38,7 @@ $(TARGETDIR)/%.o: %.cpp $(TARGETDIR)/%.o: %.c mkdir -p $(TARGETDIR) $(CXX) $(ALL_CXXFLAGS) -c $^ -o $@ +endif $(TARGETDIR)/%.s: %.cpp mkdir -p $(TARGETDIR) diff --git a/Makefile.rules.msp430-llvm b/Makefile.rules.msp430-llvm new file mode 100644 index 0000000..89041a4 --- /dev/null +++ b/Makefile.rules.msp430-llvm @@ -0,0 +1,29 @@ +#GCC_PATH = /opt/mspgcc-4.7/bin/ + +MCU = msp430g2553 +TARGET_FLAGS = -mmcu=$(MCU) +# Can select specific device if multiple connected at the same time, +# format "-s " or "-U ", see mspdebug --help +DEVICE_SELECT ?= + +OPT = opt-3.0 +LLC = llc-3.0 +CROSS_COMPILE = msp430- + +LOPS = -D__MSP430__ -D__MSP430G2553__ -I/usr/msp430/include -m32 -emit-llvm +OOPS = -std-compile-opts -strip-debug -disable-simplify-libcalls +LLCOPS = -march=msp430 + +OVERRIDE_RULES = 1 + +$(TARGETDIR)/%.o: %.cpp + mkdir -p $(TARGETDIR) + clang $(ALL_CXXFLAGS) $(LOPS) -c $^ -o $@.bc + $(OPT) $(OOPS) $@.bc -f -o $@.opt.bc + $(LLC) $(LLCOPS) $@.opt.bc -o $@.opt.s_ + awk '/.globl\tmain/ { print "\t.section\t.init9,\"ax\",@progbits"; } \ + { print }' $@.opt.s_ > $@.opt.s + msp430-as $@.opt.s -o $@ + +deploy-%: $(TARGETDIR)/% + mspdebug $(DEVICE_SELECT) rf2500 "prog $^" diff --git a/include/msp430/delay_static_msp430.hpp b/include/msp430/delay_static_msp430.hpp index bd689f3..628ca69 100644 --- a/include/msp430/delay_static_msp430.hpp +++ b/include/msp430/delay_static_msp430.hpp @@ -72,6 +72,7 @@ static ALWAYS_INLINE void __delay_cycles2(long delay) quot = (delay - 4) / 4 - 1; // cycles stops on 0 -> -1 transition, i.e. 1 extra iteration rem = (delay - 4) % 4; +#ifndef __clang__ asm( "mov %A0, r14 \n" "mov %B0, r15 \n" @@ -81,7 +82,17 @@ static ALWAYS_INLINE void __delay_cycles2(long delay) "jc 1b \n" // 2 cycles, msp430 has weird C flag value for substracts : : "ir" (quot) : "r14", "r15" ); - +#else + asm( + "mov %0, r14 \n" + "mov %1, r15 \n" + "1: \n" + "sub #1, r14 \n" // 1 cycle + "subc #0, r15 \n" // 1 cycle + "jc 1b \n" // 2 cycles, msp430 has weird C flag value for substracts + : : "ir" ((uint16_t)(quot & 0xffff)), "ir" ((uint16_t)(quot >> 16)) : "r14", "r15" + ); +#endif // It might be possible to optimize these, but it's boring uint16_t low = (uint16_t)quot; uint16_t hiw = quot >> 16; From 1692511275b075998ab5ac65a1d64ab6fa42850d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 25 Jun 2013 23:53:46 +0300 Subject: [PATCH 15/48] Elaborate LLVM support for MSP430. --- Makefile.rules.msp430-llvm | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Makefile.rules.msp430-llvm b/Makefile.rules.msp430-llvm index 89041a4..7936b79 100644 --- a/Makefile.rules.msp430-llvm +++ b/Makefile.rules.msp430-llvm @@ -1,4 +1,7 @@ -#GCC_PATH = /opt/mspgcc-4.7/bin/ +LLVM_PATH = /home/pfalcon/projects-3rdparty/llvm-3.0.src/Debug/bin +OPT = $(LLVM_PATH)/opt +LLC = $(LLVM_PATH)/llc +CROSS_COMPILE = msp430- MCU = msp430g2553 TARGET_FLAGS = -mmcu=$(MCU) @@ -6,21 +9,19 @@ TARGET_FLAGS = -mmcu=$(MCU) # format "-s " or "-U ", see mspdebug --help DEVICE_SELECT ?= -OPT = opt-3.0 -LLC = llc-3.0 -CROSS_COMPILE = msp430- - -LOPS = -D__MSP430__ -D__MSP430G2553__ -I/usr/msp430/include -m32 -emit-llvm -OOPS = -std-compile-opts -strip-debug -disable-simplify-libcalls -LLCOPS = -march=msp430 +CLANGFLAGS = -ccc-host-triple msp430 -D__MSP430G2553__ -I/usr/msp430/include -m32 -emit-llvm +OPTFLAGS = -std-compile-opts -strip-debug -disable-simplify-libcalls +LLCFLAGS = -march=msp430 OVERRIDE_RULES = 1 $(TARGETDIR)/%.o: %.cpp mkdir -p $(TARGETDIR) - clang $(ALL_CXXFLAGS) $(LOPS) -c $^ -o $@.bc - $(OPT) $(OOPS) $@.bc -f -o $@.opt.bc - $(LLC) $(LLCOPS) $@.opt.bc -o $@.opt.s_ + clang $(ALL_CXXFLAGS) $(CLANGFLAGS) -S -c $^ -o $@.ll + $(OPT) $(OPTFLAGS) -S $@.ll -f -o $@.opt.ll + + $(LLC) $(LLCFLAGS) $@.opt.ll -o $@.opt.s_ + awk '/.globl\tmain/ { print "\t.section\t.init9,\"ax\",@progbits"; } \ { print }' $@.opt.s_ > $@.opt.s msp430-as $@.opt.s -o $@ From b7e041ef86f7a4be4c4c8c5d483c5338e61a0b1a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 25 Jun 2013 23:54:22 +0300 Subject: [PATCH 16/48] Add support for LLVM C backend roundtrip compile. --- Makefile.rules.msp430-llvm-c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Makefile.rules.msp430-llvm-c diff --git a/Makefile.rules.msp430-llvm-c b/Makefile.rules.msp430-llvm-c new file mode 100644 index 0000000..0ad2d27 --- /dev/null +++ b/Makefile.rules.msp430-llvm-c @@ -0,0 +1,33 @@ +LLVM_PATH = /home/pfalcon/projects-3rdparty/llvm-3.0.src/Debug/bin +OPT = $(LLVM_PATH)/opt +LLC = $(LLVM_PATH)/llc +CROSS_COMPILE = msp430- + +MCU = msp430g2553 +TARGET_FLAGS = -mmcu=$(MCU) +# Can select specific device if multiple connected at the same time, +# format "-s " or "-U ", see mspdebug --help +DEVICE_SELECT ?= + +CLANGFLAGS = -ccc-host-triple msp430 -D__MSP430G2553__ -I/usr/msp430/include -m32 -emit-llvm +OPTFLAGS = -std-compile-opts -strip-debug -disable-simplify-libcalls +LLCFLAGS = -march=msp430 + +OVERRIDE_RULES = 1 + +$(TARGETDIR)/%.o: %.cpp + mkdir -p $(TARGETDIR) + clang $(ALL_CXXFLAGS) $(CLANGFLAGS) -S -c $^ -o $@.ll + $(OPT) $(OPTFLAGS) -S $@.ll -f -o $@.opt.ll + + $(LLC) -march=c $@.opt.ll -o $@.cbackend.c + clang $(ALL_CXXFLAGS) $(CLANGFLAGS) -c $@.cbackend.c -o $@.cbackend.ll + $(OPT) $(OPTFLAGS) $@.cbackend.ll -f -S -o $@.cbackend.opt.ll + $(LLC) $(LLCFLAGS) $@.cbackend.opt.ll -o $@.opt.s_ + + awk '/.globl\tmain/ { print "\t.section\t.init9,\"ax\",@progbits"; } \ + { print }' $@.opt.s_ > $@.opt.s + msp430-as $@.opt.s -o $@ + +deploy-%: $(TARGETDIR)/% + mspdebug $(DEVICE_SELECT) rf2500 "prog $^" From 3cb883de8c45b9abb0236131ddef3a027b5219af Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 13 Jul 2013 22:42:03 +0200 Subject: [PATCH 17/48] Fix one case were bitcode was still generated instead of LLVM assembly. --- Makefile.rules.msp430-llvm-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.rules.msp430-llvm-c b/Makefile.rules.msp430-llvm-c index 0ad2d27..44d242b 100644 --- a/Makefile.rules.msp430-llvm-c +++ b/Makefile.rules.msp430-llvm-c @@ -21,7 +21,7 @@ $(TARGETDIR)/%.o: %.cpp $(OPT) $(OPTFLAGS) -S $@.ll -f -o $@.opt.ll $(LLC) -march=c $@.opt.ll -o $@.cbackend.c - clang $(ALL_CXXFLAGS) $(CLANGFLAGS) -c $@.cbackend.c -o $@.cbackend.ll + clang $(ALL_CXXFLAGS) $(CLANGFLAGS) -S -c $@.cbackend.c -o $@.cbackend.ll $(OPT) $(OPTFLAGS) $@.cbackend.ll -f -S -o $@.cbackend.opt.ll $(LLC) $(LLCFLAGS) $@.cbackend.opt.ll -o $@.opt.s_ From d56287f0d50aa3daa29e6ed496a413abf4f79943 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 25 Sep 2013 23:39:19 +0300 Subject: [PATCH 18/48] Add NearPtr class implementation - transparent offseted pointer of small size. For example, allows to address up to 64KB of 32bit MCU with 16bit pointer value. Useful when pointers need to be stored within in-memory objects. --- include/algo/nearptr.hpp | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 include/algo/nearptr.hpp diff --git a/include/algo/nearptr.hpp b/include/algo/nearptr.hpp new file mode 100644 index 0000000..907adae --- /dev/null +++ b/include/algo/nearptr.hpp @@ -0,0 +1,77 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _NEAR_PTR_HPP +#define _NEAR_PTR_HPP +// As C++ doesn't support overloading templates by parameters, we should name +// all templates differently. Also, "const char *" template parameter cannot +// be cast to int. So, we have 3 templates with the same implementation, +// difgering only in type of base template parameter. + +#define IMPL(name) \ +public: \ + storage_t off; \ + name() { off = 0; } \ + name(T *p) { off = ((int)p - (int)base) >> align; } \ + T& operator*() const { return *(T*)((int)base + (off << align)); } \ + operator T*() const { return (T*)((int)base + (off << align)); } + +// NearPtr against absolute base. This is what would be used on +// MCU platform. +// Params: +// base - base of the memoty region within which pointer will point +// storage_t - size of pointer value (uint8_t, uint16_t, etc.); can be +// signed type too if needed +// T - type to point to +// align - alignment of pointer, as power of 2 +// For example, 16-bit NearPtr with alignment of 16 can address 1MB of memory +template class AbsNearPtr +{ + IMPL(AbsNearPtr) +}; + +// NearPtr against statically allocated array (note: must have external +// linkage, i.e. defined globally w/o static keyword). +template class ArrayNearPtr +{ + IMPL(ArrayNearPtr) +}; + +// NearPtr against dynamic base store in a variable, for example, received +// from malloc(). +template class VarNearPtr +{ + IMPL(VarNearPtr) +}; + +#if 0 +// Example usage: + +const int base1 = 0x20000000; +char base2[256] = "foobar"; +char *base3 = (char*)malloc(256); + +template using Ptr1 = AbsNearPtr; +template using Ptr2 = ArrayNearPtr; +template using Ptr3 = VarNearPtr; + +Ptr2 p = &base2[3]; +printf("%c", *p); // Produces "b" +#endif + +#endif // _NEAR_PTR_HPP From 332e296633160d5548cad66c243854ab40f26fef Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 25 Sep 2013 23:42:50 +0300 Subject: [PATCH 19/48] Add NearPtr test. --- tests/Makefile | 3 ++- tests/nearptr.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/nearptr.cpp diff --git a/tests/Makefile b/tests/Makefile index 259cb08..b8037f1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,7 +1,7 @@ PTL_PATH = .. include $(PTL_PATH)/Makefile.rules -ALL = sub_mod circular +ALL = sub_mod circular nearptr .PHONY: $(ALL) .PRECIOUS: $(TARGETDIR)/%.o @@ -10,3 +10,4 @@ all: $(ALL) sub_mod: $(TARGETDIR)/sub_mod circular: $(TARGETDIR)/circular +nearptr: $(TARGETDIR)/nearptr diff --git a/tests/nearptr.cpp b/tests/nearptr.cpp new file mode 100644 index 0000000..6812f2a --- /dev/null +++ b/tests/nearptr.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +const int base1 = 0x20000000; +char base2[256] = "foobar"; +char *base3 = (char*)malloc(256); + +//template using Ptr = AbsNearPtr; +template using Ptr = ArrayNearPtr; +//template using Ptr = VarNearPtr; + +void func(Ptr p) +{ + assert(sizeof(p) == 2); + assert((char*)p == base2 + 3); + assert(*p == 'b'); + assert(p[1] == 'a'); +} + +int main() +{ + Ptr p = &base2[3]; + assert(sizeof(p) == 2); + // Pass into a function to avoid inlining optimizations + func(p); +} From 9eb101d6713d80b2895dbb6201a5882747e2a7f0 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 25 Sep 2013 23:45:48 +0300 Subject: [PATCH 20/48] First step towards switching to C++11. --- Makefile.rules.i686-linux-gnu | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.rules.i686-linux-gnu b/Makefile.rules.i686-linux-gnu index 388549c..6da5d8c 100644 --- a/Makefile.rules.i686-linux-gnu +++ b/Makefile.rules.i686-linux-gnu @@ -1,2 +1,4 @@ OBJDUMP = objdump #TARGET_CFLAGS = -S +GCC_VER = -4.8 +TARGET_CFLAGS = -std=c++11 From 68ef1861aa5536510eebacff5cd93d8738fbfcd6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 15:57:32 +0300 Subject: [PATCH 21/48] spi_msp430: Add comments about pin altfunc setting. --- include/msp430/spi_msp430.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/msp430/spi_msp430.hpp b/include/msp430/spi_msp430.hpp index 4612bd2..6ce9079 100644 --- a/include/msp430/spi_msp430.hpp +++ b/include/msp430/spi_msp430.hpp @@ -50,6 +50,7 @@ class SPI : public ISPI, public SPIBlockXfer< SPI >, public MSP4 UCB0BR0 = 1; UCB0BR1 = 0; + // Set SPI altfuncs for pins P1SEL |= SCLK | SDI | SDO; P1SEL2 |= SCLK | SDI | SDO; // Per MSP430 manual, direction of SCLK/MOSI/MISO is controlled @@ -60,6 +61,7 @@ class SPI : public ISPI, public SPIBlockXfer< SPI >, public MSP4 static void disable() { UCB0CTL1 = UCSWRST; + // Unset SPI altfuncs, back to GPIO mode P1SEL &= ~(SCLK | SDI | SDO); P1SEL2 &= ~(SCLK | SDI | SDO); } From 34fce25437ed7c9eab1a71992b12b765b7ada049 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 16:18:30 +0300 Subject: [PATCH 22/48] Elaborate why BSD-like licensing is required for contribution. --- docs/contributing.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/contributing.txt b/docs/contributing.txt index d63aa88..4a69e55 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -5,5 +5,12 @@ licensed third-party code is merged, and contributors are asked to license their patches under dual LGPL3/BSD license (or alternatively, just under BSD license). +The rationale of this request is that, if such licensing change is carried +out in the future, all contributors will need to be contacted to ask their +permissions to relicense, with possible complications that some contributors +won't respond, or will be against such change. So, instead I'm asking all +potential contributors about BSD licensing right away. I hope this makes +sense and reasonably fair. + If you have suggestions regarding licensing, please feel free to bring them up. From 1cc3e85156cea7a89fa044fe9b20bbef4a9c8fb7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 17:54:37 +0300 Subject: [PATCH 23/48] README: Grammar fix. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 8a7b716..b8a4172 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ standard protocols to access peripheral devices, like SPI, I2C, UART, 1-Wire, etc. To achieve high-level efficiency, PTL is built using (C++) templated static -types, which allows to apply aggressive compile-time optimizations, +types, allowing to apply aggressive compile-time optimizations, achieving the efficiency level of the C code purposedly written for specific MCU. Using templates also allows to provide optimized protocol implementations utilizing specialized MCU hardware blocks like SPI/I2C From ea477be448cb8ebcc3d1e1a232c7caaa184b6427 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 27 Oct 2013 12:58:25 +0200 Subject: [PATCH 24/48] gpio_base: (Finally) let parametrize IPin value width, defaults to int for compatibility. IPin's value width would be most likely underlying port width. --- include/gpio_base.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/gpio_base.hpp b/include/gpio_base.hpp index e697dea..f65b1ca 100644 --- a/include/gpio_base.hpp +++ b/include/gpio_base.hpp @@ -27,15 +27,16 @@ namespace PTL { // Pin is abstraction of basic I/O signal -template +template class IPin { public: + typedef width_ width; + static void enable(); static void output(); static void input(); - // TODO: need better type - static int value(); + static width value(); static void high(); static void low(); static void toggle(); From fc36c72da5a4ca794274c43fabace6acce615da6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 27 Oct 2013 13:06:05 +0200 Subject: [PATCH 25/48] gpio_base: Allow to specify relative port number. Indended to be used with dynamic pins. --- include/gpio_base.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/gpio_base.hpp b/include/gpio_base.hpp index f65b1ca..04f053e 100644 --- a/include/gpio_base.hpp +++ b/include/gpio_base.hpp @@ -53,11 +53,14 @@ class IPin }; // Port is a collection of related pins -template +// no_ is thru-numbered relative port number (0 - very first GPIO port, etc.) +// Used mostly for defining numbering for dynapins. +template class IPort { public: typedef width_ width; + static const int no = no_; // Enable port for access (power on, set up clocks, etc.) static void enable() {} From 80c5a7e89c6e933f249ecb6543db0d3fcc5ba701 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 27 Oct 2013 13:24:12 +0200 Subject: [PATCH 26/48] gpio_base: Elaborate descriptions of classes. --- include/gpio_base.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/gpio_base.hpp b/include/gpio_base.hpp index 04f053e..f9fed53 100644 --- a/include/gpio_base.hpp +++ b/include/gpio_base.hpp @@ -72,7 +72,12 @@ class IPort static void set_masked(width val, width mask) { set(value() & mask); } }; -// Pin which belongs to a port +// Pin which belongs to a (static) port +// Most GPIO pins in MCUs are grouped into ports, +// and this class captures pin's port and bit position +// within port. But note that all pins don't have +// to use this class (when there's no underlying "port", +// if such port is not static) and can use IPin directly. template class PortPin: public IPin { @@ -84,7 +89,10 @@ class PortPin: public IPin }; // Non-existent pin, can be used when a pin in some design is optional. -// All access will be optimized out by compiler. +// All access will be optimized out by compiler. Typical example +// is a LED - boards which have it, can define it to a specific pin, +// and boards which lack - to NullPin, and code will still compile +// (though indication obviously won't be present in second case). class NullPin : public IPin { public: From 1a779f55a19d45a9fb062104462481c4fc4c22aa Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 13 Aug 2014 23:23:12 +0300 Subject: [PATCH 27/48] examples: Add example of interfacing C code with PTL. Of course, this is pretty inefficient - the idea is to wrap efficient templated, inlinable C++ call into public, non-inlinable C function. But if there's need to interface with legacy C code - well, that's possible. --- examples/Makefile | 5 ++++- examples/blink_c.c | 12 ++++++++++++ examples/blink_c_api.cpp | 31 +++++++++++++++++++++++++++++++ examples/blink_c_api.h | 14 ++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 examples/blink_c.c create mode 100644 examples/blink_c_api.cpp create mode 100644 examples/blink_c_api.h diff --git a/examples/Makefile b/examples/Makefile index c9375da..618a320 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,7 @@ PTL_PATH = .. include $(PTL_PATH)/Makefile.rules ALL = blink blink_static blink_dynamic blink_timer blink_ticks \ - blink_sleep blink_bus \ + blink_sleep blink_bus blink_c \ uart_echo uart_echo_irq uart_echo_async \ uart_printf \ spi i2c_24cxx 1wire adc \ @@ -22,6 +22,7 @@ blink_timer: $(TARGETDIR)/blink_timer blink_ticks: $(TARGETDIR)/blink_ticks blink_sleep: $(TARGETDIR)/blink_sleep blink_bus: $(TARGETDIR)/blink_bus +blink_c: $(TARGETDIR)/blink_c uart_echo: $(TARGETDIR)/uart_echo uart_echo_irq: $(TARGETDIR)/uart_echo_irq uart_echo_async: $(TARGETDIR)/uart_echo_async @@ -58,6 +59,8 @@ $(TARGETDIR)/blink_ticks.o: blink_ticks.cpp $(TARGETDIR)/blink_bus: $(TARGETDIR)/blink_bus.o $(TARGETDIR)/blink_bus.o: blink_bus.cpp +$(TARGETDIR)/blink_c: $(TARGETDIR)/blink_c.o $(TARGETDIR)/blink_c_api.o + $(TARGETDIR)/uart_echo: $(TARGETDIR)/uart_echo.o $(TARGETDIR)/uart_echo.o: uart_echo.cpp diff --git a/examples/blink_c.c b/examples/blink_c.c new file mode 100644 index 0000000..d7328af --- /dev/null +++ b/examples/blink_c.c @@ -0,0 +1,12 @@ +#include "blink_c_api.h" + +int main() +{ + init(); + while (1) { + led_high(); + delay(100000U); + led_low(); + delay(100000U); + } +} diff --git a/examples/blink_c_api.cpp b/examples/blink_c_api.cpp new file mode 100644 index 0000000..17e1325 --- /dev/null +++ b/examples/blink_c_api.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include "blink_c_api.h" + +using namespace PTL; + +typedef Delay delayer; + +void led_high() +{ + board::LED::high(); +} + +void led_low() +{ + board::LED::low(); +} + +void delay(uint32_t val) +{ + delayer::delay(val); +} + +void init() +{ + cpu::init(cpu::DEFAULT); + board::LED::port::enable(); + board::LED::output(); +} diff --git a/examples/blink_c_api.h b/examples/blink_c_api.h new file mode 100644 index 0000000..f6713b1 --- /dev/null +++ b/examples/blink_c_api.h @@ -0,0 +1,14 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void init(); +void led_high(); +void led_low(); +void delay(uint32_t val); + +#ifdef __cplusplus +} +#endif From 09bd71631ce4f65b57765b156ecd926017fb0402 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 13 Aug 2014 23:38:54 +0300 Subject: [PATCH 28/48] Makefile.rules: Use C compiler to compile C sources, after all. Required for C interoperatibility example. --- Makefile.rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.rules b/Makefile.rules index 9ac5a0b..5eb1861 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -37,7 +37,7 @@ $(TARGETDIR)/%.o: %.cpp $(TARGETDIR)/%.o: %.c mkdir -p $(TARGETDIR) - $(CXX) $(ALL_CXXFLAGS) -c $^ -o $@ + $(CC) $(ALL_CXXFLAGS) -c $^ -o $@ endif $(TARGETDIR)/%.s: %.cpp From a5ee59cb9ac3df652760d57d0128e3ebcf29ad9e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 16:45:56 +0300 Subject: [PATCH 29/48] mps430: Add script to help calculate best UART modulation value. Details are in datasheet. --- scripts/msp430_rate.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 scripts/msp430_rate.py diff --git a/scripts/msp430_rate.py b/scripts/msp430_rate.py new file mode 100644 index 0000000..f57abbd --- /dev/null +++ b/scripts/msp430_rate.py @@ -0,0 +1,23 @@ +def calc(freq, baud): + return ((freq * 8 * 2 / baud) - (freq / baud * 8 * 2) + 1) / 2 + +#for baud in (9600, 19200, 38400, 56000, 115200, 128000, 256000): + +MOD = [0, 0x02, 0x22, 0x2a, 0xaa, 0xae, 0xee, 0xfe] + + +for baud in (256000,): + div = 1000000 / baud + mod = calc(1000000, baud) + 0 + print baud, mod + t_ideal = 1.0 / baud + print "ideal bit length (s):", t_ideal + bit = 1 + err = 0.0 + while bit != 0x100: + t = (div + int(bool(MOD[mod] & bit))) / 1000000.0 + print t, t - t_ideal + err += t - t_ideal + bit <<= 1 + + print err / t_ideal * 100 From c0b19bdd77a77703fa21579cb784231cecbbe37e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 16:49:40 +0300 Subject: [PATCH 30/48] protocol: AVR ISP protocol. WIP. Based on AVR910. --- include/protocol/avr_isp.hpp | 67 ++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 include/protocol/avr_isp.hpp diff --git a/include/protocol/avr_isp.hpp b/include/protocol/avr_isp.hpp new file mode 100644 index 0000000..8c95802 --- /dev/null +++ b/include/protocol/avr_isp.hpp @@ -0,0 +1,67 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2014 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#include +#include +#include + +// TODO: WIP, untested + +namespace PTL { + +template +class AVR_ISP +{ +public: + static void init() + { + reset_sig::output(); + reset_sig::deassert(); + } + + static void start() + { + reset_sig::assert(); + //AVR910 + delayer::delay_ms(20); + } + + static void send_cmd(uint16_t cmd, uint8_t b2, uint8_t b3) + { + spi::transfer(cmd >> 8); + spi::transfer(cmd & 0xff); + spi::transfer(b2); + return spi::transfer(b3); + } + + static void enable_program() + { + if (send_cmd(CMD_Program_Enable, 0x55, 0xaa) != 0x55) + return false; + return true; + } + + static void read_flash(uint16_t addr) + { + uint16_t cmd = addr & 1 ? CMD_Read_Flash_High : CMD_Read_Flash_Low; + addr >>= 1; + return send_cmd(cmd | (addr >> 8), addr & 0xff, 0); + } +}; + +} // namespace From 873f2be5f68eb83eaac7d409c15b30673f94b7b8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 16:50:44 +0300 Subject: [PATCH 31/48] protocol: USB host protocol, very rough sketch WIP. --- include/protocol/usb.hpp | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 include/protocol/usb.hpp diff --git a/include/protocol/usb.hpp b/include/protocol/usb.hpp new file mode 100644 index 0000000..116b752 --- /dev/null +++ b/include/protocol/usb.hpp @@ -0,0 +1,48 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2014 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +// TODO: WIP, untested + +namespace PTL { + +template <> +class USB +{ + PID _next_data = PID_DATA0; +public: + static void xact_in(); + static void xact_out(usb_addr_t addr, usb_endp_t endpoint, uint8_t *data, uint16_t len) + { + send_token(PID_OUT, addr, endpoint); + send_data(next_data(), data, len); + recv_handshake(); + } + static void xact_setup(); + + PID next_data() + { + PID r = _next_data; + if (_next_data == PID_DATA0) + _next_data == PID_DATA1; + else + _next_data == PID_DATA0; + } +}; + +} // namespace From 50d253f9d1c9460c862afa400cba73597eb1e550 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 16:52:48 +0300 Subject: [PATCH 32/48] cortex-m: Timer using Cycle Count (CYCCNT) debug register. --- include/cortex-m/timer_cortexm_cyccnt.hpp | 49 +++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 include/cortex-m/timer_cortexm_cyccnt.hpp diff --git a/include/cortex-m/timer_cortexm_cyccnt.hpp b/include/cortex-m/timer_cortexm_cyccnt.hpp new file mode 100644 index 0000000..cf5a252 --- /dev/null +++ b/include/cortex-m/timer_cortexm_cyccnt.hpp @@ -0,0 +1,49 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _TIMER_CORTEXM_SYSTICK_HPP +#define _TIMER_CORTEXM_SYSTICK_HPP + +#include + +// TODO: WIP, untested + +namespace PTL { + +class CCycCnt : public ITimer +{ +public: + typedef uint32_t width; + + static width value() { return DWT->CYCCNT; } + static void free_run() + { + // p.11-19 Cortex-M3 r2p0 TechRefMan + // The TRCENA bit of the Debug Exception and Monitor Control Register must be set + // before you can use the DWT. + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA; + if (DWT->CTRL == 0 || (DWT->CTRL & DWT_CTRL_NOCYCCNT)) { + abort(); + } + DWT->CTRL |= DWT_CTRL_CYCCNTENA; + } +}; + +} // namespace + +#endif // _TIMER_CORTEXM_SYSTICK_HPP From 1c1048ae1c4d56de80204c5e32d7099a8b4a78fd Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 23:16:55 +0300 Subject: [PATCH 33/48] mps430: Dynamic GPIO pin implementation. Dynapin whose location (port/bit) can be assigned (and changed) at runtime. --- include/msp430/gpio_msp430.hpp | 1 + include/msp430/gpiodyn_msp430.hpp | 96 +++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 include/msp430/gpiodyn_msp430.hpp diff --git a/include/msp430/gpio_msp430.hpp b/include/msp430/gpio_msp430.hpp index b8a4fb7..85052b3 100644 --- a/include/msp430/gpio_msp430.hpp +++ b/include/msp430/gpio_msp430.hpp @@ -29,6 +29,7 @@ template { public: + static const int base = in_reg_; static const int in_reg = in_reg_; static const int out_reg = out_reg_; static const int dir_reg = dir_reg_; diff --git a/include/msp430/gpiodyn_msp430.hpp b/include/msp430/gpiodyn_msp430.hpp new file mode 100644 index 0000000..b60d8a9 --- /dev/null +++ b/include/msp430/gpiodyn_msp430.hpp @@ -0,0 +1,96 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _GPIODYN_MSP430_HPP +#define _GPIODYN_MSP430_HPP + +#include +#include +#include + +namespace PTL { + +struct DynaPort_Store { + int base; +}; + +struct DynaPin_Store { + int base; + uint8_t value; +}; + +template +class DynaPort { +public: + static void enable() { store.base; } +}; + +template +class DynaPin { + static int in_reg(int base) { return base; } + static int out_reg(int base) { return base + 1; } + static int dir_reg(int base) { return base + 2; } + static int ren_reg(int base) { return base == P3::base ? P3REN_ : base + 7; } + +public: + typedef uint8_t width; + typedef DynaPort port; + + static width value() + { + return _REG8(in_reg(store.base)) & store.value; + } + static void high() + { + _REG8(out_reg(store.base)) |= store.value; + } + static void low() + { + _REG8(out_reg(store.base)) &= ~store.value; + } + static void toggle() + { + _REG8(out_reg(store.base)) ^= store.value; + } + static void output() + { + _REG8(dir_reg(store.base)) |= store.value; + } + static void input() + { + _REG8(dir_reg(store.base)) &= ~store.value; + } + static void pulloff() + { + _REG8(ren_reg(store.base)) &= ~store.value; + } + static void pullup() + { + _REG8(ren_reg(store.base)) |= store.value; + _REG8(out_reg(store.base)) |= store.value; + } + static void pulldown() + { + _REG8(ren_reg(store.base)) |= store.value; + _REG8(out_reg(store.base)) &= ~store.value; + } +}; + +} // namespace + +#endif //_GPIODYN_MSP430_HPP From 6f06064d5da8418539d9ccb0e7e374cfbdaf67b9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 27 Oct 2013 13:08:53 +0200 Subject: [PATCH 34/48] gpio_msp430: Assign relative port numbers. --- include/msp430/gpio_msp430.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/msp430/gpio_msp430.hpp b/include/msp430/gpio_msp430.hpp index 85052b3..bdfe092 100644 --- a/include/msp430/gpio_msp430.hpp +++ b/include/msp430/gpio_msp430.hpp @@ -25,8 +25,8 @@ namespace PTL { -template -class Port : public IPort +template +class Port : public IPort { public: static const int base = in_reg_; @@ -36,9 +36,9 @@ class Port : public IPort static const int resistor_reg = resistor_reg_; }; -typedef Port P1; -typedef Port P2; -typedef Port P3; +typedef Port P1; +typedef Port P2; +typedef Port P3; template class Pin : public PortPin< Pin, port, bit > From 95b4c05a22ba6b328255da1b3225e6163eb76931 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 27 Oct 2013 13:31:52 +0200 Subject: [PATCH 35/48] msp430: Elaborate gpiodyn implementation. --- include/msp430/gpiodyn_msp430.hpp | 48 +++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/include/msp430/gpiodyn_msp430.hpp b/include/msp430/gpiodyn_msp430.hpp index b60d8a9..deab8cc 100644 --- a/include/msp430/gpiodyn_msp430.hpp +++ b/include/msp430/gpiodyn_msp430.hpp @@ -26,22 +26,60 @@ namespace PTL { struct DynaPort_Store { - int base; + // msp430 SFR (including port) registers are located in + // first 256 bytes of address space, plus there's movzx + // instruction. So, we can optimize port base addres + // storage to byte w/o any overhead. + uint8_t base; + + DynaPort_Store() {} + DynaPort_Store(uint8_t port_no) { + set(port_no); + } + + void set(uint8_t port_no) { + switch (port_no) { + case 0: + base = P1::base; + break; + case 1: + base = P2::base; + break; + case 2: + base = P3::base; + break; + } + } }; -struct DynaPin_Store { - int base; +struct DynaPin_Store : DynaPort_Store { + // Pin mask, named for consistency with Bit<>::value uint8_t value; + + DynaPin_Store(uint8_t port_no, uint8_t pin_no) { + set(port_no, pin_no); + } + + void set(uint8_t port_no, uint8_t pin_no) { + DynaPort_Store::set(port_no); + value = 1 << pin_no; + } }; +// Here's caveat: template param really should be DynaPort_Store&, +// but C++ in template class DynaPin "typedef DynaPort port;" then +// cannot cast from DynaPin_Store& to DynaPort_Store& - implicitly or +// explicitly. So, little choice: dynamic port backing storage takes +// as much as dynamic pin, and the other field is not really used. +// C++, grow smarter! template -class DynaPort { +class DynaPort : public IPort { public: static void enable() { store.base; } }; template -class DynaPin { +class DynaPin : public IPin, uint8_t> { static int in_reg(int base) { return base; } static int out_reg(int base) { return base + 1; } static int dir_reg(int base) { return base + 2; } From 49e027c5cdde2a19636eaf85fd16f70fa2b924f7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 23:17:58 +0300 Subject: [PATCH 36/48] Example for dynapin. --- examples/Makefile | 3 ++- examples/blink_dynapin.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 examples/blink_dynapin.cpp diff --git a/examples/Makefile b/examples/Makefile index 618a320..ad363f2 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,7 @@ PTL_PATH = .. include $(PTL_PATH)/Makefile.rules ALL = blink blink_static blink_dynamic blink_timer blink_ticks \ - blink_sleep blink_bus blink_c \ + blink_sleep blink_bus blink_c blink_dynapin \ uart_echo uart_echo_irq uart_echo_async \ uart_printf \ spi i2c_24cxx 1wire adc \ @@ -23,6 +23,7 @@ blink_ticks: $(TARGETDIR)/blink_ticks blink_sleep: $(TARGETDIR)/blink_sleep blink_bus: $(TARGETDIR)/blink_bus blink_c: $(TARGETDIR)/blink_c +blink_dynapin: $(TARGETDIR)/blink_dynapin uart_echo: $(TARGETDIR)/uart_echo uart_echo_irq: $(TARGETDIR)/uart_echo_irq uart_echo_async: $(TARGETDIR)/uart_echo_async diff --git a/examples/blink_dynapin.cpp b/examples/blink_dynapin.cpp new file mode 100644 index 0000000..54a0ada --- /dev/null +++ b/examples/blink_dynapin.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +using namespace PTL; + +typedef TimeDelay delayer; + +//DynaPin_Store led_spec = {board::LED::port::base, board::LED::bit::value}; +DynaPin_Store led_spec(board::LED::port::no, board::LED::bit::shift); +typedef DynaPin dynaLED; + +int main() +{ + cpu::init(cpu::DEFAULT); + dynaLED::port::enable(); + dynaLED::output(); + while (true) { + dynaLED::high(); + delayer::delay_ms(500); + dynaLED::low(); + delayer::delay_ms(500); + } +} From 6fa8611b6f6a3cfc01c891a74b1050a5f511ff5f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Aug 2014 11:14:02 +0300 Subject: [PATCH 37/48] examples: HW configs: explicitly define hardware uart object (hwuart). Some examples require hardware UART with interrupt support, etc., so make it obvious. --- examples/hw_config_avr.hpp | 3 ++- examples/hw_config_msp430.hpp | 19 ++++++++++++++----- examples/hw_config_tm4.hpp | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/examples/hw_config_avr.hpp b/examples/hw_config_avr.hpp index cf8d41b..513c4cb 100644 --- a/examples/hw_config_avr.hpp +++ b/examples/hw_config_avr.hpp @@ -2,7 +2,8 @@ using namespace PTL; -typedef board::uart uart; +typedef board::uart hwuart; +typedef hwuart uart; typedef ParBus hd44780_data; typedef Signal hd44780_en_sig; diff --git a/examples/hw_config_msp430.hpp b/examples/hw_config_msp430.hpp index 7064523..dcfc84e 100644 --- a/examples/hw_config_msp430.hpp +++ b/examples/hw_config_msp430.hpp @@ -5,6 +5,10 @@ using namespace PTL; +//#define LAUNCHPAD_MSP430_VER_1_4 + +#ifndef LAUNCHPAD_MSP430_VER_1_4 + /* MSP430 Launchpad hw. rev. 1.5 has different (swapped) pin assignments for "software" and "hardware" UART. This is rooted in the fact that hwrev. 1.4 had "software" assignment, but later released chips with hardware UART @@ -18,18 +22,23 @@ using namespace PTL; 1.4 support. More info: http://pfalcon-oe.blogspot.com/2012/07/ti-launchpad-14-vs-15-pin-swappery.html */ +typedef UART<1 MHZ, 9600, USCI_A> hwuart; //typedef UART uart; typedef UART<1 MHZ, 9600, USCI_A> uart; -/* MSP430 Launchpad hw. rev. 1.4 doesn't have hardware UART support at all, - and bitbang UART has to use swapped RXD/TXD pins. */ -//typedef UART, Pin, timer> uart; - -/* At this time, only USCI-based hardware SPI is supported, USI is still needs +/* At this time, only USCI-based hardware SPI is supported, USI still needs wrapping. Note that USCI vs USI SPI pins have the same swapping issue as UART above (great work, TI!) */ typedef SPI spi; +#else + +/* MSP430 Launchpad hw. rev. 1.4 doesn't have hardware UART support at all, + and bitbang UART has to use swapped RXD/TXD pins. */ +typedef UART, Pin, timer> uart; + +#endif + typedef ParBus< Pin, Pin, Pin, Pin > hd44780_data; typedef Signal< Pin > hd44780_en_sig; typedef Signal< Pin > hd44780_regsel_sig; diff --git a/examples/hw_config_tm4.hpp b/examples/hw_config_tm4.hpp index e87891e..7667f97 100644 --- a/examples/hw_config_tm4.hpp +++ b/examples/hw_config_tm4.hpp @@ -2,4 +2,5 @@ using namespace PTL; -typedef UART<16 MHZ, 115200, UART0_> uart; +typedef UART<16 MHZ, 115200, UART0_> hwuart; +typedef hwuart uart; From 6a2edac45c3e96985e4e64845141c3a8b204a2e4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 14 Aug 2014 10:58:22 +0300 Subject: [PATCH 38/48] examples/uart_echo_irq.cpp: Update for PTL namespace and HW config. --- examples/uart_echo_irq.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/uart_echo_irq.cpp b/examples/uart_echo_irq.cpp index 9d008d8..7e8bdd8 100644 --- a/examples/uart_echo_irq.cpp +++ b/examples/uart_echo_irq.cpp @@ -3,7 +3,9 @@ #include #include -typedef UART<1 MHZ, 9600, USCI> uart; +#include HW_CONFIG + +namespace PTL { template <> void uart::uart_rx_irq_handler() @@ -12,13 +14,15 @@ void uart::uart_rx_irq_handler() board::LED::toggle(); } +} + int main() { cpu::init(cpu::DEFAULT); board::LED::output(); board::LED::low(); - uart::init(); - uart::enable_rx_irq(); + hwuart::init(); + hwuart::enable_rx_irq(); cpu::enable_irq(); while (true); From 97424ecc784a4e77a8a7c904bd291129045866f3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Aug 2014 01:57:17 +0300 Subject: [PATCH 39/48] circular.hpp: Mark few methods volatile for interrupt-safe operation. --- include/rtos/circular.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/rtos/circular.hpp b/include/rtos/circular.hpp index 05a1482..1d0fb31 100644 --- a/include/rtos/circular.hpp +++ b/include/rtos/circular.hpp @@ -18,6 +18,10 @@ */ namespace PTL { + +// Note: only methods marked "volatile" are thread/interrupt safe +// All other methods should be called only from critical section +// (e.g., with interrupts disabled). template class CircularBuffer { @@ -34,7 +38,7 @@ class CircularBuffer return _size; } - bool empty() const + bool empty() const volatile { return _size == 0; } @@ -56,7 +60,7 @@ class CircularBuffer return e; } - elem front() const + elem front() const volatile { return *head; } @@ -71,7 +75,7 @@ class CircularBuffer return max_size_ - _size; } - bool full() const + bool full() const volatile { return _size == max_size_; } From a84e51688061dd1c40b75f320352cf7f3d0bd384 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 23:19:30 +0300 Subject: [PATCH 40/48] buffered_uart.hpp: Buffered interrupt-driven UART. --- include/rtos/buffered_uart.hpp | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 include/rtos/buffered_uart.hpp diff --git a/include/rtos/buffered_uart.hpp b/include/rtos/buffered_uart.hpp new file mode 100644 index 0000000..60f41d1 --- /dev/null +++ b/include/rtos/buffered_uart.hpp @@ -0,0 +1,95 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#include +#include + +namespace PTL { + +template class buffer = PTL::CircularBuffer> +class BufferedUart +{ +public: + + static buffer read_buf; + static buffer write_buf; + + class uart_handlers : public uart + { + public: + static void irq_rx() + { + if (read_buf.full()) + overrun(); + else + read_buf.push(uart::read_async()); + } + static void irq_tx() + { +// assert(!store.write_buf.empty()); + uint8_t c = write_buf.pop(); + uart::write_async(c); + // If there's nothing more to send, disable TX IRQ + // (really "TX Buffer Empty IRQ") + if (write_buf.empty()) + uart::disable_tx_irq(); + } + }; + +public: + static void init() + { + uart::init(); + // We always should expect to receive something + uart::enable_rx_irq(); + // but in the beginning, there's nothing to send - + // interrupts will be enabled on first char to send + uart::disable_tx_irq(); + } + static uint8_t read() + { + while (read_buf.empty()); + uart::disable_rx_irq(); + uint8_t c = read_buf.pop(); + uart::enable_rx_irq(); + return c; + } + static void write(uint8_t c) + { + while (write_buf.full()); + uart::disable_tx_irq(); + write_buf.push(c); + // We added new char, so there's something to send - enable TX IRQ + uart::enable_tx_irq(); + } + + // Override + static void overrun() + { + } + +}; + +// Explicit instantiation of static fields +template class buffer> + buffer BufferedUart::read_buf; +template class buffer> + buffer BufferedUart::write_buf; + +} // namespace From c9bf0901ad5f9936ae67046c0e73c462bbf60491 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 23:20:43 +0300 Subject: [PATCH 41/48] examples: Buffered UART demo. --- examples/Makefile | 3 ++- examples/uart_echo_buffered.cpp | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 examples/uart_echo_buffered.cpp diff --git a/examples/Makefile b/examples/Makefile index ad363f2..1480c69 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,7 +3,7 @@ include $(PTL_PATH)/Makefile.rules ALL = blink blink_static blink_dynamic blink_timer blink_ticks \ blink_sleep blink_bus blink_c blink_dynapin \ - uart_echo uart_echo_irq uart_echo_async \ + uart_echo uart_echo_irq uart_echo_async uart_echo_buffered \ uart_printf \ spi i2c_24cxx 1wire adc \ timer_irq timer_irq_dispatch irq_dispatch irq_dispatch_simple \ @@ -27,6 +27,7 @@ blink_dynapin: $(TARGETDIR)/blink_dynapin uart_echo: $(TARGETDIR)/uart_echo uart_echo_irq: $(TARGETDIR)/uart_echo_irq uart_echo_async: $(TARGETDIR)/uart_echo_async +uart_echo_buffered: $(TARGETDIR)/uart_echo_buffered uart_printf: $(TARGETDIR)/uart_printf spi: $(TARGETDIR)/spi i2c_24cxx: $(TARGETDIR)/i2c_24cxx diff --git a/examples/uart_echo_buffered.cpp b/examples/uart_echo_buffered.cpp new file mode 100644 index 0000000..d7fb91d --- /dev/null +++ b/examples/uart_echo_buffered.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include HW_CONFIG + +typedef BufferedUart buart; + +IRQ_DISPATCH(buart::uart_handlers); + +int main() +{ + cpu::init(cpu::DEFAULT); + board::LED::output(); + board::LED::low(); + buart::init(); + cpu::enable_irq(); + + while (true) { + // We have time to process only 3 incoming chars, ... + for (int i = 0; i < 3; i++) { + uint8_t b = buart::read(); + board::LED::toggle(); + buart::write(b); + } + // ..., and then we're busy with very important task + // The whole idea is that even if we don't process incoming + // chars regularly, they are not lost, but buffered in + // background. + StaticDelay::delay(500000U); + } +} From 6d592cd5e5e8d581b909756807d4270ce7fd2244 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 16 Aug 2014 01:52:14 +0300 Subject: [PATCH 42/48] docs: Add data model description (including advanced topics). --- docs/data_model.markdown | 144 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 docs/data_model.markdown diff --git a/docs/data_model.markdown b/docs/data_model.markdown new file mode 100644 index 0000000..b3d3362 --- /dev/null +++ b/docs/data_model.markdown @@ -0,0 +1,144 @@ +Normal C++ objects keep their state in memory fields. However, for embedded +devices, state is usually held is special registers outside usual memory +range. And even an empty (with 0 fields) C++ object takes at least 1 byte +of a memory (as mandated by C++ standard). As PTL strives for the highest +possible efficiency, wasting a whole byte for nothing is not acceptable and +C++ objects are not used for basic hardware data model. (Note, C++ objects +are used for higher-level ("RTOS-like") functionality, as there's clear +need to keep additional state in memory). + +Instead, PTL uses C++ parametrized types (aka templates) to represent +hardware objects. There's rough correspondence between conventional runtime +C++ object model and typed-based schedule: + +Generic entity abstraction ("class"): + +Runtime OO: + + class Foo { + Foo(type1 param1, type2 param2); + ... + }; + +Type-based OO: + + template + class Foo {...}; + +Object instantiation: + +Runtime OO: + + Foo foo1(param1, param2); + +Type-based OO: + + typdef Foo foo1; + +Passing object as argument (to function or constructor of another object): + +Runtime OO: + + Bar bar1(foo1); + +Type-based OO: + + typedef Bar bar1; + +Dynamic allocation: + +Runtime OO: + + Foo *foo2 = new Foo(param1, param2); + +Type-based OO: + + In type-based schedule, objects take 0 bytes of conventional memory, + and keep state in implicit special memory location, so it doesn't make + sense to "dynamically allocate" them. + + + +Well, the last subsection about dynamic allocation is "almost true". Let's +first consider that besides efficiency PTL also strives to provide fully +generic and generalized abstraction of hardware devices, support arbitrary +possible implementations for them, and allow different abtract blocks to +be combined in structured manner. This poses interesting problem that +while typically hardware classes don't have own state (because they wrap +special hardware registers, and address them implicitly), for some +implementations of these classes there may be need to store additional +state. + +Let's take a GPIO pin as an example. Typically, a pin will be represented +by: + +typedef GPIO mypin1; + +Where PORT_A and PIN_0 are constants statically selecting particular port +and pin in it. + +But sometimes there may be need to have "dynamic" GPIO pin, which is not +bound to a particular physical pin, but rather configured with at runtime +to use arbitrary pin. This would be obvious usecase for conventional C++ +object: + +GPIO mypin2(port_var, pin_var); + +But we already selected type-based object representation, so mypin as defined +above won't be compatible with PTL standard model, in other word, you won't be +able to "pass" mypin2 where mypin1 is expected (per above comparison table, +type-based objects are passed as template arguments, where normal objects are +passed as normal arguments). + +So, we must retain type-based interface, and yet add runtime-modifiable state +to such type. There're 2 ways to resolve this situation: + +1. Split state from type-based object into "backing store": + +struct GPIOStore { + int port; + int pin; +}; + +And then parametrize type-based object with reference to particular instance +of backing store: + +template +class DynaGPIO { +}; + +2. Well, just store state in static fields, but making sure we parametrize +type-based object by unique values, so template instantiation leads to +distinct types (and thus distinct static variables for each type object). +For such unique values, initial/default values make work (they certainly +work for GPIO case - hopefully one won't create 2 distinct pin objects +which are actually the same pin). + +template +class DynaGPIO { + static int port; + static int pin; +}; + +template int Pin::port = port_; +template int Pin::pin = pin_; + +Note the explicit instantiation of templated static fields. + + +Second choice looks more "integral", because it doesn't require creation of +separate type, but it has mild tricks of requiring unique parametrization +and explicit template instantiation for static fields. And well, it's clear +that here state will be statically allocated. + +First choice looks more flexible, because it would be seem that backing +store might be allocated on stack. But that's not really case, because +template parameter must be (at least in C++03) compile time addressable, +like static varaible and unlike automatic or dynamic variable. + +So, choice 2 looks like clear winner as offering cleaner and more concise +interface. Choice 1 was initially implemented for DynaPin class, and +retained there for time being (to explore and see if more differences +between choices will be found), but choice 2 will be used for new classes. + + From f2d5f315903fac9a803ca7d8170bc347a9218943 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 17:32:23 +0300 Subject: [PATCH 43/48] WIP Add RTOS-style virtual timer. --- include/rtos/virt_timer.hpp | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 include/rtos/virt_timer.hpp diff --git a/include/rtos/virt_timer.hpp b/include/rtos/virt_timer.hpp new file mode 100644 index 0000000..9354a78 --- /dev/null +++ b/include/rtos/virt_timer.hpp @@ -0,0 +1,39 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _VIRT_TIMER_HPP +#define _VIRT_TIMER_HPP + +#include + +namespace PTL { + +template +class VirtTimer +{ + typename timer::width start; + typename timer::width period; +public: + void start(typename timer::width period) { start = timer::value(); this->period = period; } + bool expired() + { return timer::elapsed(timer::value(), start) > period; } +}; + +} // namespace + +#endif //_VIRT_TIMER_HPP From 87eb698cc7267ab407d5dfcc7941a651e77a471d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 27 Oct 2013 18:44:34 +0200 Subject: [PATCH 44/48] Some initial hack to support LPC800 bootrom with drivers. Drivers are arguably ugly. The whole idea of this is to show that PTL can wrap such ROM drivers, not to promote their usage. --- include/lpc/lpc800_bootrom.hpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 include/lpc/lpc800_bootrom.hpp diff --git a/include/lpc/lpc800_bootrom.hpp b/include/lpc/lpc800_bootrom.hpp new file mode 100644 index 0000000..922304b --- /dev/null +++ b/include/lpc/lpc800_bootrom.hpp @@ -0,0 +1,34 @@ +#define BOOTROM 0x1fff0000 +#define BOOTROM_SIZE 8192 +// ROM In-Application Programming routine +// +1 to signify this is Thumb code +#define BOOTROM_IAP (BOOTROM + BOOTROM_SIZE - 16 + 1) +#define BOOTROM_DEVICE_DRIVER_TABLE (BOOTROM + BOOTROM_SIZE - 8) + +// cmd and result can point to same area of memory (UM10601 p.269) +typedef void (*IAPFuncPtr)(uint32_t *cmd, uint32_t *result); + +#define DEVICE_DRIVER_FUNC_TABLE(device_no) ((*(uint32_t**)BOOTROM_DEVICE_DRIVER_TABLE)[device_no]) + +struct LPC800_PWRD { + void (*set_pll)(unsigned int cmd[4], unsigned int resp[2]); + void (*set_power)(unsigned int cmd[4], unsigned int resp[2]); +}; + +struct LPC800_DeviceDrivers { + void *res0; + void *res1; + void *res2; + struct LPC800_PWRD *PWRD; + void *res4; + struct LPC800_I2CD *I2CD; + void *res6; + void *res7; + void *res8; + struct LPC800_USARTD *USARTD; +}; + +#define DeviceDrivers (*(struct LPC800_DeviceDrivers**)BOOTROM_DEVICE_DRIVER_TABLE) + +// Example usage: +//DeviceDrivers->PWRD->set_power(); From 3206d6b7b263d98d831d2a066167c35d92966871 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 17:16:12 +0300 Subject: [PATCH 45/48] irqs_msp430.hpp: File with enumeration of all MSP430 IRQ handlers. Rejected. Was rejected - handlers belong to specific hardware blocks. --- include/msp430/irqs_msp430.hpp | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 include/msp430/irqs_msp430.hpp diff --git a/include/msp430/irqs_msp430.hpp b/include/msp430/irqs_msp430.hpp new file mode 100644 index 0000000..a24956b --- /dev/null +++ b/include/msp430/irqs_msp430.hpp @@ -0,0 +1,55 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _IRQ_MSP430_HPP +#define _IRQ_MSP430_HPP + +namespace PTL { + +struct TimerIrqHandlers +{ + static void irq_reset(); + static void irq_capture_compare0(); + static void irq_capture_compare1(); + static void irq_capture_compare2(); +}; + +struct CommIrqHandlers +{ + static void irq_rx(); + static void irq_tx(); +}; + +struct ComparatorIrqHandlers +{ + static void irq_change(); +}; + +struct AdcIrqHandlers +{ + static void irq_done(); +}; + +struct GpioIrqHandlers +{ + static void irq_pin_change(); +}; + +} // namespace + +#endif // _IRQ_MSP430_HPP From 0a4b9c1af82960fc4476e528da1d9f9caa91d688 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 17:18:16 +0300 Subject: [PATCH 46/48] timer_irq_dispatch_msp430.hpp.function --- .../timer_irq_dispatch_msp430.hpp.function | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 include/msp430/timer_irq_dispatch_msp430.hpp.function diff --git a/include/msp430/timer_irq_dispatch_msp430.hpp.function b/include/msp430/timer_irq_dispatch_msp430.hpp.function new file mode 100644 index 0000000..5cc411e --- /dev/null +++ b/include/msp430/timer_irq_dispatch_msp430.hpp.function @@ -0,0 +1,87 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _TIMER_MSP430_DISPATCH_HPP +#define _TIMER_MSP430_DISPATCH_HPP + +#include +// interrupt(X) define. TODO: get rid of? +#include + +//template +template +class TimerIrqDispatch +{ + +public: + ALWAYS_INLINE static void handle_main() { + overflow(); + // Ack IRQ + switch (timer::irq_status()) { + // MSP headers define TAIV bits per-timer, but they are actually + // the same for all timers (hopefully for all MCUs!) + case TA0IV_TAIFG: + overflow(); + break; +#if 0 + case TA0IV_TACCR1: + if (cc1) cc1(); + break; + case TA0IV_TACCR2: + if (cc2) cc2(); + break; +#endif + } + } + + ALWAYS_INLINE static void handle_cc0() { +#if 0 + if (cc0) cc0(); +#endif + } + + // The idea would be to *define* *Timer's* irq_handler*() here (as a friend + // method). Unfortunately that's not supported by C++. So, we'll define + // irq handlers as ours, at least Timer::irq_no_* allows us to avoid duplication + // and abstract it a bit. + + // Unfortunately, this doesn't work with gcc 4.5 either + +#if 0 + static interrupt(Timer::irq_no_main) irq_handler() + { + handle_main(); + } + + static interrupt(Timer::irq_no_cc0) irq_handler_cc0() + } + if (cc0) cc0(); + } +#endif +}; + +#define irq_dispatch(timer, dispatcher) \ + template <> \ + void timer::irq_handler() \ + { dispatcher::handle_main(); } \ + template <> \ + void timer::irq_handler_cc0() \ + { dispatcher::handle_cc0(); } + + +#endif // _TIMER_MSP430_DISPATCH_HPP From 5bda747492a2756593e497edef262bfcca33092d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 17:18:51 +0300 Subject: [PATCH 47/48] irq_dispatch_msp430.hpp.old --- include/msp430/irq_dispatch_msp430.hpp.old | 126 +++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 include/msp430/irq_dispatch_msp430.hpp.old diff --git a/include/msp430/irq_dispatch_msp430.hpp.old b/include/msp430/irq_dispatch_msp430.hpp.old new file mode 100644 index 0000000..2ae535e --- /dev/null +++ b/include/msp430/irq_dispatch_msp430.hpp.old @@ -0,0 +1,126 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _IRQ_DISPATCH_MSP430_HPP +#define _IRQ_DISPATCH_MSP430_HPP + +#include +// interrupt(X) define. TODO: get rid of? +#include + +namespace PTL { + +class NullBlock +{ +public: + const static int block_type = 0; +}; + +/* + * We want to declare a function here whose body will be executed only + * when condition is true. We have to use metaprog conditionals here, + * because if condition is false, func body may not compile at all + * (for example because class it opeartes on lacks specific methods). + * So, we use 2 complementary implementations of func: one with empty + * body for case of condition == false, and one with the given body + * in case it's true. All is wrapped with macros for readability. + */ + +#define IRQ_DISPATCH_HELPER(func_name, cond) \ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(!(cond))>::type* = 0) {} \ +\ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(cond)>::type* = 0) \ + + +IRQ_DISPATCH_HELPER(do_timer_main, block::block_type == MSP430_TIMER) +{ + // Reading status also acks IRQ + switch (block::irq_status()) { + // 1. MSP headers define TAIV bits per-timer, but they are actually + // the same for all timers (hopefully for all MCUs!) + // 2. Method calls below are expected to be inlined, and if + // one is empry, entire branch to be dead-code elimated. + case TA0IV_TAIFG: + block::irq_reset(); + break; + case TA0IV_TACCR1: + block::irq_capture_compare1(); + break; + case TA0IV_TACCR2: + block::irq_capture_compare2(); + break; + } +} + +IRQ_DISPATCH_HELPER(do_timer_cc0, block::block_type == MSP430_TIMER) +{ + block::irq_capture_compare0(); +} + +IRQ_DISPATCH_HELPER(do_usci_rx, block::block_type == MSP430_USCI) +{ + uint8_t ifg2 = val; + if (block::usci::no == 'A' && (ifg2 & UCA0RXIFG)) + block::irq_rx(); + + if (block::usci::no == 'B' && (ifg2 & UCB0RXIFG)) + block::irq_rx(); +} + +IRQ_DISPATCH_HELPER(do_usci_tx, block::block_type == MSP430_USCI) +{ + uint8_t ifg2 = val; + if (block::usci::no == 'A' && (ifg2 & UCA0TXIFG)) + block::irq_tx(); + + if (block::usci::no == 'B' && (ifg2 & UCB0TXIFG)) + block::irq_tx(); +} + + +#define APPLY_TO_ALL(func, b1, b2, b3) { func(); func(); func(); } +#define APPLY_TO_ALL_ARG(func, arg, b1, b2, b3) { func(arg); func(arg); func(arg); } + +#define HANDLER(vector, dispatch_func) \ + static interrupt(vector) vector##_handler() \ + { \ + APPLY_TO_ALL(dispatch_func, b1, b2, b3); \ + } + +#define HANDLER_CACHE_REG(vector, dispatch_func, reg) \ + static interrupt(vector) vector##_handler() \ + { \ + uint8_t cache = reg; \ + APPLY_TO_ALL_ARG(dispatch_func, cache, b1, b2, b3); \ + } + +template +class IrqDispatch +{ +public: + HANDLER(TIMER0_A1_VECTOR, do_timer_main); + HANDLER(TIMER0_A0_VECTOR, do_timer_cc0); + HANDLER_CACHE_REG(USCIAB0RX_VECTOR, do_usci_rx, IFG2); + HANDLER_CACHE_REG(USCIAB0TX_VECTOR, do_usci_tx, IFG2); +}; + +} // namespace + +#endif // _IRQ_DISPATCH_MSP430_HPP From a367aee678fc77944ed024e70ae037e0f3bdb23f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 26 Oct 2013 17:31:22 +0300 Subject: [PATCH 48/48] Older versions of IRQ dispatching impls. --- include/cortex-m/irq_dispatch_cortexm_v1.hpp | 122 +++++++++++++++++ include/cortex-m/irq_dispatch_cortexm_v2.hpp | 134 +++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 include/cortex-m/irq_dispatch_cortexm_v1.hpp create mode 100644 include/cortex-m/irq_dispatch_cortexm_v2.hpp diff --git a/include/cortex-m/irq_dispatch_cortexm_v1.hpp b/include/cortex-m/irq_dispatch_cortexm_v1.hpp new file mode 100644 index 0000000..d142ee4 --- /dev/null +++ b/include/cortex-m/irq_dispatch_cortexm_v1.hpp @@ -0,0 +1,122 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _IRQ_DISPATCH_MSP430_HPP +#define _IRQ_DISPATCH_MSP430_HPP + +namespace PTL { + +class NullBlock +{ +public: + const static int block_type = 0; +}; + +/* + * We want to declare a function here whose body will be executed only + * when condition is true. We have to use metaprog conditionals here, + * because if condition is false, func body may not compile at all + * (for example because class it opeartes on lacks specific methods). + * So, we use 2 complementary implementations of func: one with empty + * body for case of condition == false, and one with the given body + * in case it's true. All is wrapped with macros for readability. + */ + +#define IRQ_DISPATCH_HELPER(func_name, cond) \ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(!(cond))>::type* = 0) {} \ +\ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(cond)>::type* = 0) \ + + +#if 0 +IRQ_DISPATCH_HELPER(do_timer_cc0, block::block_type == MSP430_TIMER) +{ + block::irq_capture_compare0(); +} + +IRQ_DISPATCH_HELPER(do_usci_rx, block::block_type == MSP430_USCI) +{ + uint8_t ifg2 = val; + if (block::usci::no == 'A' && (ifg2 & UCA0RXIFG)) + block::irq_rx(); + + if (block::usci::no == 'B' && (ifg2 & UCB0RXIFG)) + block::irq_rx(); +} + +IRQ_DISPATCH_HELPER(do_usci_tx, block::block_type == MSP430_USCI) +{ + uint8_t ifg2 = val; + if (block::usci::no == 'A' && (ifg2 & UCA0TXIFG)) + block::irq_tx(); + + if (block::usci::no == 'B' && (ifg2 & UCB0TXIFG)) + block::irq_tx(); +} +#endif + +#define APPLY_TO_ALL(func, b1, b2, b3) { func(); func(); func(); } +#define APPLY_TO_ALL_ARG(func, arg, b1, b2, b3) { func(arg); func(arg); func(arg); } + +#if 0 +#define HANDLER(vector, dispatch_func) \ + static interrupt(vector) vector##_handler() \ + { \ + APPLY_TO_ALL(dispatch_func, b1, b2, b3); \ + } + +#define HANDLER_CACHE_REG(vector, dispatch_func, reg) \ + static interrupt(vector) vector##_handler() \ + { \ + uint8_t cache = reg; \ + APPLY_TO_ALL_ARG(dispatch_func, cache, b1, b2, b3); \ + } + +template +class IrqDispatch +{ +public: + HANDLER(TIMER0_A1_VECTOR, do_timer_main); + HANDLER(TIMER0_A0_VECTOR, do_timer_cc0); + HANDLER_CACHE_REG(USCIAB0RX_VECTOR, do_usci_rx, IFG2); + HANDLER_CACHE_REG(USCIAB0TX_VECTOR, do_usci_tx, IFG2); +}; +#endif + + +#define HANDLER(vector, dispatch_func, blocks...) \ + void vector##Handler() \ + { \ + APPLY_TO_ALL(dispatch_func, blocks); \ + } + + +IRQ_DISPATCH_HELPER(do_systick, block::block_type == CORTEXM_SYSTICK) +{ + block::irq_reset(); +} + +#define IRQ_DISPATCH(blocks...) \ + HANDLER(SysTick_, do_systick, blocks); + + +} // namespace + +#endif // _IRQ_DISPATCH_MSP430_HPP diff --git a/include/cortex-m/irq_dispatch_cortexm_v2.hpp b/include/cortex-m/irq_dispatch_cortexm_v2.hpp new file mode 100644 index 0000000..28c39ef --- /dev/null +++ b/include/cortex-m/irq_dispatch_cortexm_v2.hpp @@ -0,0 +1,134 @@ +/* + * This file is part of the Peripheral Template Library project. + * + * Copyright (c) 2012-2013 Paul Sokolovsky + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#ifndef _IRQ_DISPATCH_CORTEXM_HPP +#define _IRQ_DISPATCH_CORTEXM_HPP + +namespace PTL { + +class NullBlock +{ +public: + const static int block_type = 0; +}; + +/** + ** Device-independent helper macros for interrupt dispatching + **/ + +/* + * We want to declare a function whose body will be executed only + * when (static) condition is true. We have to use metaprog conditionals + * here, because if condition is false, func body may not compile at all + * (for example because class it opeartes on lacks specific methods). + * So, we use 2 complementary implementations of func: one with empty + * body for case of condition == false, and one with the given body + * in case it's true. All is wrapped with macros for readability. + */ + +#define IRQ_DISPATCH_HELPER(func_name, cond) \ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(!(cond))>::type* = 0) {} \ +\ +template \ +inline void func_name(uint8_t val = 0, typename meta::enable_if<(cond)>::type* = 0) \ + +/* Apply templated function to list of template args. Note: this and other similar + funcs depend on particular number of arguments passed and must be updated to + pass more. */ +#define APPLY_TO_ALL(func, b1, b2, b3) { func(); func(); func(); } +/* Apply templated function to list of template args, also passing (runtime) argument + to a function. */ +#define APPLY_TO_ALL_ARG(func, arg, b1, b2, b3) { func(arg); func(arg); func(arg); } + +/* Define handler function for particular hardware IRQ. */ +#define HANDLER(vector, dispatch_func) \ + static void vector##Handler() \ + { \ + APPLY_TO_ALL(dispatch_func, b1, b2, b3); \ + } + +/* Define handler function for particular hardware IRQ, caching value + of a register allowing to demux multiplexed IRQs. This cached value + is passed to each PTL handler. */ +#define HANDLER_CACHE_REG(vector, dispatch_func, reg) \ + static void vector##Handler() \ + { \ + uint8_t cache = reg; \ + APPLY_TO_ALL_ARG(dispatch_func, cache, b1, b2, b3); \ + } + +/** + ** Device-specific classes and macros for interrupt dispatching + **/ + +/* Dispatch IRQ from MCU and compiler specific "IRQ vector" function. This + is expected to be fully optimized out by inlining. + What to change: name/attributes of function defined. */ +#define CALL_HANDLER(dispatcher, vector) \ + void vector##Handler() \ + { \ + dispatcher::vector##Handler(); \ + } + +/* Implementation of function which will dispatch harware IRQ to all + blocks which have corresponding PTL handler. + What to change: name, condition, implementation. */ +IRQ_DISPATCH_HELPER(do_systick, block::block_type == CORTEXM_SYSTICK) +{ + block::irq_reset(); +} + +/* Main IRQ dispatching class. User needs to instantiate this per + application needs (using explicit template instantiation). */ +template +class IrqDispatch +{ +public: + HANDLER(SysTick_, do_systick); +}; + +/* Macros to dispatch from MCU/compiler specific "IRQ vector function" + to IrqDispatch class. The latter should be passed in as a param. */ +#define IRQ_DISPATCH(dispatcher) \ + CALL_HANDLER(dispatcher, SysTick_); + +/* Usage example: */ +#if 0 + +class mytimer : public timer +{ +public: + void irq_reset() + { + // Do something + } +}; + +// Don't Repeat Yourself, and explicit template instantiation cannot +// be applied to a typedef name, so user old trusty defines. +#define irq_dispatch IrqDispatch +template class irq_dispatch; +IRQ_DISPATCH(irq_dispatch); + +#endif + + +} // namespace + +#endif // _IRQ_DISPATCH_CORTEXM_HPP