From 4a5027b18b3fa5c44951b7cb51f5ca57a103acf8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 7 Nov 2016 20:09:35 +0000 Subject: [PATCH] Add the STM32F CPU support. --- Config.h | 2 +- Globals.h | 22 +- IOSTM.cpp | 353 ++++++++++++++++++++++++++++ MMDVM.cpp | 2 +- MMDVM_STM32F4xx.cogui | 485 +++++++++++++++++++++++++++++++++++++++ MMDVM_STM32F4xx.comarker | 23 ++ MMDVM_STM32F4xx.coproj | 186 +++++++++++++++ Makefile | 104 +++++++++ README.md | 4 +- RSSIRB.h | 5 + SampleRB.h | 5 + SerialRB.h | 5 + SerialSTM.cpp | 464 +++++++++++++++++++++++++++++++++++++ Utils.h | 7 +- stm32_flash.ld | 170 ++++++++++++++ 15 files changed, 1830 insertions(+), 7 deletions(-) create mode 100644 IOSTM.cpp create mode 100644 MMDVM_STM32F4xx.cogui create mode 100644 MMDVM_STM32F4xx.comarker create mode 100644 MMDVM_STM32F4xx.coproj create mode 100644 Makefile create mode 100644 SerialSTM.cpp create mode 100644 stm32_flash.ld diff --git a/Config.h b/Config.h index 3eb0ed4..156e850 100644 --- a/Config.h +++ b/Config.h @@ -27,7 +27,7 @@ // Frequencies such as 10.0 Mhz (48000 * 208.333) or 20 Mhz (48000 * 416.666) are not suitable. // // For 12 MHz -// #define EXTERNAL_OSC 12000000 +#define EXTERNAL_OSC 12000000 // For 12.288 MHz // #define EXTERNAL_OSC 12288000 // For 14.4 MHz diff --git a/Globals.h b/Globals.h index 8f3d22e..807417e 100644 --- a/Globals.h +++ b/Globals.h @@ -19,16 +19,34 @@ #if !defined(GLOBALS_H) #define GLOBALS_H +#if defined(STM32F4XX) || defined(STM32F4) +#include "stm32f4xx.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_rcc.h" +#include "stm32f4xx_dac.h" +#include "stm32f4xx_adc.h" +#include "stm32f4xx_tim.h" +#include "stm32f4xx_usart.h" +#include "misc.h" +#include +#include +#else #include +#endif -#if defined(__SAM3X8E__) || defined(__STM32F1__) || defined(__STM32F2__) +#if defined(__SAM3X8E__) #define ARM_MATH_CM3 -#elif defined(__STM32F3__) || defined(__STM32F4__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) +#elif defined(STM32F4XX) || defined(STM32F4) || defined(__MK20DX256__) || defined(__MK66FX1M0__) #define ARM_MATH_CM4 #else #error "Unknown processor type" #endif + +#if defined(STM32F4XX) || defined(STM32F4) +#include "cmsis.h" +#else #include +#endif enum MMDVM_STATE { STATE_IDLE = 0, diff --git a/IOSTM.cpp b/IOSTM.cpp new file mode 100644 index 0000000..1388367 --- /dev/null +++ b/IOSTM.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2016 by Jim McLaughlin KI6ZUM + * Copyright (C) 2016 by Andy Uribe CA6JAU + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" +#include "IO.h" + +#if defined(STM32F4XX) || defined(STM32F4) + +/* +Pin definitions: + +PTT PD8 output +COSLED PA7 output +LED PD15 output +COS PA5 input +ADC1 PA0 analog input +ADC2 PA1 analog input +DAC1 PA4 analog output + +DSTAR PD12 output +DMR PD13 output +YSF PD14 output +P25 PD11 output +*/ + +#define PIN_COS GPIO_Pin_5 +#define PORT_COS GPIOA +#define PIN_PTT GPIO_Pin_8 +#define PORT_PTT GPIOD +#define PIN_COSLED GPIO_Pin_7 +#define PORT_COSLED GPIOA +#define PIN_LED GPIO_Pin_15 +#define PORT_LED GPIOD +#define PIN_ADC GPIO_Pin_0 +#define PORT_ADC GPIOA +#define PIN_DAC GPIO_Pin_4 +#define PORT_DAC GPIOA + +#define PIN_P25 GPIO_Pin_11 +#define PORT_P25 GPIOD +#define PIN_DSTAR GPIO_Pin_12 +#define PORT_DSTAR GPIOD +#define PIN_DMR GPIO_Pin_13 +#define PORT_DMR GPIOD +#define PIN_YSF GPIO_Pin_14 +#define PORT_YSF GPIOD + +const uint16_t DC_OFFSET = 2048U; + +extern "C" { + void TIM2_IRQHandler() { + if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { + TIM_ClearITPendingBit(TIM2, TIM_IT_Update); + io.interrupt(); + } + } +} + +void CIO::initInt() +{ + GPIO_InitTypeDef GPIO_InitStruct; + + // PTT pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_PTT; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_PTT, &GPIO_InitStruct); + + // COSLED pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_COSLED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_COSLED, &GPIO_InitStruct); + + // LED pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_LED, &GPIO_InitStruct); + + // Init the input pins PIN_COS + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_COS; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(PORT_COS, &GPIO_InitStruct); + + // DSTAR pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_DSTAR; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_DSTAR, &GPIO_InitStruct); + + // DMR pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_DMR; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_DMR, &GPIO_InitStruct); + + // YSF pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_YSF; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_YSF, &GPIO_InitStruct); + + // P25 pin + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + GPIO_StructInit(&GPIO_InitStruct); + GPIO_InitStruct.GPIO_Pin = PIN_P25; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_Init(PORT_P25, &GPIO_InitStruct); +} + +void CIO::startInt() +{ + if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET)) + io.interrupt(); + + // ADC1 PA0 analog input + // ADC2 PA1 analog input + // DAC1 PA4 analog output + + // Init the ADC + GPIO_InitTypeDef GPIO_InitStruct; + ADC_InitTypeDef ADC_InitStructure; + ADC_CommonInitTypeDef ADC_CommonInitStructure; + + GPIO_StructInit(&GPIO_InitStruct); + ADC_CommonStructInit(&ADC_CommonInitStructure); + ADC_StructInit(&ADC_InitStructure); + + // Enable ADC clock + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); +#if defined(SEND_RSSI_DATA) + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE); +#else + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); +#endif + + // For ADC1 on PA0, ADC2 on PA1 +#if defined(SEND_RSSI_DATA) + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; +#else + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; +#endif + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_Init(GPIOA, &GPIO_InitStruct); + + // Init ADCs in dual mode, div clock by two + ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult; + ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; + ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; + ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; + ADC_CommonInit(&ADC_CommonInitStructure); + + // Init ADC1 and ADC2: 12bit, single-conversion + ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; + ADC_InitStructure.ADC_ScanConvMode = DISABLE; + ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; + ADC_InitStructure.ADC_ExternalTrigConvEdge = 0; + ADC_InitStructure.ADC_ExternalTrigConv = 0; + ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; + ADC_InitStructure.ADC_NbrOfConversion = 1; + + ADC_Init(ADC1, &ADC_InitStructure); + + ADC_EOCOnEachRegularChannelCmd(ADC1, ENABLE); + ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles); + + // Enable ADC1 + ADC_Cmd(ADC1, ENABLE); + +#if defined(SEND_RSSI_DATA) + ADC_Init(ADC2, &ADC_InitStructure); + + ADC_EOCOnEachRegularChannelCmd(ADC2, ENABLE); + ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_3Cycles); + + // Enable ADC2 + ADC_Cmd(ADC2, ENABLE); +#endif + + // Init the DAC + DAC_InitTypeDef DAC_InitStructure; + + GPIO_StructInit(&GPIO_InitStruct); + DAC_StructInit(&DAC_InitStructure); + + // GPIOA & D clock enable + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + + // DAC Periph clock enable + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + + // GPIO CONFIGURATION of DAC Pins + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStruct); + + DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(DAC_Channel_1, &DAC_InitStructure); + DAC_Cmd(DAC_Channel_1, ENABLE); + + // Init the timer + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + + TIM_TimeBaseInitTypeDef timerInitStructure; + TIM_TimeBaseStructInit (&timerInitStructure); + timerInitStructure.TIM_Prescaler = 1749; // 24 kHz + timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up; + timerInitStructure.TIM_Period = 1; + timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; + timerInitStructure.TIM_RepetitionCounter = 0; + TIM_TimeBaseInit(TIM2, &timerInitStructure); + TIM_Cmd(TIM2, ENABLE); + TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); + + NVIC_InitTypeDef nvicStructure; + nvicStructure.NVIC_IRQChannel = TIM2_IRQn; + nvicStructure.NVIC_IRQChannelPreemptionPriority = 0; + nvicStructure.NVIC_IRQChannelSubPriority = 1; + nvicStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&nvicStructure); + + GPIO_ResetBits(PORT_COSLED, PIN_COSLED); + GPIO_SetBits(PORT_LED, PIN_LED); +} + +void CIO::interrupt() +{ + uint8_t control = MARK_NONE; + uint16_t sample = DC_OFFSET; + uint16_t rawRSSI = 0U; + + m_txBuffer.get(sample, control); + + // Send the value to the DAC + DAC_SetChannel1Data(DAC_Align_12b_R, sample); + + // Read value from ADC1 and ADC2 + if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)) { + // shouldn't be still in reset at this point so null the sample value? + sample = 0U; + } else { + sample = ADC_GetConversionValue(ADC1); +#if defined(SEND_RSSI_DATA) + rawRSSI = ADC_GetConversionValue(ADC2); +#endif + } + + // trigger next ADC1 + ADC_ClearFlag(ADC1, ADC_FLAG_EOC); + ADC_SoftwareStartConv(ADC1); + + m_rxBuffer.put(sample, control); + m_rssiBuffer.put(rawRSSI); + + m_watchdog++; +} + +bool CIO::getCOSInt() +{ + return GPIO_ReadOutputDataBit(PORT_COS, PIN_COS) == Bit_SET; +} + +void CIO::setLEDInt(bool on) +{ + GPIO_WriteBit(PORT_LED, PIN_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::setPTTInt(bool on) +{ + GPIO_WriteBit(PORT_PTT, PIN_PTT, on ? Bit_SET : Bit_RESET); +} + +void CIO::setCOSInt(bool on) +{ + GPIO_WriteBit(PORT_COSLED, PIN_COSLED, on ? Bit_SET : Bit_RESET); +} + +void CIO::setDStarInt(bool on) +{ + GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET); +} + +void CIO::setDMRInt(bool on) +{ + GPIO_WriteBit(PORT_DMR, PIN_DMR, on ? Bit_SET : Bit_RESET); +} + +void CIO::setYSFInt(bool on) +{ + GPIO_WriteBit(PORT_YSF, PIN_YSF, on ? Bit_SET : Bit_RESET); +} + +void CIO::setP25Int(bool on) +{ + GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET); +} + +#endif + diff --git a/MMDVM.cpp b/MMDVM.cpp index 69f916d..4f21843 100644 --- a/MMDVM.cpp +++ b/MMDVM.cpp @@ -18,7 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(notdef) +#if defined(STM32F4XX) || defined(STM32F4) #include "Config.h" #include "Globals.h" diff --git a/MMDVM_STM32F4xx.cogui b/MMDVM_STM32F4xx.cogui new file mode 100644 index 0000000..0b4cff9 --- /dev/null +++ b/MMDVM_STM32F4xx.cogui @@ -0,0 +1,485 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MMDVM_STM32F4xx.comarker b/MMDVM_STM32F4xx.comarker new file mode 100644 index 0000000..b78ac1c --- /dev/null +++ b/MMDVM_STM32F4xx.comarker @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MMDVM_STM32F4xx.coproj b/MMDVM_STM32F4xx.coproj new file mode 100644 index 0000000..c0fa940 --- /dev/null +++ b/MMDVM_STM32F4xx.coproj @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4e72d56 --- /dev/null +++ b/Makefile @@ -0,0 +1,104 @@ +### +# GNU ARM Embedded Toolchain +CC=arm-none-eabi-gcc +CXX=arm-none-eabi-g++ +LD=arm-none-eabi-ld +AR=arm-none-eabi-ar +AS=arm-none-eabi-as +CP=arm-none-eabi-objcopy +OD=arm-none-eabi-objdump +NM=arm-none-eabi-nm +SIZE=arm-none-eabi-size +A2L=arm-none-eabi-addr2line + +### +# Directory Structure +BINDIR=bin + +### +# Find source files +ASOURCES=$(shell find . -name '*.s') +CSOURCES=$(shell find . -name '*.c') +CXXSOURCES=$(shell find . -name '*.cpp') +# Find header directories +INC=$(shell find . -name '*.h' -exec dirname {} \; | uniq) +INCLUDES=$(INC:%=-I%) +# Find libraries +INCLUDES_LIBS=libarm_cortexM4lf_math.a +LINK_LIBS= +# Create object list +OBJECTS=$(ASOURCES:%.s=%.o) +OBJECTS+=$(CSOURCES:%.c=%.o) +OBJECTS+=$(CXXSOURCES:%.cpp=%.o) +# Define output files ELF & IHEX +BINELF=outp.elf +BINHEX=outp.hex + +### +# MCU FLAGS +MCFLAGS=-mcpu=cortex-m4 -mthumb -mlittle-endian \ +-mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork +# COMPILE FLAGS +DEFS=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F407VG +CFLAGS=-c $(MCFLAGS) $(DEFS) $(INCLUDES) +CXXFLAGS=-c $(MCFLAGS) $(DEFS) $(INCLUDES) +# LINKER FLAGS +LDSCRIPT=stm32_flash.ld +LDFLAGS =-T $(LDSCRIPT) $(MCFLAGS) --specs=nosys.specs $(INCLUDES_LIBS) $(LINK_LIBS) + +### +# Build Rules +.PHONY: all release release-memopt debug clean + +all: release-memopt + +release-memopt: DEFS+=-DCUSTOM_NEW -DNO_EXCEPTIONS +release-memopt: CFLAGS+=-Os -ffunction-sections -fdata-sections -fno-builtin # -flto +release-memopt: CXXFLAGS+=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti # -flto +release-memopt: LDFLAGS+=-Os --specs=nano.specs # -flto +release-memopt: release + +debug: CFLAGS+=-g +debug: CXXFLAGS+=-g +debug: LDFLAGS+=-g +debug: release + +release: $(BINDIR)/$(BINHEX) + +$(BINDIR)/$(BINHEX): $(BINDIR)/$(BINELF) + $(CP) -O ihex $< $@ + @echo "Objcopy from ELF to IHEX complete!\n" + +$(BINDIR)/$(BINELF): $(OBJECTS) + $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ + @echo "Linking complete!\n" + $(SIZE) $(BINDIR)/$(BINELF) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $< -o $@ + @echo "Compiled "$<"!\n" + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ + @echo "Compiled "$<"!\n" + +%.o: %.s + $(CC) $(CFLAGS) $< -o $@ + @echo "Assambled "$<"!\n" + +clean: + rm -f $(OBJECTS) $(BINDIR)/$(BINELF) $(BINDIR)/$(BINHEX) $(BINDIR)/output.map + +deploy: +ifneq ($(wildcard /usr/bin/openocd),) + /usr/bin/openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/$(BINELF) verify reset exit" +endif + +ifneq ($(wildcard /usr/local/bin/openocd),) + /usr/local/bin/openocd -f /usr/local/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/$(BINELF) verify reset exit" +endif + +ifneq ($(wildcard /opt/openocd/bin/openocd),) + /opt/openocd/bin/openocd -f /opt/openocd/share/openocd/scripts/board/stm32f4discovery.cfg -c "program bin/$(BINELF) verify reset exit" +endif + diff --git a/README.md b/README.md index fd13ce8..3bfea68 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion and P25. -Currently it only runs on the Arduino Due, but other platforms are planned. +It runs on the Arduino Due, and the STM32F4xx platforms. Support for the Teensy (3.1/3.2 and 3.6) is being added. -In order to build this software you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. +In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden. diff --git a/RSSIRB.h b/RSSIRB.h index 41e6b8c..111a3ef 100644 --- a/RSSIRB.h +++ b/RSSIRB.h @@ -21,7 +21,12 @@ Boston, MA 02110-1301, USA. #if !defined(RSSIRB_H) #define RSSIRB_H +#if defined(STM32F4XX) || defined(STM32F4) +#include "stm32f4xx.h" +#include +#else #include +#endif class CRSSIRB { public: diff --git a/SampleRB.h b/SampleRB.h index 284a1a5..16d3441 100644 --- a/SampleRB.h +++ b/SampleRB.h @@ -21,7 +21,12 @@ Boston, MA 02110-1301, USA. #if !defined(SAMPLERB_H) #define SAMPLERB_H +#if defined(STM32F4XX) || defined(STM32F4) +#include "stm32f4xx.h" +#include +#else #include +#endif class CSampleRB { public: diff --git a/SerialRB.h b/SerialRB.h index ea7421e..1671b23 100644 --- a/SerialRB.h +++ b/SerialRB.h @@ -21,7 +21,12 @@ Boston, MA 02110-1301, USA. #if !defined(SERIALRB_H) #define SERIALRB_H +#if defined(STM32F4XX) || defined(STM32F4) +#include "stm32f4xx.h" +#include +#else #include +#endif const uint16_t SERIAL_RINGBUFFER_SIZE = 370U; diff --git a/SerialSTM.cpp b/SerialSTM.cpp new file mode 100644 index 0000000..73cde0a --- /dev/null +++ b/SerialSTM.cpp @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2016 by Jim McLaughlin KI6ZUM + * Copyright (C) 2016 by Andy Uribe CA6JAU + * + * 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" + +#include "SerialPort.h" + +#if defined(STM32F4XX) || defined(STM32F4) + +volatile uint32_t intcount1, intcount3; + +#define TX_SERIAL_FIFO_SIZE 256U +#define RX_SERIAL_FIFO_SIZE 256U + +volatile uint8_t TXSerialfifo1[TX_SERIAL_FIFO_SIZE]; +volatile uint8_t RXSerialfifo1[RX_SERIAL_FIFO_SIZE]; +volatile uint16_t TXSerialfifohead1, TXSerialfifotail1; +volatile uint16_t RXSerialfifohead1, RXSerialfifotail1; + +volatile uint8_t TXSerialfifo3[TX_SERIAL_FIFO_SIZE]; +volatile uint8_t RXSerialfifo3[RX_SERIAL_FIFO_SIZE]; +volatile uint16_t TXSerialfifohead3, TXSerialfifotail3; +volatile uint16_t RXSerialfifohead3, RXSerialfifotail3; + +extern "C" { + void USART1_IRQHandler(); + void USART3_IRQHandler(); +} + +/* ************* USART1 ***************** */ + +// Init queues +void TXSerialfifoinit1() +{ + TXSerialfifohead1 = 0U; + TXSerialfifotail1 = 0U; +} + +void RXSerialfifoinit1() +{ + RXSerialfifohead1 = 0U; + RXSerialfifotail1 = 0U; +} + +// How full is queue +// TODO decide if how full or how empty is preferred info to return +uint16_t TXSerialfifolevel1() +{ + uint32_t tail = TXSerialfifotail1; + uint32_t head = TXSerialfifohead1; + + if (tail > head) + return TX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +uint16_t RXSerialfifolevel1() +{ + uint32_t tail = RXSerialfifotail1; + uint32_t head = RXSerialfifohead1; + + if (tail > head) + return RX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +// Flushes the transmit shift register +// warning: this call is blocking +void TXSerialFlush1() +{ + // wait until the TXE shows the shift register is empty + while (USART_GetITStatus(USART1, USART_FLAG_TXE)) + ; +} + +uint8_t TXSerialfifoput1(uint8_t next) +{ + if (TXSerialfifolevel1() < TX_SERIAL_FIFO_SIZE) { + TXSerialfifo1[TXSerialfifohead1] = next; + + TXSerialfifohead1++; + if (TXSerialfifohead1 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifohead1 = 0U; + + // make sure transmit interrupts are enabled as long as there is data to send + USART_ITConfig(USART1, USART_IT_TXE, ENABLE); + return 1U; + } else { + return 0U; // signal an overflow occurred by returning a zero count + } +} + +void USART1_IRQHandler() +{ + uint8_t c; + + if (USART_GetITStatus(USART1, USART_IT_RXNE)) { + c = (uint8_t) USART_ReceiveData(USART1); + + if (RXSerialfifolevel1() < RX_SERIAL_FIFO_SIZE) { + RXSerialfifo1[RXSerialfifohead1] = c; + + RXSerialfifohead1++; + if (RXSerialfifohead1 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifohead1 = 0U; + } else { + // TODO - do something if rx fifo is full? + } + + USART_ClearITPendingBit(USART1, USART_IT_RXNE); + intcount1++; + } + + if (USART_GetITStatus(USART1, USART_IT_TXE)) { + c = 0U; + + if (TXSerialfifohead1 != TXSerialfifotail1) { // if the fifo is not empty + c = TXSerialfifo1[TXSerialfifotail1]; + + TXSerialfifotail1++; + if (TXSerialfifotail1 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifotail1 = 0U; + + USART_SendData(USART1, c); + } else { // if there's no more data to transmit then turn off TX interrupts + USART_ITConfig(USART1, USART_IT_TXE, DISABLE); + } + + USART_ClearITPendingBit(USART1, USART_IT_TXE); + } +} + +void InitUSART1(int speed) +{ + // USART1 - TXD PA9 - RXD PA10 - pins on mmdvm pi board + GPIO_InitTypeDef GPIO_InitStructure; + USART_InitTypeDef USART_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); + + // USART IRQ init + NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_Init(&NVIC_InitStructure); + + // Configure USART as alternate function + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // Tx | Rx + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + // Configure USART baud rate + USART_StructInit(&USART_InitStructure); + USART_InitStructure.USART_BaudRate = speed; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_Init(USART1, &USART_InitStructure); + + USART_Cmd(USART1, ENABLE); + + USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); + + // initialize the fifos + TXSerialfifoinit1(); + RXSerialfifoinit1(); +} + +uint8_t AvailUSART1(void) +{ + if (RXSerialfifolevel1() > 0U) + return 1U; + else + return 0U; +} + +uint8_t ReadUSART1(void) +{ + uint8_t data_c = RXSerialfifo1[RXSerialfifotail1]; + + RXSerialfifotail1++; + if (RXSerialfifotail1 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifotail1 = 0U; + + return data_c; +} + +void WriteUSART1(const uint8_t* data, uint16_t length) +{ + for (uint16_t i = 0U; i < length; i++) + TXSerialfifoput1(data[i]); + + USART_ITConfig(USART1, USART_IT_TXE, ENABLE); +} + +/* ************* USART3 ***************** */ + +// Init queues +void TXSerialfifoinit3() +{ + TXSerialfifohead3 = 0U; + TXSerialfifotail3 = 0U; +} + +void RXSerialfifoinit3() +{ + RXSerialfifohead3 = 0U; + RXSerialfifotail3 = 0U; +} + +// How full is queue +// TODO decide if how full or how empty is preferred info to return +uint16_t TXSerialfifolevel3() +{ + uint32_t tail = TXSerialfifotail3; + uint32_t head = TXSerialfifohead3; + + if (tail > head) + return TX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +uint16_t RXSerialfifolevel3() +{ + uint32_t tail = RXSerialfifotail3; + uint32_t head = RXSerialfifohead3; + + if (tail > head) + return RX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +// Flushes the transmit shift register +// warning: this call is blocking +void TXSerialFlush3() +{ + // wait until the TXE shows the shift register is empty + while (USART_GetITStatus(USART3, USART_FLAG_TXE)) + ; +} + +uint8_t TXSerialfifoput3(uint8_t next) +{ + if (TXSerialfifolevel3() < TX_SERIAL_FIFO_SIZE) { + TXSerialfifo3[TXSerialfifohead3] = next; + + TXSerialfifohead3++; + if (TXSerialfifohead3 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifohead3 = 0U; + + // make sure transmit interrupts are enabled as long as there is data to send + USART_ITConfig(USART3, USART_IT_TXE, ENABLE); + return 1U; + } else { + return 0U; // signal an overflow occurred by returning a zero count + } +} + +void USART3_IRQHandler() +{ + uint8_t c; + + if (USART_GetITStatus(USART3, USART_IT_RXNE)) { + c = (uint8_t) USART_ReceiveData(USART3); + + if (RXSerialfifolevel3() < RX_SERIAL_FIFO_SIZE) { + RXSerialfifo3[RXSerialfifohead3] = c; + + RXSerialfifohead3++; + if (RXSerialfifohead3 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifohead3 = 0U; + } else { + // TODO - do something if rx fifo is full? + } + + USART_ClearITPendingBit(USART3, USART_IT_RXNE); + intcount3++; + } + + if (USART_GetITStatus(USART3, USART_IT_TXE)) { + c = 0U; + + if (TXSerialfifohead3 != TXSerialfifotail3) { // if the fifo is not empty + c = TXSerialfifo3[TXSerialfifotail3]; + + TXSerialfifotail3++; + if (TXSerialfifotail3 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifotail3 = 0U; + + USART_SendData(USART3, c); + } else { // if there's no more data to transmit then turn off TX interrupts + USART_ITConfig(USART3, USART_IT_TXE, DISABLE); + } + + USART_ClearITPendingBit(USART3, USART_IT_TXE); + } +} + +void InitUSART3(int speed) +{ + // USART3 - TXD PB10 - RXD PB11 - pins when jumpered from FTDI board to F4Discovery board + GPIO_InitTypeDef GPIO_InitStructure; + USART_InitTypeDef USART_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3); + + // USART IRQ init + NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_Init(&NVIC_InitStructure); + + // Configure USART as alternate function + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; // Tx | Rx + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + // Configure USART baud rate + USART_StructInit(&USART_InitStructure); + USART_InitStructure.USART_BaudRate = speed; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_Init(USART3, &USART_InitStructure); + + USART_Cmd(USART3, ENABLE); + + USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); + + // initialize the fifos + TXSerialfifoinit3(); + RXSerialfifoinit3(); +} + +uint8_t AvailUSART3(void) +{ + if (RXSerialfifolevel3() > 0U) + return 1U; + else + return 0U; +} + +uint8_t ReadUSART3(void) +{ + uint8_t data_c = RXSerialfifo3[RXSerialfifotail3]; + + RXSerialfifotail3++; + if (RXSerialfifotail3 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifotail3 = 0U; + + return data_c; +} + +void WriteUSART3(const uint8_t* data, uint16_t length) +{ + for (uint16_t i = 0U; i < length; i++) + TXSerialfifoput3(data[i]); + + USART_ITConfig(USART3, USART_IT_TXE, ENABLE); +} + +///////////////////////////////////////////////////////////////// + +void CSerialPort::beginInt(uint8_t n, int speed) +{ + switch (n) { + case 1U: + InitUSART3(speed); + break; + case 3U: + InitUSART1(speed); + break; + default: + break; + } +} + +int CSerialPort::availableInt(uint8_t n) +{ + switch (n) { + case 1U: + return AvailUSART3(); + case 3U: + return AvailUSART1(); + default: + return false; + } +} + +uint8_t CSerialPort::readInt(uint8_t n) +{ + switch (n) { + case 1U: + return ReadUSART3(); + case 3U: + return ReadUSART1(); + default: + return 0U; + } +} + +void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush) +{ + switch (n) { + case 1U: + WriteUSART3(data, length); + if (flush) + TXSerialFlush3(); + break; + case 3U: + WriteUSART1(data, length); + if (flush) + TXSerialFlush1(); + break; + default: + break; + } +} + +#endif + diff --git a/Utils.h b/Utils.h index 913e9a6..d158c6b 100644 --- a/Utils.h +++ b/Utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * * 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 @@ -19,7 +19,12 @@ #if !defined(UTILS_H) #define UTILS_H +#if defined(STM32F4XX) || defined(STM32F4) +#include "stm32f4xx.h" +#include +#else #include +#endif uint8_t countBits8(uint8_t bits); diff --git a/stm32_flash.ld b/stm32_flash.ld new file mode 100644 index 0000000..1a0b4b8 --- /dev/null +++ b/stm32_flash.ld @@ -0,0 +1,170 @@ +/* +***************************************************************************** +** +** File : stm32_flash.ld +** +** Abstract : Linker script for STM32F407VG Device with +** 1024KByte FLASH, 192KByte RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Environment : Atollic TrueSTUDIO(R) +** +** Distribution: The file is distributed “as is,” without any warranty +** of any kind. +** +** (c)Copyright Atollic AB. +** You may use this file as-is or modify it according to the needs of your +** project. Distribution of this file (unmodified or modified) is not +** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the +** rights to distribute the assembled, compiled & linked contents of this +** file as part of an application binary file, provided that it is built +** using the Atollic TrueSTUDIO(R) toolchain. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20020000; /* end of 128K RAM on AHB bus*/ + +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K + MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array*)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = .; + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM + + /* MEMORY_bank1 section, code must be located here explicitly */ + /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */ + .memory_b1_text : + { + *(.mb1text) /* .mb1text sections (code) */ + *(.mb1text*) /* .mb1text* sections (code) */ + *(.mb1rodata) /* read-only data (constants) */ + *(.mb1rodata*) + } >MEMORY_B1 + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +}