From b1a276a15faaf6b4b74769021857850e818156b7 Mon Sep 17 00:00:00 2001 From: Leo C Date: Wed, 19 Apr 2017 12:55:02 +0200 Subject: [PATCH 1/1] Inital commit --- Makefile | 34 ++++ config.h | 15 ++ irmp-main.c | 368 +++++++++++++++++++++++++++++++++++++++++++ libopencm3.rules.mk | 276 ++++++++++++++++++++++++++++++++ libopencm3.target.mk | 44 ++++++ serial.c | 224 ++++++++++++++++++++++++++ serial.h | 15 ++ timer.c | 44 ++++++ timer.h | 15 ++ 9 files changed, 1035 insertions(+) create mode 100644 Makefile create mode 100644 config.h create mode 100644 irmp-main.c create mode 100644 libopencm3.rules.mk create mode 100644 libopencm3.target.mk create mode 100644 serial.c create mode 100644 serial.h create mode 100644 timer.c create mode 100644 timer.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7de5646 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## 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 . +## + +DEFS += -DUSE_OPENCM3_API=0 #-DCON_BAUDRATE=38400 +DEFS += -DDEBUG_IRMP_TIMER_INT=1 + +BINARY = irmp-main +OBJS += serial.o timer.o + +IRMP_DIR = irmp +OBJS += $(IRMP_DIR)/irmp.o +DEFS += -I$(IRMP_DIR) +DEFS += -DF_INTERRUPTS=15000 -DIRMP_PROTOCOL_NAMES=1 + +DEVICE = stm32f103c8t6 +OPENCM3_DIR = libopencm3 + +include libopencm3.target.mk diff --git a/config.h b/config.h new file mode 100644 index 0000000..7df9d9a --- /dev/null +++ b/config.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include + +#define USART_CONSOLE 1 +#ifndef CON_BAUDRATE +#define CON_BAUDRATE 38400 +#endif + +#define LED_PORT GPIOC +#define LED_PIN GPIO13 +#define RCC_LED_PORT RCC_GPIOC + +#endif /* CONFIG_H */ diff --git a/irmp-main.c b/irmp-main.c new file mode 100644 index 0000000..51b2e1d --- /dev/null +++ b/irmp-main.c @@ -0,0 +1,368 @@ +/*--------------------------------------------------------------------------------------------------------------------------------------------------- + * irmp-main-stm32.c - demo main module to test IRMP decoder on STM32 + * + * Copyright (c) 2009-2016 Frank Meyer - frank(at)fli4l.de + * + * $Id: irmp-main-stm32.c,v 1.2 2016/01/12 21:15:16 fm Exp $ + * + * This demo module is runnable on STM32 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *--------------------------------------------------------------------------------------------------------------------------------------------------- + */ + +#include "config.h" +#include "timer.h" +#include "serial.h" +#include "irmp.h" +#include +#include +#include + +#ifndef USE_OPENCM3_API +#define USE_OPENCM3_API 1 +#endif + +#ifndef DEBUG_IRMP_TIMER_INT +#define DEBUG_IRMP_TIMER_INT 0 +#endif + +static void setup_clock_and_gpios(void) +{ + /* Clock setup */ + /* Default clock is 8MHz HSI */ + //rcc_clock_setup_in_hse_8mhz_out_24mhz(); + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + /* GPIO setup */ + /* Only the on board led is configured here */ + + rcc_periph_clock_enable(RCC_LED_PORT); + + /* Set GPIO13 (in GPIO port C) to 'output push-pull'. */ + /* Manually: */ + // GPIOC_CRH = (GPIO_CNF_OUTPUT_PUSHPULL << (((12 - 8) * 4) + 2)); + // GPIOC_CRH |= (GPIO_MODE_OUTPUT_2_MHZ << ((12 - 8) * 4)); + /* Using API functions: */ + gpio_set(LED_PORT, LED_PIN); /* set output register high (led off) */ + gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); +} + +/*--------------------------------------------------------------------------*/ +/* IRMP */ +/*--------------------------------------------------------------------------*/ + +#define TIM_IRMP_CR1 TIM_CR1(TIM_IRMP) +#define TIM_IRMP_DIER TIM_DIER(TIM_IRMP) +#define TIM_IRMP_SR TIM_SR(TIM_IRMP) +#define TIM_IRMP_ARR TIM_ARR(TIM_IRMP) +#define RCC_TIM_IRMP CONCAT(RCC_TIM, IRMP_TIMER) +#define NVIC_TIM_IRMP_IRQ CONCAT(CONCAT(NVIC_TIM, IRMP_TIMER), _IRQ) +#define IRMP_TIMER_ISR CONCAT(CONCAT(tim, IRMP_TIMER), _isr) + + +uint32_t timer_internal_clock_get(uint32_t timer_peripheral) +{ + uint32_t timer_frequency; + uint32_t ppre; + + /* Get preripheral bus frequency and prescaler mask */ + if (timer_peripheral == TIM1 || timer_peripheral == TIM8) { + /* Advanced timers TIM1 and TIM8 are on APB2 */ + ppre = RCC_CFGR_PPRE2; + timer_frequency = rcc_apb2_frequency; + } else { + /* Other timers are on APB1 */ + ppre = RCC_CFGR_PPRE1; + timer_frequency = rcc_apb1_frequency; + } + /* Timer clock is doubled, if the APB prescaler is greater than 1 */ + if ((RCC_CFGR & ppre) != 0) + timer_frequency *= 2; + + return timer_frequency; +} + +void irmp_timer_init (void) +{ +#if DEBUG_IRMP_TIMER_INT + /* Output pin for debugging */ + rcc_periph_clock_enable(RCC_GPIOA); + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO2); +#endif + /* Enable timer clock. */ + rcc_periph_clock_enable(RCC_TIM_IRMP); + nvic_set_priority(NVIC_TIM_IRMP_IRQ, 4*16); + nvic_enable_irq(NVIC_TIM_IRMP_IRQ); + +#if USE_OPENCM3_API /* Using API functions: */ + + /* Timer global mode: + * - No divider + * - Alignment edge + * - Direction up + * (These are actually default values after reset, so this call + * is strictly unnecessary, but demos the api for alternative settings) + */ + timer_set_mode(TIM_IRMP, TIM_CR1_CKD_CK_INT, + TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_set_period(TIM_IRMP, timer_internal_clock_get(TIM_IRMP) / F_INTERRUPTS); + /* Enable Channel 1 compare interrupt to recalculate compare values */ + timer_enable_irq(TIM_IRMP, TIM_DIER_UIE); + /* Counter enable. */ + timer_enable_counter(TIM_IRMP); + +#else /* Manually */ + + TIM_IRMP_CR1 = TIM_CR1_CKD_CK_INT | TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP; + TIM_IRMP_ARR = timer_internal_clock_get(TIM_IRMP) / F_INTERRUPTS; + + /* Enable Timer interrupt and timer */ + TIM_IRMP_DIER = TIM_DIER_UIE; + TIM_IRMP_CR1 |= TIM_CR1_CEN; + +#endif +} + +void IRMP_TIMER_ISR(void) +{ +#if DEBUG_IRMP_TIMER_INT +# if USE_OPENCM3_API /* Using API functions: */ + + gpio_clear(GPIOA, GPIO2); + /* Clear update interrupt flag. */ + timer_clear_flag(TIM_IRMP, TIM_SR_UIF); +# else /* Manually */ + GPIO_BRR(GPIOA) = GPIO2; +# endif +#endif + /* Clear update interrupt flag. */ + TIM_IRMP_SR = ~TIM_SR_UIF; + + (void) irmp_ISR(); // call irmp ISR + + // call other timer interrupt routines... + +#if DEBUG_IRMP_TIMER_INT +# if USE_OPENCM3_API /* Using API functions: */ + gpio_set(GPIOA, GPIO2); +# else /* Manually */ + GPIO_BSRR(GPIOA) = GPIO2; +# endif +#endif +} + +/*--------------------------------------------------------------------------*/ + +int irmp_protocol_is_supported(int proto) +{ +#if IRMP_SUPPORT_SIRCS_PROTOCOL + if (proto == IRMP_SIRCS_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NEC_PROTOCOL + if (proto == IRMP_NEC_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_SAMSUNG_PROTOCOL + if (proto == IRMP_SAMSUNG_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_KASEIKYO_PROTOCOL + if (proto == IRMP_KASEIKYO_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_JVC_PROTOCOL + if (proto == IRMP_JVC_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NEC16_PROTOCOL + if (proto == IRMP_NEC16_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NEC42_PROTOCOL + if (proto == IRMP_NEC42_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_MATSUSHITA_PROTOCOL + if (proto == IRMP_MATSUSHITA_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_DENON_PROTOCOL + if (proto == IRMP_DENON_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RC5_PROTOCOL + if (proto == IRMP_RC5_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RC6_PROTOCOL + if (proto == IRMP_RC6_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_IR60_PROTOCOL + if (proto == IRMP_IR60_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_GRUNDIG_PROTOCOL + if (proto == IRMP_GRUNDIG_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_SIEMENS_PROTOCOL + if (proto == IRMP_SIEMENS_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NOKIA_PROTOCOL + if (proto == IRMP_NOKIA_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_BOSE_PROTOCOL + if (proto == IRMP_BOSE_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_KATHREIN_PROTOCOL + if (proto == IRMP_KATHREIN_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NUBERT_PROTOCOL + if (proto == IRMP_NUBERT_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_FAN_PROTOCOL + if (proto == IRMP_FAN_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_SPEAKER_PROTOCOL + if (proto == IRMP_SPEAKER_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_BANG_OLUFSEN_PROTOCOL + if (proto == IRMP_BANG_OLUFSEN_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RECS80_PROTOCOL + if (proto == IRMP_RECS80_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RECS80EXT_PROTOCOL + if (proto == IRMP_RECS80EXT_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_THOMSON_PROTOCOL + if (proto == IRMP_THOMSON_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NIKON_PROTOCOL + if (proto == IRMP_NIKON_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_NETBOX_PROTOCOL + if (proto == IRMP_NETBOX_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_ORTEK_PROTOCOL + if (proto == IRMP_ORTEK_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_TELEFUNKEN_PROTOCOL + if (proto == IRMP_TELEFUNKEN_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_FDC_PROTOCOL + if (proto == IRMP_FDC_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RCCAR_PROTOCOL + if (proto == IRMP_RCCAR_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_ROOMBA_PROTOCOL + if (proto == IRMP_ROOMBA_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RUWIDO_PROTOCOL + if (proto == IRMP_RUWIDO_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_A1TVBOX_PROTOCOL + if (proto == IRMP_A1TVBOX_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_LEGO_PROTOCOL + if (proto == IRMP_LEGO_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RCMM_PROTOCOL + if (proto == IRMP_RCMM_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_LGAIR_PROTOCOL + if (proto == IRMP_LGAIR_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_SAMSUNG48_PROTOCOL + if (proto == IRMP_SAMSUNG48_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_MERLIN_PROTOCOL + if (proto == IRMP_MERLIN_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_PENTAX_PROTOCOL + if (proto == IRMP_PENTAX_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_S100_PROTOCOL + if (proto == IRMP_S100_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_ACP24_PROTOCOL + if (proto == IRMP_ACP24_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_TECHNICS_PROTOCOL + if (proto == IRMP_TECHNICS_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_PANASONIC_PROTOCOL + if (proto == IRMP_PANASONIC_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_MITSU_HEAVY_PROTOCOL + if (proto == IRMP_MITSU_HEAVY_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_VINCENT_PROTOCOL + if (proto == IRMP_VINCENT_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_SAMSUNGAH_PROTOCOL + if (proto == IRMP_SAMSUNGAH_PROTOCOL) return 1; +#endif +#if IRMP_SUPPORT_RADIO1_PROTOCOL + if (proto == IRMP_RADIO1_PROTOCOL) return 1; +#endif + + return 0; +} + +void print_supported_protocols(void) +{ + printf("Supported IR protocols:"); + for (int i = 0; i <= IRMP_N_PROTOCOLS; i++) { + if (irmp_protocol_is_supported(i)) { +#if IRMP_PROTOCOL_NAMES == 1 + printf(" %s", irmp_protocol_names[i]); +#else + printf(" %d", i); +#endif + } + } + printf("\n"); +} + +/*--------------------------------------------------------------------------*/ + +void led_blink(void) +{ + static uint32_t ts; + + if (get_timer(ts) >= 500) { + ts = get_timer(0); + gpio_toggle(LED_PORT, LED_PIN); + } +} + +int main (void) +{ + IRMP_DATA irmp_data; + + setup_clock_and_gpios(); + setvbuf(stdout, NULL, _IONBF, 0); + serial_setup(CON_BAUDRATE); + + printf("\nIRMP on STM32F103 with libopencm3 demo\n" + " System frequency: %luHz\n" + "IRMP timer input frequency (CK_INT): %luHz\n" + " IRMP interrupt frequency: %uHz\n", + rcc_ahb_frequency, timer_internal_clock_get(TIM_IRMP), F_INTERRUPTS); + + systick_setup(); + irmp_timer_init(); // initialize timer for irmp + irmp_init(); // initialize irmp + + print_supported_protocols(); + for (;;) + { + led_blink(); + if (irmp_get_data (&irmp_data)) + { + printf("protocol: 0x%.2x", irmp_data.protocol); +#if IRMP_PROTOCOL_NAMES == 1 + printf(" %-11s", irmp_protocol_names[irmp_data.protocol]); +#endif + printf(" adress: 0x%.4x command: 0x%.4x flags: 0x%.2x\n", + irmp_data.address, irmp_data.command, irmp_data.flags); + } + } +} diff --git a/libopencm3.rules.mk b/libopencm3.rules.mk new file mode 100644 index 0000000..0a6171a --- /dev/null +++ b/libopencm3.rules.mk @@ -0,0 +1,276 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## Copyright (C) 2013 Frantisek Burian +## +## 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 . +## + +# Be silent per default, but 'make V=1' will show all compiler calls. +ifneq ($(V),1) +Q := @ +NULL := 2>/dev/null +endif + +############################################################################### +# Executables + +PREFIX ?= arm-none-eabi + +CC := $(PREFIX)-gcc +CXX := $(PREFIX)-g++ +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +SIZE := $(PREFIX)-size +GDB := $(PREFIX)-gdb +STFLASH = $(shell which st-flash) +STYLECHECK := /checkpatch.pl +STYLECHECKFLAGS := --no-tree -f --terse --mailback +STYLECHECKFILES := $(shell find . -name '*.[ch]') +OPT := -Os +CSTD ?= -std=c99 + + +############################################################################### +# Source files + +OBJS += $(BINARY).o + + +ifeq ($(strip $(OPENCM3_DIR)),) +# user has not specified the library path, so we try to detect it + +# where we search for the library +LIBPATHS := ./libopencm3 ../../../../libopencm3 ../../../../../libopencm3 + +OPENCM3_DIR := $(wildcard $(LIBPATHS:=/locm3.sublime-project)) +OPENCM3_DIR := $(firstword $(dir $(OPENCM3_DIR))) + +ifeq ($(strip $(OPENCM3_DIR)),) +$(warning Cannot find libopencm3 library in the standard search paths.) +$(error Please specify it through OPENCM3_DIR variable!) +endif +endif + +ifeq ($(V),1) +$(info Using $(OPENCM3_DIR) path to library) +endif + +define ERR_DEVICE_LDSCRIPT_CONFLICT +You can either specify DEVICE=blah, and have the LDSCRIPT generated, +or you can provide LDSCRIPT, and ensure CPPFLAGS, LDFLAGS and LDLIBS +all contain the correct values for the target you wish to use. +You cannot provide both! +endef + +ifeq ($(strip $(DEVICE)),) +# Old style, assume LDSCRIPT exists +DEFS += -I$(OPENCM3_DIR)/include +LDFLAGS += -L$(OPENCM3_DIR)/lib +LDLIBS += -l$(LIBNAME) +LDSCRIPT ?= $(BINARY).ld +else +# New style, assume device is provided, and we're generating the rest. +ifneq ($(strip $(LDSCRIPT)),) +$(error $(ERR_DEVICE_LDSCRIPT_CONFLICT)) +endif +include $(OPENCM3_DIR)/mk/genlink-config.mk +endif + +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +############################################################################### +# C flags + +TGT_CFLAGS += $(OPT) $(CSTD) -g +TGT_CFLAGS += $(ARCH_FLAGS) +TGT_CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration +TGT_CFLAGS += -Wredundant-decls -Wstrict-prototypes +TGT_CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C++ flags + +TGT_CXXFLAGS += $(OPT) $(CXXSTD) -g +TGT_CXXFLAGS += $(ARCH_FLAGS) +TGT_CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++ +TGT_CXXFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C & C++ preprocessor common flags + +TGT_CPPFLAGS += -MD +TGT_CPPFLAGS += -Wall -Wundef +TGT_CPPFLAGS += $(DEFS) + +############################################################################### +# Linker flags + +TGT_LDFLAGS += --static -nostartfiles --specs=nano.specs +TGT_LDFLAGS += -T$(LDSCRIPT) +TGT_LDFLAGS += $(ARCH_FLAGS) +TGT_LDFLAGS += -Wl,-Map=$(*).map +TGT_LDFLAGS += -Wl,--gc-sections +ifeq ($(V),99) +TGT_LDFLAGS += -Wl,--print-gc-sections +endif + +############################################################################### +# Used libraries + +LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group + +############################################################################### +############################################################################### +############################################################################### + +.SUFFIXES: .elf .bin .hex .srec .list .map .images +.SECONDEXPANSION: +.SECONDARY: + +all: elf + +elf: $(BINARY).elf +bin: $(BINARY).bin +hex: $(BINARY).hex +srec: $(BINARY).srec +list: $(BINARY).list +size: $(BINARY).size + +images: $(BINARY).images +flash: $(BINARY).stlink-flash + +# Either verify the user provided LDSCRIPT exists, or generate it. +ifeq ($(strip $(DEVICE)),) +$(LDSCRIPT): + ifeq (,$(wildcard $(LDSCRIPT))) + $(error Unable to find specified linker script: $(LDSCRIPT)) + endif +else +include $(OPENCM3_DIR)/mk/genlink-rules.mk +endif + +# Define a helper macro for debugging make errors online +# you can type "make print-OPENCM3_DIR" and it will show you +# how that ended up being resolved by all of the included +# makefiles. +print-%: + @echo $*=$($*) + +%.images: %.bin %.hex %.srec %.list %.map + @#printf "*** $* images generated ***\n" + +%.bin: %.elf + @#printf " OBJCOPY $(*).bin\n" + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + +%.hex: %.elf + @#printf " OBJCOPY $(*).hex\n" + $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex + +%.srec: %.elf + @#printf " OBJCOPY $(*).srec\n" + $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec + +%.list: %.elf + @#printf " OBJDUMP $(*).list\n" + $(Q)$(OBJDUMP) -S $(*).elf > $(*).list + +%.elf %.map: $(OBJS) $(LDSCRIPT) + @#printf " LD $(*).elf\n" + $(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(*).elf + +%.o: %.c + @#printf " CC $(*).c\n" + $(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).c + +%.o: %.cxx + @#printf " CXX $(*).cxx\n" + $(Q)$(CXX) $(TGT_CXXFLAGS) $(CXXFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).cxx + +%.o: %.cpp + @#printf " CXX $(*).cpp\n" + $(Q)$(CXX) $(TGT_CXXFLAGS) $(CXXFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).cpp + +clean: + @#printf " CLEAN\n" + $(Q)$(RM) *.o *.d *.elf *.bin *.hex *.srec *.list *.map generated.* ${OBJS} ${OBJS:%.o=%.d} + +%.size: %.elf + @#printf " SIZE $(*).elf\n" + $(Q)$(SIZE) $(*).elf + +stylecheck: $(STYLECHECKFILES:=.stylecheck) +styleclean: $(STYLECHECKFILES:=.styleclean) + +# the cat is due to multithreaded nature - we like to have consistent chunks of text on the output +%.stylecheck: % + $(Q)$(SCRIPT_DIR)$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \ + if [ -s $*.stylecheck ]; then \ + cat $*.stylecheck; \ + else \ + rm -f $*.stylecheck; \ + fi; + +%.styleclean: + $(Q)rm -f $*.stylecheck; + + +%.stlink-flash: %.bin + @printf " FLASH $<\n" + $(STFLASH) write $(*).bin 0x8000000 + +ifeq ($(STLINK_PORT),) +ifeq ($(BMP_PORT),) +ifeq ($(OOCD_FILE),) +%.flash: %.elf + @printf " FLASH $<\n" + (echo "halt; program $(realpath $(*).elf) verify reset" | nc -4 localhost 4444 2>/dev/null) || \ + $(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ + -f target/$(OOCD_TARGET).cfg \ + -c "program $(*).elf verify reset exit" \ + $(NULL) +else +%.flash: %.elf + @printf " FLASH $<\n" + (echo "halt; program $(realpath $(*).elf) verify reset" | nc -4 localhost 4444 2>/dev/null) || \ + $(OOCD) -f $(OOCD_FILE) \ + -c "program $(*).elf verify reset exit" \ + $(NULL) +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(GDB) --batch \ + -ex 'target extended-remote $(BMP_PORT)' \ + -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \ + $(*).elf +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(GDB) --batch \ + -ex 'target extended-remote $(STLINK_PORT)' \ + -x $(SCRIPT_DIR)/stlink_flash.scr \ + $(*).elf +endif + +.PHONY: images clean stylecheck styleclean elf bin hex srec list size + +-include $(OBJS:.o=.d) diff --git a/libopencm3.target.mk b/libopencm3.target.mk new file mode 100644 index 0000000..af4fc20 --- /dev/null +++ b/libopencm3.target.mk @@ -0,0 +1,44 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## +## 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 . +## + +LIBNAME = opencm3_stm32f1 +DEFS += -DSTM32F1 + +FP_FLAGS ?= -msoft-float +ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd + +################################################################################ +# OpenOCD specific variables + +OOCD ?= openocd +OOCD_INTERFACE ?= flossjtag +OOCD_TARGET ?= stm32f1x + +################################################################################ +# Black Magic Probe specific variables +# Set the BMP_PORT to a serial port and then BMP is used for flashing +BMP_PORT ?= + +################################################################################ +# texane/stlink specific variables +#STLINK_PORT ?= :4242 + + +include libopencm3.rules.mk diff --git a/serial.c b/serial.c new file mode 100644 index 0000000..60a328c --- /dev/null +++ b/serial.c @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "serial.h" +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + +#if (USART_CONSOLE == 1) +#define CON_PORT A +#define CON_GPIO GPIOA +#elif (USART_CONSOLE == 2) +#define CON_PORT A +#define CON_GPIO GPIOA +#elif (USART_CONSOLE == 3) +#define CON_PORT B +#define CON_GPIO GPIOB +#else +#error USART_CONSOLE undefined or invalid value +#endif + +#define CONCAT2(a,b) a##b +#define CONCAT(a,b) CONCAT2(a,b) + + +#define CON_USART CONCAT(USART,USART_CONSOLE) +#define CON_IRQ CONCAT(CONCAT(NVIC_USART, USART_CONSOLE), _IRQ) +#define CON_isr CONCAT(CONCAT(usart, USART_CONSOLE), _isr) +#define CON_GPIO_RX CONCAT(CONCAT(GPIO_USART, USART_CONSOLE), _RX) +#define CON_GPIO_TX CONCAT(CONCAT(GPIO_USART, USART_CONSOLE), _TX) +#define RCC_USART_CON CONCAT(RCC_USART, USART_CONSOLE) +#define RCC_GPIO_CON CONCAT(RCC_GPIO, CON_PORT) + + +int _write(int fd, char *ptr, int len) __attribute__((used)); + + +struct ring { + uint8_t *data; + int size; + volatile int begin; + volatile int end; +}; + + +#define BUFFER_SIZE 256 + +struct ring rx_ring; +struct ring tx_ring; +uint8_t rx_ring_buffer[BUFFER_SIZE]; +uint8_t tx_ring_buffer[BUFFER_SIZE]; + + +static void ring_init(struct ring *ring, uint8_t *buf, int size) +{ + ring->data = buf; + ring->size = size; + ring->begin = 0; + ring->end = 0; +} + +static int ring_write_ch(struct ring *ring, uint8_t ch) +{ + int ep = (ring->end + 1) % ring->size; + + if ((ep) != ring->begin) { + ring->data[ring->end] = ch; + ring->end = ep; + return 1; + } + + return -1; +} + +#if 0 /* unused */ +static int ring_write(struct ring *ring, uint8_t *data, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (ring_write_ch(ring, data[i]) < 0) + return -i; + } + + return i; +} +#endif + +static int ring_read_ch(struct ring *ring) +{ + int ret = -1; + + if (ring->begin != ring->end) { + ret = ring->data[ring->begin]; + ring->begin = (ring->begin +1) % ring->size; + } + + return ret; +} + +void usart_setup(int baud) +{ + /* Initialize output ring buffer. */ + ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE); + ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE); + + rcc_periph_clock_enable(RCC_USART_CON); + + /* Enable the USART_CONSOLE interrupt. */ + nvic_enable_irq(CON_IRQ); + nvic_set_priority(CON_IRQ, 6*16); + + /* Setup GPIO pins for CONSOLE TX/RX */ + rcc_periph_clock_enable(RCC_GPIO_CON); + gpio_set_mode(CON_GPIO, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, CON_GPIO_TX); + gpio_set_mode(CON_GPIO, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, CON_GPIO_RX); + + /* Setup UART parameters. */ + usart_set_baudrate(CON_USART, baud); + usart_set_databits(CON_USART, 8); + usart_set_stopbits(CON_USART, USART_STOPBITS_1); + usart_set_parity(CON_USART, USART_PARITY_NONE); + usart_set_flow_control(CON_USART, USART_FLOWCONTROL_NONE); + usart_set_mode(CON_USART, USART_MODE_TX_RX); + + /* Enable CONSOLE Receive interrupt. */ + USART_CR1(CON_USART) |= USART_CR1_RXNEIE; + + /* Finally enable the USART. */ + usart_enable(CON_USART); +} + + +void CON_isr(void) +{ + /* Check if we were called because of RXNE. */ + if (((USART_CR1(CON_USART) & USART_CR1_RXNEIE) != 0) && + ((USART_SR(CON_USART) & USART_SR_RXNE) != 0)) { + + /* Retrieve the data from the peripheral. */ + ring_write_ch(&rx_ring, USART_DR(CON_USART) & USART_DR_MASK); + + } + + /* Check if we were called because of TXE. */ + if (((USART_CR1(CON_USART) & USART_CR1_TXEIE) != 0) && + ((USART_SR(CON_USART) & USART_SR_TXE) != 0)) { + + int data; + + data = ring_read_ch(&tx_ring); + + if (data == -1) { + /* Disable the TXE interrupt, it's no longer needed. */ + USART_CR1(CON_USART) &= ~USART_CR1_TXEIE; + } else { + /* Put data into the transmit register. */ + usart_send(CON_USART, data); + } + } +} + +/*--------------------------------------------------------------------------*/ + +void serial_setup(int baud) +{ + usart_setup(baud); +} + +void serial_setbaudrate(int baud) +{ + usart_set_baudrate(CON_USART, baud); +} + +/*--------------------------------------------------------------------------*/ + +/** + * Use USART_CONSOLE as a console. + * This is a syscall for newlib + * @param fd + * @param ptr + * @param len + * @return + */ +int _write(int fd, char *ptr, int len) +{ + int i; + + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { + for (i = 0; i < len; i++) { + if (ptr[i] == '\n') { + serial_putc('\r'); + } + serial_putc(ptr[i]); + } + return i; + } + errno = EIO; + return -1; +} + +int serial_getc(void) +{ + return ring_read_ch(&rx_ring); +} + +void serial_putc(int data) +{ + while (ring_write_ch(&tx_ring, data) < 0) + ; + + /* Enable the TXE interrupt. */ + USART_CR1(CON_USART) |= USART_CR1_TXEIE; +} diff --git a/serial.h b/serial.h new file mode 100644 index 0000000..eae576f --- /dev/null +++ b/serial.h @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef SERIAL_H +#define SERIAL_H + +void serial_setup(int baud); +void serial_setbaudrate(int baud); +void serial_putc(int ch); +int serial_getc(void); + +#endif /* SERIAL_H */ diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..58a4d2f --- /dev/null +++ b/timer.c @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2017 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "timer.h" +#include +#include +#include +#include + + +/* timer interrupt/overflow counter */ +/* counts up every ms. */ +static volatile +uint32_t timestamp; + +void systick_setup(void) +{ + /* SysTick interrupt every N clock pulses: set reload to N-1 */ + STK_RVR = rcc_ahb_frequency/1000 - 1; + + /* Set source to core clock, enable int and start counting. */ + STK_CSR = STK_CSR_CLKSOURCE_AHB | STK_CSR_TICKINT | STK_CSR_ENABLE; +} + +/*--------------------------------------------------------------------------*/ + +/* + * + * 1000Hz timer interrupt generated by System Timer + */ +void sys_tick_handler(void) +{ + ++timestamp; +} + +/*--------------------------------------------------------------------------*/ + +uint32_t get_timer(uint32_t base) +{ + return timestamp - base; +} diff --git a/timer.h b/timer.h new file mode 100644 index 0000000..b6bc785 --- /dev/null +++ b/timer.h @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2017 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef TIMER_H +#define TIMER_H + +#include + +void systick_setup(void); +uint32_t get_timer(uint32_t); + +#endif /* TIMER_H */ -- 2.39.2