Compare commits

..
1 Commits
Author SHA1 Message Date
Jonathan Naylor a904b5fb4e Beginning od dPMR support. 2024-10-03 16:50:54 +01:00
165 changed files with 7341 additions and 74359 deletions
+5 -3
View File
@@ -1,3 +1,5 @@
.pio *.o
.vscode obj/
bin/
GitVersion.h
build/
+6
View File
@@ -0,0 +1,6 @@
[submodule "STM32F4XX_Lib"]
path = STM32F4XX_Lib
url = https://github.com/juribeparada/STM32F4XX_Lib.git
[submodule "STM32F7XX_Lib"]
path = STM32F7XX_Lib
url = https://github.com/juribeparada/STM32F7XX_Lib.git
@@ -25,11 +25,12 @@
#include "AX25Demodulator.h" #include "AX25Demodulator.h"
#include "AX25Defines.h" #include "AX25Defines.h"
const uint32_t SYMBOL_RATE = 1200U; const float32_t SAMPLE_RATE = 24000.0F;
const float32_t SYMBOL_RATE = 1200.0F;
const uint16_t DELAY_LEN = 11U; const uint16_t DELAY_LEN = 11U;
const float32_t SAMPLES_PER_SYMBOL = float32_t(SAMPLE_RATE / SYMBOL_RATE); const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE;
const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F; const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F;
const uint32_t LPF_FILTER_LEN = 48U; const uint32_t LPF_FILTER_LEN = 48U;
+2 -2
View File
@@ -193,7 +193,7 @@ void CAX25RX::initRand() //Can also be used to seed the rng with more entropy du
{ {
m_a = (m_a ^ m_c ^ m_x); m_a = (m_a ^ m_c ^ m_x);
m_b = (m_b + m_a); m_b = (m_b + m_a);
m_c = (m_c + ((m_b >> 1) ^ m_a)); m_c = (m_c + (m_b >> 1) ^ m_a);
} }
uint8_t CAX25RX::rand() uint8_t CAX25RX::rand()
@@ -202,7 +202,7 @@ uint8_t CAX25RX::rand()
m_a = (m_a ^ m_c ^ m_x); //note the mix of addition and XOR m_a = (m_a ^ m_c ^ m_x); //note the mix of addition and XOR
m_b = (m_b + m_a); //And the use of very few instructions m_b = (m_b + m_a); //And the use of very few instructions
m_c = (m_c + ((m_b >> 1) ^ m_a)); //the right shift is to ensure that high-order bits from b can affect m_c = (m_c + (m_b >> 1) ^ m_a); //the right shift is to ensure that high-order bits from b can affect
return uint8_t(m_c); //low order bits of other variables return uint8_t(m_c); //low order bits of other variables
} }
View File
View File
View File
+125
View File
@@ -0,0 +1,125 @@
In order to build MMDVM, you need to tell the Arduino GUI to link with the
CMSIS DSP library, which is doesn't do by default.
My development is on Windows and so I can vouch for the following instructions.
For Arduino 1.6.3 with SAM 1.6.4
--------------------------------
1. Go to the where the platform.txt file is located. On my Windows machine it's
in:
C:\Users\Jonathan\AppData\Roaming\Arduino15\packages\arduino\hardware\sam\1.6.4
On Mac OS X it's located in:
/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/sam
Or
~/Library/Arduino15/packages/arduino/hardware/sam/1.6.6
2. You'll need to open the file in a text editor and find the line:
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc
In my version it's line 73.
3. Modify it to read as follows:
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group "{build.path}/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.system.path}/CMSIS/CMSIS/Lib/ARM/arm_cortexM3l_math.lib" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc
The change is near the end, and is the addition of:
"{build.system.path}/CMSIS/CMSIS/Lib/ARM/arm_cortexM3l_math.lib"
Which is the CMSIS AMR3 DSP library for little-endian operation.
4. Save the file and start up the Arduino GUI and build MMDVM.
I would like to get instructions for doing the same on a Linux platform. As a
starter find the relevent platform.txt and try adding:
"{build.system.path}/CMSIS/CMSIS/Lib/ARM/libarm_cortexM3l_math.a"
or maybe:
"{build.variant.path}/libarm_cortexM3l_math.a"
Likely on Linux
"{build.system.path}/CMSIS/CMSIS/Lib/GCC/libarm_cortexM3l_math.a"
As with Arduino 1.6.7 with SAM 1.6.6, see below.
For Arduino 1.6.7 with SAM 1.6.6
--------------------------------
(checked OK on Arduino 1.6.11 and SAM 1.6.9)
1. Go to the where the platform.txt file is located. On my Windows machine it's
in:
C:\Users\Jonathan\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.6
On Mac OS X it's located in:
/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/sam
On Linux, it's located in my home directory, downloaded and extracted from Arduino website, but must be installed.
/home/m1geo/arduino-1.6.7/hardware/arduino/sam
or
/home/m1geo/.arduino15/packages/arduino/hardware/sam/1.6.9 (if you let the board/library manager install SAM)
I (M1GEO) found it was necessary to download SAM-1.6.6 outside of the Arduino IDE, and manually extract the files.
The Board Manager didn't seem to install the SAM files correctly. Here's how I did it:
a) wget http://downloads.arduino.cc/cores/sam-1.6.6.tar.bz2 -O /tmp/sam-1.6.6.tar.bz2 (download and save in /tmp)
b) cd arduino-1.6.7/hardware/arduino/ (Arduino root, here, in my home directory)
c) tar xvfj /tmp/sam-1.6.6.tar.bz2
2. You'll need to open the file (platform.txt) in a text editor and find the line:
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -mcpu={build.mcu} -mthumb {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group "{build.path}/core/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc
In my version it's line 73.
3. Modify it to read as follows:
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -mcpu={build.mcu} -mthumb {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group "{build.path}/core/syscalls_sam3.c.o" {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.system.path}/CMSIS/CMSIS/Lib/ARM/arm_cortexM3l_math.lib" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc
The change is near the end, and is the addition of:
"{build.system.path}/CMSIS/CMSIS/Lib/ARM/arm_cortexM3l_math.lib"
On Linux, the path was found to differ slightly (GCC instead of ARM):
"{build.system.path}/CMSIS/CMSIS/Lib/GCC/libarm_cortexM3l_math.a"
Which is the CMSIS AMR3 DSP library for little-endian operation.
4. Save the file and start up the Arduino GUI and build MMDVM.
For Arduino 1.6.9 with SAM 1.6.8
--------------------------------
1. Locate platform.txt. On Ubuntu 14.04 LTS x86_64 OS it is in:
/home/$user/.arduino15/packages/arduino/hardware/sam/1.6.8/
2. Open the file in a text editor and change the line:
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -mcpu={build.mcu} -mthumb {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group {compiler.combine.flags} {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc
to
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" -mcpu={build.mcu} -mthumb {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group {compiler.combine.flags} {object_files} "{build.variant.path}/{build.variant_system_lib}" "{build.system.path}/CMSIS/CMSIS/Lib/GCC/libarm_cortexM3l_math.a" "{build.path}/{archive_file}" -Wl,--end-group -lm -gcc
3. Save the file, open the Arduino IDE and build MMDVM
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
+44 -13
View File
@@ -38,6 +38,9 @@
#define MODE_NXDN #define MODE_NXDN
#define USE_NXDN_BOXCAR #define USE_NXDN_BOXCAR
// Enable dPMR support.
#define MODE_DPMR
// Enable M17 support. // Enable M17 support.
#define MODE_M17 #define MODE_M17
@@ -50,15 +53,50 @@
// Enable AX.25 support, this is only enabled if FM is also enabled. // Enable AX.25 support, this is only enabled if FM is also enabled.
#define MODE_AX25 #define MODE_AX25
// Allow for the use of high quality external clock oscillators
// The number is the frequency of the oscillator in Hertz.
//
// The frequency of the TCXO must be an integer multiple of 48000.
// Frequencies such as 12.0 Mhz (48000 * 250) and 14.4 Mhz (48000 * 300) are suitable.
// 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
// For 12.288 MHz
// #define EXTERNAL_OSC 12288000
// For 14.4 MHz
// #define EXTERNAL_OSC 14400000
// For 19.2 MHz
// #define EXTERNAL_OSC 19200000
// Select a baud rate for host communication. The faster speeds are needed for external FM to work. // Select a baud rate for host communication. The faster speeds are needed for external FM to work.
// #define SERIAL_SPEED 115200 // Suitable for most older boards. External FM will NOT work with this! // #define SERIAL_SPEED 115200 // Suitable for most older boards (Arduino Due, etc). External FM will NOT work with this!
// #define SERIAL_SPEED 230400 // Only works on newer boards like fast M4, M7. External FM might work with this // #define SERIAL_SPEED 230400 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM might work with this
#define SERIAL_SPEED 460800 // Only works on newer boards like fast M4, M7. External FM will work with this #define SERIAL_SPEED 460800 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM should work with this
//#define SERIAL_SPEED 500000 // Used with newer boards and Armbian on AllWinner SOCs (H2, H3) that do not support 460800 //#define SERIAL_SPEED 500000 // Used with newer boards and Armbian on AllWinner SOCs (H2, H3) that do not support 460800
// Use pins to output the current mode via LEDs // Use pins to output the current mode via LEDs
#define MODE_LEDS #define MODE_LEDS
// For the original Arduino Due pin layout
// #define ARDUINO_DUE_PAPA
// For the ZUM V1.0 and V1.0.1 boards pin layout
// #define ARDUINO_DUE_ZUM_V10
// For the SP8NTH board
// #define ARDUINO_DUE_NTH
// For ST Nucleo-64 STM32F446RE board
// #define STM32F4_NUCLEO_MORPHO_HEADER
// #define STM32F4_NUCLEO_ARDUINO_HEADER
// Use separate mode pins to switch external channel/filters/bandwidth for example
// #define MODE_PINS
// For the VK6MST Pi3 Shield communicating over i2c. i2c address & speed defined in i2cTeensy.cpp
// #define VK6MST_TEENSY_PI3_SHIELD_I2C
// Pass RSSI information to the host // Pass RSSI information to the host
#define SEND_RSSI_DATA #define SEND_RSSI_DATA
@@ -74,16 +112,6 @@
// To reduce CPU load, you can remove the DC blocker by commenting out the next line // To reduce CPU load, you can remove the DC blocker by commenting out the next line
#define USE_DCBLOCKER #define USE_DCBLOCKER
// Choose the type of modem board in use, only one.
// The KI6ZUM v0.9 Pi hat, STM32F446 CPU
#define ZUM_V09_PI
// The KI6ZUM v1.0 Pi hat, STM32F722 CPU
// #define ZUM_V10_PI
// The Repeater Builder V3 board, STM32F446 CPU
// #define RB_V3_PI
// The Repeater Builder V5 board, STM32F722 CPU
// #define RB_V5_PI
// Constant Service LED once repeater is running // Constant Service LED once repeater is running
// Do not use if employing an external hardware watchdog // Do not use if employing an external hardware watchdog
// #define CONSTANT_SRV_LED // #define CONSTANT_SRV_LED
@@ -100,5 +128,8 @@
// Use the D-Star and YSF LEDs for FM // Use the D-Star and YSF LEDs for FM
#define USE_ALTERNATE_FM_LEDS #define USE_ALTERNATE_FM_LEDS
// Use the DMR and YSF LEDs for dPMR
#define USE_ALTERNATE_DPMR_LEDS
#endif #endif
View File
View File
View File
View File
View File
View File
View File
View File
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright (C) 2016,2017,2018,2024 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
* 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.
*/
#if !defined(DPMRDEFINES_H)
#define DPMRDEFINES_H
const unsigned int DPMR_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate
const unsigned int DPMR_HEADER_FRAME_LENGTH_BITS = 312U;
const unsigned int DPMR_HEADER_FRAME_LENGTH_BYTES = DPMR_HEADER_FRAME_LENGTH_BITS / 8U;
const unsigned int DPMR_HEADER_FRAME_LENGTH_SYMBOLS = DPMR_HEADER_FRAME_LENGTH_BITS / 2U;
const unsigned int DPMR_HEADER_FRAME_LENGTH_SAMPLES = DPMR_HEADER_FRAME_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const unsigned int DPMR_DATA_FRAME_LENGTH_BITS = 384U;
const unsigned int DPMR_DATA_FRAME_LENGTH_BYTES = DPMR_DATA_FRAME_LENGTH_BITS / 8U;
const unsigned int DPMR_DATA_FRAME_LENGTH_SYMBOLS = DPMR_DATA_FRAME_LENGTH_BITS / 2U;
const unsigned int DPMR_DATA_FRAME_LENGTH_SAMPLES = DPMR_DATA_FRAME_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const unsigned int DPMR_END_FRAME_LENGTH_BITS = 96U;
const unsigned int DPMR_END_FRAME_LENGTH_BYTES = DPMR_END_FRAME_LENGTH_BITS / 8U;
const unsigned int DPMR_END_FRAME_LENGTH_SYMBOLS = DPMR_END_FRAME_LENGTH_BITS / 2U;
const unsigned int DPMR_END_FRAME_LENGTH_SAMPLES = DPMR_END_FRAME_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const unsigned int DPMR_FS1_LENGTH_BITS = 48U;
const unsigned int DPMR_FS1_LENGTH_SYMBOLS = DPMR_FS1_LENGTH_BITS / 2U;
const unsigned int DPMR_FS1_LENGTH_SAMPLES = DPMR_FS1_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const unsigned int DPMR_FS2_LENGTH_BITS = 24U;
const unsigned int DPMR_FS2_LENGTH_SYMBOLS = DPMR_FS2_LENGTH_BITS / 2U;
const unsigned int DPMR_FS2_LENGTH_SAMPLES = DPMR_FS2_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const unsigned int DPMR_FS3_LENGTH_BITS = 24U;
const unsigned int DPMR_FS3_LENGTH_SYMBOLS = DPMR_FS3_LENGTH_BITS / 2U;
const unsigned int DPMR_FS3_LENGTH_SAMPLES = DPMR_FS3_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const unsigned int DPMR_FS4_LENGTH_BITS = 48U;
const unsigned int DPMR_FS4_LENGTH_SYMBOLS = DPMR_FS4_LENGTH_BITS / 2U;
const unsigned int DPMR_FS4_LENGTH_SAMPLES = DPMR_FS4_LENGTH_SYMBOLS * DPMR_RADIO_SYMBOL_LENGTH;
const uint8_t DPMR_FS1_BYTES[] = {0x57U, 0xFFU, 0x5FU, 0x75U, 0xD5U, 0x77U};
const uint8_t DPMR_FS1_BYTES_LENGTH = 6U;
const uint8_t DPMR_FS2_BYTES[] = {0x5FU, 0xF7U, 0x7DU};
const uint8_t DPMR_FS2_BYTES_LENGTH = 3U;
const uint8_t DPMR_FS3_BYTES[] = {0x7DU, 0xDFU, 0xF5U};
const uint8_t DPMR_FS3_BYTES_LENGTH = 3U;
const uint8_t DPMR_FS4_BYTES[] = {0xFDU, 0x55U, 0xF5U, 0xDFU, 0x7FU, 0xDDU};
const uint8_t DPMR_FS4_BYTES_LENGTH = 6U;
const uint64_t DPMR_FS1_BITS = 0x000057FF5F75D577U;
const uint64_t DPMR_FS1_BITS_MASK = 0x0000FFFFFFFFFFFFU;
const uint64_t DPMR_FS2_BITS = 0x00000000005FF77DU;
const uint64_t DPMR_FS2_BITS_MASK = 0x0000000000FFFFFFU;
const uint64_t DPMR_FS3_BITS = 0x00000000007DDFF5U;
const uint64_t DPMR_FS3_BITS_MASK = 0x0000000000FFFFFFU;
const uint64_t DPMR_FS4_BITS = 0x0000FD55F5DF7FDDU;
const uint64_t DPMR_FS4_BITS_MASK = 0x0000FFFFFFFFFFFFU;
// FS1
// 5 5 F F 5 F 7 5 D 5 7 7
// 01 01 01 11 11 11 11 11 01 01 11 11 01 11 01 01 11 01 01 01 01 11 01 11
// +3 +3 +3 -3 -3 -3 -3 -3 +3 +3 -3 -3 +3 -3 +3 +3 -3 +3 +3 +3 +3 -3 +3 -3
const int8_t DPMR_FS1_SYMBOLS_VALUES[] = {+3, +3, +3, -3, -3, -3, -3, -3, +3, +3, -3, -3, +3, -3, +3, +3, -3, +3, +3, +3, +3, -3, +3, -3};
const uint32_t DPMR_FS1_SYMBOLS = 0x00E0CB7AU;
const uint32_t DPMR_FS1_SYMBOLS_MASK = 0x00FFFFFFU;
// FS2
// 5 F F 7 7 D
// 01 01 11 11 11 11 01 11 01 11 11 01
// +3 +3 -3 -3 -3 -3 +3 -3 +3 -3 -3 +3
const int8_t DPMR_FS2_SYMBOLS_VALUES[] = {+3, +3, -3, -3, -3, -3, +3, -3, +3, -3, -3, +3};
const uint32_t DPMR_FS2_SYMBOLS = 0x00000C29U;
const uint32_t DPMR_FS2_SYMBOLS_MASK = 0x00000FFFU;
// FS3
// 7 D D F F 5
// 01 11 11 01 11 01 11 11 11 11 01 01
// +3 -3 -3 +3 -3 +3 -3 -3 -3 -3 +3 +3
const int8_t DPMR_FS3_SYMBOLS_VALUES[] = {+3, -3, -3, +3, -3, +3, -3, -3, -3, -3, +3, +3};
const uint32_t DPMR_FS3_SYMBOLS = 0x00000943U;
const uint32_t DPMR_FS3_SYMBOLS_MASK = 0x00000FFFU;
// FS4
// F D 5 5 F 5 D F 7 F D D
// 11 11 11 01 01 01 01 01 11 11 01 01 11 01 11 11 01 11 11 11 11 01 11 01
// -3 -3 -3 +3 +3 +3 +3 +3 -3 -3 +3 +3 -3 +3 -3 -3 +3 -3 -3 -3 -3 +3 -3 +3
const int8_t DPMR_FS4_SYMBOLS_VALUES[] = {-3, -3, -3, +3, +3, +3, +3, +3, -3, -3, +3, +3, -3, +3, -3, -3, +3, -3, -3, -3, -3, +3, -3, +3};
const uint32_t DPMR_FS4_SYMBOLS = 0x001F3485U;
const uint32_t DPMR_FS4_SYMBOLS_MASK = 0x00FFFFFFU;
#endif
+687
View File
@@ -0,0 +1,687 @@
/*
* Copyright (C) 2009-2018,2020,2024 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
* 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"
#if defined(MODE_DPMR)
#include "Globals.h"
#include "DPMRRX.h"
#include "Utils.h"
const q15_t SCALING_FACTOR = 18750; // Q15(0.55)
const uint8_t MAX_FS_BIT_START_ERRS = 1U;
const uint8_t MAX_FS_BIT_RUN_ERRS = 3U;
const uint8_t MAX_FS_SYMBOLS_ERRS = 2U;
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
const uint8_t NOAVEPTR = 99U;
const uint16_t NOENDPTR = 9999U;
const unsigned int MAX_FS_FRAMES = 5U + 1U;
CDPMRRX::CDPMRRX() :
m_state(DPMRRXS_NONE),
m_bitBuffer(),
m_buffer(),
m_bitPtr(0U),
m_dataPtr(0U),
m_startPtr(NOENDPTR),
m_endPtr(NOENDPTR),
m_fsPtr(NOENDPTR),
m_minFSPtr(NOENDPTR),
m_maxFSPtr(NOENDPTR),
m_maxCorr(0),
m_lostCount(0U),
m_countdown(0U),
m_centre(),
m_centreVal(0),
m_threshold(),
m_thresholdVal(0),
m_averagePtr(NOAVEPTR),
m_rssiAccum(0U),
m_rssiCount(0U)
{
}
void CDPMRRX::reset()
{
m_state = DPMRRXS_NONE;
m_dataPtr = 0U;
m_bitPtr = 0U;
m_maxCorr = 0;
m_averagePtr = NOAVEPTR;
m_startPtr = NOENDPTR;
m_endPtr = NOENDPTR;
m_fsPtr = NOENDPTR;
m_minFSPtr = NOENDPTR;
m_maxFSPtr = NOENDPTR;
m_centreVal = 0;
m_thresholdVal = 0;
m_lostCount = 0U;
m_countdown = 0U;
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
void CDPMRRX::samples(const q15_t* samples, uint16_t* rssi, uint8_t length)
{
for (uint8_t i = 0U; i < length; i++) {
q15_t sample = samples[i];
m_rssiAccum += rssi[i];
m_rssiCount++;
m_bitBuffer[m_bitPtr] <<= 1;
if (sample < 0)
m_bitBuffer[m_bitPtr] |= 0x01U;
m_buffer[m_dataPtr] = sample;
switch (m_state) {
case DPMRRXS_HEADER:
processHeader(sample);
break;
case DPMRRXS_DATA:
processData(sample);
break;
case DPMRRXS_EOT:
processEOT(sample);
break;
default:
processNone(sample);
break;
}
m_dataPtr++;
if (m_dataPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_dataPtr = 0U;
m_bitPtr++;
if (m_bitPtr >= DPMR_RADIO_SYMBOL_LENGTH)
m_bitPtr = 0U;
}
}
void CDPMRRX::processNone(q15_t sample)
{
// Process the FS1/Header sync
bool ret = correlateFS1();
if (ret) {
// On the first sync, start the countdown to the state change
if (m_countdown == 0U) {
m_rssiAccum = 0U;
m_rssiCount = 0U;
io.setDecode(true);
io.setADCDetection(true);
m_averagePtr = NOAVEPTR;
m_countdown = 5U;
}
}
if (m_countdown > 0U)
m_countdown--;
if (m_countdown == 1U) {
m_minFSPtr = m_fsPtr + DPMR_HEADER_FRAME_LENGTH_SAMPLES - 1U;
if (m_minFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_minFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
m_maxFSPtr = m_fsPtr + 1U;
if (m_maxFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_maxFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
m_state = DPMRRXS_HEADER;
m_countdown = 0U;
}
// Process the FS2/Data sync
ret = correlateFS2();
if (ret) {
// On the first sync, start the countdown to the state change
if (m_countdown == 0U) {
m_rssiAccum = 0U;
m_rssiCount = 0U;
io.setDecode(true);
io.setADCDetection(true);
m_averagePtr = NOAVEPTR;
m_countdown = 5U;
}
}
if (m_countdown > 0U)
m_countdown--;
if (m_countdown == 1U) {
m_minFSPtr = m_fsPtr + DPMR_DATA_FRAME_LENGTH_SAMPLES - 1U;
if (m_minFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_minFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
m_maxFSPtr = m_fsPtr + 1U;
if (m_maxFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_maxFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
m_state = DPMRRXS_DATA;
m_countdown = 0U;
}
// Don't process FS3/End sync here
}
void CDPMRRX::processHeader(q15_t sample)
{
if (m_dataPtr == m_endPtr) {
m_minFSPtr = m_fsPtr + DPMR_HEADER_FRAME_LENGTH_SAMPLES - 1U;
if (m_minFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_minFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
m_maxFSPtr = m_fsPtr + 1U;
if (m_maxFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_maxFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
calculateLevels(m_startPtr, DPMR_HEADER_FRAME_LENGTH_SYMBOLS);
DEBUG4("DPMRRX: FS1 sync found pos/centre/threshold", m_fsPtr, m_centreVal, m_thresholdVal);
uint8_t frame[DPMR_HEADER_FRAME_LENGTH_BYTES + 3U];
samplesToBits(m_startPtr, DPMR_HEADER_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
frame[0U] = 0x01U;
writeRSSIHeader(frame);
m_state = DPMRRXS_DATA;
m_maxCorr = 0;
}
}
void CDPMRRX::processData(q15_t sample)
{
if (m_minFSPtr < m_maxFSPtr) {
if (m_dataPtr >= m_minFSPtr && m_dataPtr <= m_maxFSPtr) {
correlateFS2();
bool ret = correlateFS3();
if (ret)
m_state = DPMRRXS_EOT;
}
} else {
if (m_dataPtr >= m_minFSPtr || m_dataPtr <= m_maxFSPtr) {
correlateFS2();
bool ret = correlateFS3();
if (ret)
m_state = DPMRRXS_EOT;
}
}
if (m_dataPtr == m_endPtr) {
// Only update the centre and threshold if they are from a good sync
if (m_lostCount == MAX_FS2_FRAMES) {
m_minFSPtr = m_fsPtr + DPMR_DATA_FRAME_LENGTH_SAMPLES - 1U;
if (m_minFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_minFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
m_maxFSPtr = m_fsPtr + 1U;
if (m_maxFSPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_maxFSPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
}
calculateLevels(m_startPtr, DPMR_DATA_FRAME_LENGTH_SYMBOLS);
DEBUG4("DPMRRX: FS2 sync found pos/centre/threshold", m_fsPtr, m_centreVal, m_thresholdVal);
uint8_t frame[DPMR_DATA_FRAME_LENGTH_BYTES + 3U];
samplesToBits(m_startPtr, DPMR_DATA_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
// We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
m_lostCount--;
if (m_lostCount == 0U) {
DEBUG1("DPMRRX: FS2 sync timed out, lost lock");
io.setDecode(false);
io.setADCDetection(false);
serial.writeDPMRLost();
m_state = DPMRRXS_NONE;
m_endPtr = NOENDPTR;
m_averagePtr = NOAVEPTR;
m_countdown = 0U;
m_maxCorr = 0;
} else {
frame[0U] = m_lostCount == (MAX_FS2_FRAMES - 1U) ? 0x01U : 0x00U;
writeRSSIData(frame);
m_maxCorr = 0;
}
}
}
void CDPMRRX::processEnd(q15_t sample)
{
if (m_dataPtr == m_endPtr) {
calculateLevels(m_startPtr, DPMR_END_FRAME_LENGTH_SYMBOLS);
DEBUG4("DPMRRX: FS3 sync found pos/centre/threshold", m_fsPtr, m_centreVal, m_thresholdVal);
uint8_t frame[DPMR_END_FRAME_LENGTH_BYTES + 3U];
samplesToBits(m_startPtr, DPMR_END_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
frame[0U] = 0x01U;
io.setDecode(false);
io.setADCDetection(false);
writeRSSIEnd(frame);
m_state = DPMRRXS_NONE;
m_endPtr = NOENDPTR;
m_averagePtr = NOAVEPTR;
m_countdown = 0U;
m_maxCorr = 0;
}
}
bool CDPMRRX::correlateFS1()
{
if (countBits32(m_bitBuffer[m_bitPtr] ^ DPMR_FS1_SYMBOLS) <= MAX_FS1_SYMBOLS_ERRS) {
uint16_t ptr = m_dataPtr + DPMR_HEADER_FRAME_LENGTH_SAMPLES - DPMR_FS1_LENGTH_SAMPLES + DPMR_RADIO_SYMBOL_LENGTH;
if (ptr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
ptr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
q31_t corr = 0;
q15_t min = 16000;
q15_t max = -16000;
for (uint8_t i = 0U; i < DPMR_FS1_LENGTH_SYMBOLS; i++) {
q15_t val = m_buffer[ptr];
if (val > max)
max = val;
if (val < min)
min = val;
switch (DPMR_FS1_SYMBOLS_VALUES[i]) {
case +3:
corr -= (val + val + val);
break;
case +1:
corr -= val;
break;
case -1:
corr += val;
break;
default: // -3
corr += (val + val + val);
break;
}
ptr += DPMR_RADIO_SYMBOL_LENGTH;
if (ptr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
ptr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
}
if (corr > m_maxCorr) {
if (m_averagePtr == NOAVEPTR) {
m_centreVal = (max + min) >> 1;
q31_t v1 = (max - m_centreVal) * SCALING_FACTOR;
m_thresholdVal = q15_t(v1 >> 15);
}
uint16_t startPtr = m_dataPtr + DPMR_HEADER_FRAME_LENGTH_SAMPLES - DPMR_FS1_LENGTH_SAMPLES + DPMR_RADIO_SYMBOL_LENGTH;
if (startPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
startPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
uint8_t sync[DPMR_FS1_BYTES_LENGTH];
samplesToBits(startPtr, DPMR_FS1_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t errs = 0U;
for (uint8_t i = 0U; i < DPMR_FS1_BYTES_LENGTH; i++)
errs += countBits8(sync[i] ^ DPMR_FS1_BYTES[i]);
if (errs <= MAX_FS1_BIT_START_ERRS) {
m_maxCorr = corr;
m_lostCount = MAX_FS1_FRAMES;
m_fsPtr = m_dataPtr;
m_startPtr = startPtr;
m_endPtr = m_dataPtr + DPMR_HEADER_FRAME_LENGTH_SAMPLES - DPMR_FS1_LENGTH_SAMPLES - 1U;
if (m_endPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_endPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
return true;
}
}
}
return false;
}
bool CDPMRRX::correlateFS2()
{
if (countBits32(m_bitBuffer[m_bitPtr] ^ DPMR_FS2_SYMBOLS) <= MAX_FS2_SYMBOLS_ERRS) {
uint16_t ptr = m_dataPtr + DPMR_DATA_FRAME_LENGTH_SAMPLES - DPMR_FS2_LENGTH_SAMPLES + DPMR_RADIO_SYMBOL_LENGTH;
if (ptr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
ptr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
q31_t corr = 0;
q15_t min = 16000;
q15_t max = -16000;
for (uint8_t i = 0U; i < DPMR_FS2_LENGTH_SYMBOLS; i++) {
q15_t val = m_buffer[ptr];
if (val > max)
max = val;
if (val < min)
min = val;
switch (DPMR_FS2_SYMBOLS_VALUES[i]) {
case +3:
corr -= (val + val + val);
break;
case +1:
corr -= val;
break;
case -1:
corr += val;
break;
default: // -3
corr += (val + val + val);
break;
}
ptr += DPMR_RADIO_SYMBOL_LENGTH;
if (ptr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
ptr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
}
if (corr > m_maxCorr) {
if (m_averagePtr == NOAVEPTR) {
m_centreVal = (max + min) >> 1;
q31_t v1 = (max - m_centreVal) * SCALING_FACTOR;
m_thresholdVal = q15_t(v1 >> 15);
}
uint16_t startPtr = m_dataPtr + DPMR_DATA_FRAME_LENGTH_SAMPLES - DPMR_FS2_LENGTH_SAMPLES + DPMR_RADIO_SYMBOL_LENGTH;
if (startPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
startPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
uint8_t sync[DPMR_FS2_BYTES_LENGTH];
samplesToBits(startPtr, DPMR_FS2_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t maxErrs;
if (m_state == DPMRRXS_NONE)
maxErrs = MAX_FS2_BIT_START_ERRS;
else
maxErrs = MAX_FS2_BIT_RUN_ERRS;
uint8_t errs = 0U;
for (uint8_t i = 0U; i < DPMR_FS2_BYTES_LENGTH; i++)
errs += countBits8(sync[i] ^ DPMR_FS2_BYTES[i]);
if (errs <= maxErrs) {
m_maxCorr = corr;
m_lostCount = MAX_FS2_FRAMES;
m_fsPtr = m_dataPtr;
m_startPtr = startPtr;
m_endPtr = m_dataPtr + DPMR_DATA_FRAME_LENGTH_SAMPLES - DPMR_FS2_LENGTH_SAMPLES - 1U;
if (m_endPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_endPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
return true;
}
}
}
return false;
}
bool CDPMRRX::correlateFS3()
{
if (countBits32(m_bitBuffer[m_bitPtr] ^ DPMR_FS3_SYMBOLS) <= MAX_FS3_SYMBOLS_ERRS) {
uint16_t ptr = m_dataPtr + DPMR_END_FRAME_LENGTH_SAMPLES - DPMR_FS3_LENGTH_SAMPLES + DPMR_RADIO_SYMBOL_LENGTH;
if (ptr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
ptr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
q31_t corr = 0;
q15_t min = 16000;
q15_t max = -16000;
for (uint8_t i = 0U; i < DPMR_FS3_LENGTH_SYMBOLS; i++) {
q15_t val = m_buffer[ptr];
if (val > max)
max = val;
if (val < min)
min = val;
switch (DPMR_FS3_SYMBOLS_VALUES[i]) {
case +3:
corr -= (val + val + val);
break;
case +1:
corr -= val;
break;
case -1:
corr += val;
break;
default: // -3
corr += (val + val + val);
break;
}
ptr += DPMR_RADIO_SYMBOL_LENGTH;
if (ptr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
ptr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
}
if (corr > m_maxCorr) {
if (m_averagePtr == NOAVEPTR) {
m_centreVal = (max + min) >> 1;
q31_t v1 = (max - m_centreVal) * SCALING_FACTOR;
m_thresholdVal = q15_t(v1 >> 15);
}
uint16_t startPtr = m_dataPtr + DPMR_END_FRAME_LENGTH_SAMPLES - DPMR_FS3_LENGTH_SAMPLES + DPMR_RADIO_SYMBOL_LENGTH;
if (startPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
startPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
uint8_t sync[DPMR_FS1_BYTES_LENGTH];
samplesToBits(startPtr, DPMR_FS3_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t errs = 0U;
for (uint8_t i = 0U; i < DPMR_FS3_BYTES_LENGTH; i++)
errs += countBits8(sync[i] ^ DPMR_FS3_BYTES[i]);
if (errs <= MAX_FS3_BIT_RUN_ERRS) {
m_maxCorr = corr;
m_lostCount = MAX_FS3_FRAMES;
m_fsPtr = m_dataPtr;
m_startPtr = startPtr;
m_endPtr = m_dataPtr + DPMR_END_FRAME_LENGTH_SAMPLES - DPMR_FS3_LENGTH_SAMPLES - 1U;
if (m_endPtr >= DPMR_DATA_FRAME_LENGTH_SAMPLES)
m_endPtr -= DPMR_DATA_FRAME_LENGTH_SAMPLES;
return true;
}
}
}
return false;
}
void CDPMRRX::calculateLevels(uint16_t start, uint16_t count)
{
q15_t maxPos = -16000;
q15_t minPos = 16000;
q15_t maxNeg = 16000;
q15_t minNeg = -16000;
for (uint16_t i = 0U; i < count; i++) {
q15_t sample = m_buffer[start];
if (sample > 0) {
if (sample > maxPos)
maxPos = sample;
if (sample < minPos)
minPos = sample;
} else {
if (sample < maxNeg)
maxNeg = sample;
if (sample > minNeg)
minNeg = sample;
}
start += DPMR_RADIO_SYMBOL_LENGTH;
if (start >= DPMR_FRAME_LENGTH_SAMPLES)
start -= DPMR_FRAME_LENGTH_SAMPLES;
}
q15_t posThresh = (maxPos + minPos) >> 1;
q15_t negThresh = (maxNeg + minNeg) >> 1;
q15_t centre = (posThresh + negThresh) >> 1;
q15_t threshold = posThresh - centre;
DEBUG5("DPMRRX: pos/neg/centre/threshold", posThresh, negThresh, centre, threshold);
if (m_averagePtr == NOAVEPTR) {
for (uint8_t i = 0U; i < 16U; i++) {
m_centre[i] = centre;
m_threshold[i] = threshold;
}
m_averagePtr = 0U;
} else {
m_centre[m_averagePtr] = centre;
m_threshold[m_averagePtr] = threshold;
m_averagePtr++;
if (m_averagePtr >= 16U)
m_averagePtr = 0U;
}
m_centreVal = 0;
m_thresholdVal = 0;
for (uint8_t i = 0U; i < 16U; i++) {
m_centreVal += m_centre[i];
m_thresholdVal += m_threshold[i];
}
m_centreVal >>= 4;
m_thresholdVal >>= 4;
}
void CDPMRRX::samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold)
{
for (uint16_t i = 0U; i < count; i++) {
q15_t sample = m_buffer[start] - centre;
if (sample < -threshold) {
WRITE_BIT1(buffer, offset, false);
offset++;
WRITE_BIT1(buffer, offset, true);
offset++;
} else if (sample < 0) {
WRITE_BIT1(buffer, offset, false);
offset++;
WRITE_BIT1(buffer, offset, false);
offset++;
} else if (sample < threshold) {
WRITE_BIT1(buffer, offset, true);
offset++;
WRITE_BIT1(buffer, offset, false);
offset++;
} else {
WRITE_BIT1(buffer, offset, true);
offset++;
WRITE_BIT1(buffer, offset, true);
offset++;
}
start += DPMR_RADIO_SYMBOL_LENGTH;
if (start >= DPMR_FRAME_LENGTH_SAMPLES)
start -= DPMR_FRAME_LENGTH_SAMPLES;
}
}
void CDPMRRX::writeRSSIHeader(uint8_t* data)
{
#if defined(SEND_RSSI_DATA)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[49U] = (rssi >> 8) & 0xFFU;
data[50U] = (rssi >> 0) & 0xFFU;
serial.writeDPMRHeader(data, DPMR_HEADER_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeDPMRHeader(data, DPMR_HEADER_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeDPMRHeader(data, DPMR_HEADER_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
void CDPMRRX::writeRSSIData(uint8_t* data)
{
#if defined(SEND_RSSI_DATA)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[49U] = (rssi >> 8) & 0xFFU;
data[50U] = (rssi >> 0) & 0xFFU;
serial.writeDPMRData(data, DPMR_DATA_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeDPMRData(data, DPMR_DATA_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeDPMRData(data, DPMR_DATA_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
#endif
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2024 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
* 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"
#if defined(MODE_DPMR)
#if !defined(DPMRRX_H)
#define DPMRRX_H
#include "DPMRDefines.h"
enum DPMRRX_STATE {
DPMRRXS_NONE,
DPMRRXS_HEADER,
DPMRRXS_DATA,
DPMRRXS_END
};
class CDPMRRX {
public:
CDPMRRX();
void samples(const q15_t* samples, uint16_t* rssi, uint8_t length);
void reset();
private:
DPMRRX_STATE m_state;
uint32_t m_bitBuffer[DPMR_RADIO_SYMBOL_LENGTH];
q15_t m_buffer[DPMR_DATA_FRAME_LENGTH_SAMPLES];
uint16_t m_bitPtr;
uint16_t m_dataPtr;
uint16_t m_startPtr;
uint16_t m_endPtr;
uint16_t m_fsPtr;
uint16_t m_minFSPtr;
uint16_t m_maxFSPtr;
q31_t m_maxCorr;
uint16_t m_lostCount;
uint8_t m_countdown;
q15_t m_centre[16U];
q15_t m_centreVal;
q15_t m_threshold[16U];
q15_t m_thresholdVal;
uint8_t m_averagePtr;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
void processNone(q15_t sample);
void processHeader(q15_t sample);
void processData(q15_t sample);
void processEnd(q15_t sample);
bool correlateFS1();
bool correlateFS2();
bool correlateFS3();
void calculateLevels(uint16_t start, uint16_t count);
void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
void writeRSSIHeader(uint8_t* data);
void writeRSSIData(uint8_t* data);
void writeRSSIEnd(uint8_t* data);
};
#endif
#endif
+238
View File
@@ -0,0 +1,238 @@
/*
* Copyright (C) 2009-2018,2020,2024 by Jonathan Naylor G4KLX
* Copyright (C) 2017 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"
#if defined(MODE_DPMR)
#include "Globals.h"
#include "DPMRTX.h"
#include "DPMRDefines.h"
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179, -1548, -1769, -1795, -1597, -1172,
-544, 237, 1092, 1927, 2637, 3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739, -6442,
-6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822, 19484, 23810, 27520, 30367, 32156, 32767,
32156, 30367, 27520, 23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735, -6483, -6442,
-5739, -4544, -3043, -1431, 116, 1447, 2454, 3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172,
-1597, -1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
static q15_t DPMR_SINC_FILTER[] = {572, -1003, -253, 254, 740, 1290, 1902, 2527, 3090, 3517, 3747, 3747, 3517, 3090, 2527, 1902,
1290, 740, 254, -253, -1003, 572};
const uint16_t DPMR_SINC_FILTER_LEN = 22U;
const q15_t DPMR_LEVELA = 735;
const q15_t DPMR_LEVELB = 245;
const q15_t DPMR_LEVELC = -245;
const q15_t DPMR_LEVELD = -735;
const uint8_t DPMR_PREAMBLE[] = {0x57U, 0x75U, 0xFDU};
const uint8_t DPMR_SYNC = 0x5FU;
CDPMRTX::CDPMRTX() :
m_buffer(TX_BUFFER_LEN),
m_modFilter(),
m_sincFilter(),
m_modState(),
m_sincState(),
m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_txDelay(240U), // 200ms
m_txHang(3000U), // 5s
m_txCount(0U)
{
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
::memset(m_sincState, 0x00U, 70U * sizeof(q15_t));
m_modFilter.L = DPMR_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = RRC_0_2_FILTER_PHASE_LEN;
m_modFilter.pCoeffs = RRC_0_2_FILTER;
m_modFilter.pState = m_modState;
m_sincFilter.numTaps = DPMR_SINC_FILTER_LEN;
m_sincFilter.pState = m_sincState;
m_sincFilter.pCoeffs = DPMR_SINC_FILTER;
}
void CDPMRTX::process()
{
if (m_poLen == 0U && m_buffer.getData() > 0U) {
if (!m_tx) {
for (uint16_t i = 0U; i < m_txDelay; i++)
m_poBuffer[m_poLen++] = DPMR_SYNC;
m_poBuffer[m_poLen++] = DPMR_PREAMBLE[0U];
m_poBuffer[m_poLen++] = DPMR_PREAMBLE[1U];
m_poBuffer[m_poLen++] = DPMR_PREAMBLE[2U];
} else {
for (uint8_t i = 0U; i < DPMR_FRAME_LENGTH_BYTES; i++) {
uint8_t c = 0U;
m_buffer.get(c);
m_poBuffer[m_poLen++] = c;
}
}
m_poPtr = 0U;
}
if (m_poLen > 0U) {
uint16_t space = io.getSpace();
while (space > (4U * DPMR_RADIO_SYMBOL_LENGTH)) {
uint8_t c = m_poBuffer[m_poPtr++];
writeByte(c);
space -= 4U * DPMR_RADIO_SYMBOL_LENGTH;
if (m_duplex)
m_txCount = m_txHang;
if (m_poPtr >= m_poLen) {
m_poPtr = 0U;
m_poLen = 0U;
return;
}
}
} else if (m_txCount > 0U) {
// Transmit silence until the hang timer has expired.
uint16_t space = io.getSpace();
while (space > (4U * DPMR_RADIO_SYMBOL_LENGTH)) {
writeSilence();
space -= 4U * DPMR_RADIO_SYMBOL_LENGTH;
m_txCount--;
if (m_txCount == 0U)
return;
}
}
}
uint8_t CDPMRTX::writeHeader(const uint8_t* data, uint16_t length)
{
if (length != (DPMR_HEADER_FRAME_LENGTH_BYTES + 1U))
return 4U;
uint16_t space = m_buffer.getSpace();
if (space < DPMR_HEADER_FRAME_LENGTH_BYTES)
return 5U;
for (uint8_t i = 0U; i < DPMR_HEADER_FRAME_LENGTH_BYTES; i++)
m_buffer.put(data[i + 1U]);
return 0U;
}
uint8_t CDPMRTX::writeData(const uint8_t* data, uint16_t length)
{
if (length != (DPMR_DATA_FRAME_LENGTH_BYTES + 1U))
return 4U;
uint16_t space = m_buffer.getSpace();
if (space < DPMR_DATA_FRAME_LENGTH_BYTES)
return 5U;
for (uint8_t i = 0U; i < DPMR_DATA_FRAME_LENGTH_BYTES; i++)
m_buffer.put(data[i + 1U]);
return 0U;
}
uint8_t CDPMRTX::writeEOT(const uint8_t* data, uint16_t length)
{
if (length != (DPMR_END_FRAME_LENGTH_BYTES + 1U))
return 4U;
uint16_t space = m_buffer.getSpace();
if (space < DPMR_END_FRAME_LENGTH_BYTES)
return 5U;
for (uint8_t i = 0U; i < DPMR_END_FRAME_LENGTH_BYTES; i++)
m_buffer.put(data[i + 1U]);
return 0U;
}
void CDPMRTX::writeByte(uint8_t c)
{
q15_t inBuffer[4U];
q15_t intBuffer[DPMR_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[DPMR_RADIO_SYMBOL_LENGTH * 4U];
const uint8_t MASK = 0xC0U;
for (uint8_t i = 0U; i < 4U; i++, c <<= 2) {
switch (c & MASK) {
case 0xC0U:
inBuffer[i] = DPMR_LEVELA;
break;
case 0x80U:
inBuffer[i] = DPMR_LEVELB;
break;
case 0x00U:
inBuffer[i] = DPMR_LEVELC;
break;
default:
inBuffer[i] = DPMR_LEVELD;
break;
}
}
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U);
::arm_fir_fast_q15(&m_sincFilter, intBuffer, outBuffer, DPMR_RADIO_SYMBOL_LENGTH * 4U);
io.write(STATE_DPMR, outBuffer, DPMR_RADIO_SYMBOL_LENGTH * 4U);
}
void CDPMRTX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t intBuffer[DPMR_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[DPMR_RADIO_SYMBOL_LENGTH * 4U];
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U);
::arm_fir_fast_q15(&m_sincFilter, intBuffer, outBuffer, DPMR_RADIO_SYMBOL_LENGTH * 4U);
io.write(STATE_DPMR, outBuffer, DPMR_RADIO_SYMBOL_LENGTH * 4U);
}
void CDPMRTX::setTXDelay(uint8_t delay)
{
m_txDelay = 300U + uint16_t(delay) * 6U; // 500ms + tx delay
if (m_txDelay > 1200U)
m_txDelay = 1200U;
}
uint8_t CDPMRTX::getSpace() const
{
return m_buffer.getSpace() / DPMR_FRAME_LENGTH_BYTES;
}
void CDPMRTX::setParams(uint8_t txHang)
{
m_txHang = txHang * 600U;
}
#endif
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2024 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
* 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"
#if defined(MODE_DPMR)
#if !defined(DPMRTX_H)
#define DPMRTX_H
#include "RingBuffer.h"
class CDPMRTX {
public:
CDPMRTX();
uint8_t writeHeader(const uint8_t* data, uint16_t length);
uint8_t writeData(const uint8_t* data, uint16_t length);
uint8_t writeEOT(const uint8_t* data, uint16_t length);
void process();
void setTXDelay(uint8_t delay);
uint8_t getSpace() const;
void setParams(uint8_t txHang);
private:
CRingBuffer<uint8_t> m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter;
arm_fir_instance_q15 m_sincFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
q15_t m_sincState[70U]; // NoTaps + BlockSize - 1, 22 + 40 - 1 plus some spare
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay;
uint32_t m_txHang;
uint32_t m_txCount;
void writeByte(uint8_t c);
void writeSilence();
};
#endif
#endif
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
+54 -30
View File
@@ -19,8 +19,24 @@
#if !defined(GLOBALS_H) #if !defined(GLOBALS_H)
#define GLOBALS_H #define GLOBALS_H
#if defined(STM32F4XX)
#include "stm32f4xx.h"
#elif defined(STM32F7XX)
#include "stm32f7xx.h"
#else
#include <Arduino.h> #include <Arduino.h>
#undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h. #undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h.
#endif
#if defined(__SAM3X8E__)
#define ARM_MATH_CM3
#elif defined(STM32F7XX)
#define ARM_MATH_CM7
#elif defined(STM32F4XX) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define ARM_MATH_CM4
#else
#error "Unknown processor type"
#endif
#include <arm_math.h> #include <arm_math.h>
@@ -33,6 +49,7 @@ enum MMDVM_STATE {
STATE_NXDN = 5, STATE_NXDN = 5,
STATE_POCSAG = 6, STATE_POCSAG = 6,
STATE_M17 = 7, STATE_M17 = 7,
STATE_DPMR = 8,
STATE_FM = 10, STATE_FM = 10,
STATE_AX25 = 11, STATE_AX25 = 11,
@@ -58,38 +75,39 @@ enum MMDVM_STATE {
}; };
#include "SerialPort.h" #include "SerialPort.h"
#include "DMRIdleRX.h"
#include "POCSAG/CalPOCSAG.h" #include "DMRDMORX.h"
#include "DStar/CalDStarRX.h" #include "DMRDMOTX.h"
#include "DStar/CalDStarTX.h" #include "DStarRX.h"
#include "POCSAG/POCSAGTX.h" #include "DStarTX.h"
#include "DStar/DStarRX.h" #include "DPMRRX.h"
#include "DStar/DStarTX.h" #include "DPMRTX.h"
#include "DMR/DMRIdleRX.h" #include "DMRRX.h"
#include "DMR/DMRDMORX.h" #include "DMRTX.h"
#include "DMR/DMRDMOTX.h" #include "YSFRX.h"
#include "NXDN/CalNXDN.h" #include "YSFTX.h"
#include "NXDN/NXDNRX.h" #include "P25RX.h"
#include "NXDN/NXDNTX.h" #include "P25TX.h"
#include "AX25/AX25RX.h" #include "M17RX.h"
#include "AX25/AX25TX.h" #include "M17TX.h"
#include "DMR/CalDMR.h" #include "NXDNRX.h"
#include "P25/CalP25.h" #include "NXDNTX.h"
#include "M17/CalM17.h" #include "POCSAGTX.h"
#include "DMR/DMRRX.h" #include "CalDStarRX.h"
#include "DMR/DMRTX.h" #include "CalDStarTX.h"
#include "YSF/YSFRX.h" #include "CalFM.h"
#include "YSF/YSFTX.h" #include "CalDMR.h"
#include "P25/P25RX.h" #include "CalP25.h"
#include "P25/P25TX.h" #include "CalNXDN.h"
#include "M17/M17RX.h" #include "CalPOCSAG.h"
#include "M17/M17TX.h"
#include "FM/CalFM.h"
#include "CalRSSI.h" #include "CalRSSI.h"
#include "CWIdTX.h" #include "CWIdTX.h"
#include "FM/FM.h" #include "AX25RX.h"
#include "AX25TX.h"
#include "CalM17.h"
#include "Debug.h" #include "Debug.h"
#include "IO.h" #include "IO.h"
#include "FM.h"
const uint8_t MARK_SLOT1 = 0x08U; const uint8_t MARK_SLOT1 = 0x08U;
const uint8_t MARK_SLOT2 = 0x04U; const uint8_t MARK_SLOT2 = 0x04U;
@@ -100,8 +118,6 @@ const uint16_t RX_BLOCK_SIZE = 2U;
const uint16_t TX_RINGBUFFER_SIZE = 500U; const uint16_t TX_RINGBUFFER_SIZE = 500U;
const uint16_t RX_RINGBUFFER_SIZE = 600U; const uint16_t RX_RINGBUFFER_SIZE = 600U;
const uint32_t SAMPLE_RATE = 24000U;
#if defined(__MK20DX256__) #if defined(__MK20DX256__)
const uint16_t TX_BUFFER_LEN = 2000U; const uint16_t TX_BUFFER_LEN = 2000U;
#else #else
@@ -117,6 +133,7 @@ extern bool m_p25Enable;
extern bool m_nxdnEnable; extern bool m_nxdnEnable;
extern bool m_pocsagEnable; extern bool m_pocsagEnable;
extern bool m_m17Enable; extern bool m_m17Enable;
extern bool m_dpmrEnable;
extern bool m_fmEnable; extern bool m_fmEnable;
extern bool m_ax25Enable; extern bool m_ax25Enable;
@@ -178,6 +195,13 @@ extern CM17TX m17TX;
extern CCalM17 calM17; extern CCalM17 calM17;
#endif #endif
#if defined(MODE_DPMR)
extern CDPMRRX dpmrRX;
extern CDPMRTX dpmrTX;
extern CCalNXDN calNXDN;
#endif
#if defined(MODE_FM) #if defined(MODE_FM)
extern CFM fm; extern CFM fm;
extern CCalFM calFM; extern CCalFM calFM;
+149 -281
View File
@@ -20,7 +20,6 @@
#include "Config.h" #include "Config.h"
#include "Globals.h" #include "Globals.h"
#include "IOPins.h"
#include "IO.h" #include "IO.h"
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
@@ -45,12 +44,13 @@ static q15_t RRC_0_5_FILTER[] = {-147, -88, 72, 220, 223, 46, -197, -285, -79, 3
const uint16_t RRC_0_5_FILTER_LEN = 42U; const uint16_t RRC_0_5_FILTER_LEN = 42U;
#endif #endif
#if defined(MODE_NXDN) #if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
#if defined(USE_NXDN_BOXCAR)
// One symbol boxcar filter // One symbol boxcar filter
static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000}; static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000};
const uint16_t BOXCAR10_FILTER_LEN = 10U; const uint16_t BOXCAR10_FILTER_LEN = 10U;
#else #endif
#if defined(MODE_DPMR) || (defined(MODE_NXDN) && !defined(USE_NXDN_BOXCAR))
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB // Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819, static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184, 483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
@@ -63,7 +63,6 @@ static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 21
12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790}; 12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790};
const uint16_t NXDN_ISINC_FILTER_LEN = 32U; const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
#endif #endif
#endif
#if defined(MODE_DSTAR) #if defined(MODE_DSTAR)
// Generated using gaussfir(0.5, 4, 5) in MATLAB // Generated using gaussfir(0.5, 4, 5) in MATLAB
@@ -80,7 +79,6 @@ const uint16_t BOXCAR5_FILTER_LEN = 6U;
const uint16_t DC_OFFSET = 2048U; const uint16_t DC_OFFSET = 2048U;
CIO::CIO() : CIO::CIO() :
m_timer(TIM2),
m_started(false), m_started(false),
m_rxBuffer(RX_RINGBUFFER_SIZE), m_rxBuffer(RX_RINGBUFFER_SIZE),
m_txBuffer(TX_RINGBUFFER_SIZE), m_txBuffer(TX_RINGBUFFER_SIZE),
@@ -105,17 +103,16 @@ m_rrc02State2(),
m_boxcar5Filter(), m_boxcar5Filter(),
m_boxcar5State(), m_boxcar5State(),
#endif #endif
#if defined(MODE_NXDN) #if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
#if defined(USE_NXDN_BOXCAR)
m_boxcar10Filter(), m_boxcar10Filter(),
m_boxcar10State(), m_boxcar10State(),
#else #endif
#if defined(MODE_DPMR) || (defined(MODE_NXDN) && !defined(USE_NXDN_BOXCAR))
m_nxdnFilter(), m_nxdnFilter(),
m_nxdnISincFilter(), m_nxdnISincFilter(),
m_nxdnState(), m_nxdnState(),
m_nxdnISincState(), m_nxdnISincState(),
#endif #endif
#endif
#if defined(MODE_M17) #if defined(MODE_M17)
m_rrc05Filter(), m_rrc05Filter(),
m_rrc05State(), m_rrc05State(),
@@ -129,6 +126,7 @@ m_ysfTXLevel(128 * 128),
m_p25TXLevel(128 * 128), m_p25TXLevel(128 * 128),
m_nxdnTXLevel(128 * 128), m_nxdnTXLevel(128 * 128),
m_m17TXLevel(128 * 128), m_m17TXLevel(128 * 128),
m_dpmrTXLevel(128 * 128),
m_pocsagTXLevel(128 * 128), m_pocsagTXLevel(128 * 128),
m_fmTXLevel(128 * 128), m_fmTXLevel(128 * 128),
m_ax25TXLevel(128 * 128), m_ax25TXLevel(128 * 128),
@@ -179,13 +177,14 @@ m_lockout(false)
m_boxcar5Filter.pCoeffs = BOXCAR5_FILTER; m_boxcar5Filter.pCoeffs = BOXCAR5_FILTER;
#endif #endif
#if defined(MODE_NXDN) #if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
#if defined(USE_NXDN_BOXCAR)
::memset(m_boxcar10State, 0x00U, 40U * sizeof(q15_t)); ::memset(m_boxcar10State, 0x00U, 40U * sizeof(q15_t));
m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN; m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN;
m_boxcar10Filter.pState = m_boxcar10State; m_boxcar10Filter.pState = m_boxcar10State;
m_boxcar10Filter.pCoeffs = BOXCAR10_FILTER; m_boxcar10Filter.pCoeffs = BOXCAR10_FILTER;
#else #endif
#if defined(MODE_DPMR) || (defined(MODE_NXDN) && !defined(USE_NXDN_BOXCAR))
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t)); ::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t)); ::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
@@ -197,7 +196,6 @@ m_lockout(false)
m_nxdnISincFilter.pState = m_nxdnISincState; m_nxdnISincFilter.pState = m_nxdnISincState;
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER; m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
#endif #endif
#endif
#if defined(MODE_M17) #if defined(MODE_M17)
::memset(m_rrc05State, 0x00U, 70U * sizeof(q15_t)); ::memset(m_rrc05State, 0x00U, 70U * sizeof(q15_t));
@@ -206,7 +204,7 @@ m_lockout(false)
m_rrc05Filter.pCoeffs = RRC_0_5_FILTER; m_rrc05Filter.pCoeffs = RRC_0_5_FILTER;
#endif #endif
initHardware(); initInt();
selfTest(); selfTest();
} }
@@ -219,106 +217,122 @@ void CIO::selfTest()
ledValue = !ledValue; ledValue = !ledValue;
// We exclude PTT to avoid trigger the transmitter // We exclude PTT to avoid trigger the transmitter
setLED(ledValue); setLEDInt(ledValue);
setCOS(ledValue); setCOSInt(ledValue);
#if defined(MODE_LEDS) #if defined(MODE_LEDS)
setDStar(ledValue); setDStarInt(ledValue);
setDMR(ledValue); setDMRInt(ledValue);
setYSF(ledValue); setYSFInt(ledValue);
setP25(ledValue); setP25Int(ledValue);
#if !defined(USE_ALTERNATE_NXDN_LEDS) #if !defined(USE_ALTERNATE_NXDN_LEDS)
setNXDN(ledValue); setNXDNInt(ledValue);
#endif #endif
#if !defined(USE_ALTERNATE_M17_LEDS) #if !defined(USE_ALTERNATE_M17_LEDS)
setM17(ledValue); setM17Int(ledValue);
#endif #endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS) #if !defined(USE_ALTERNATE_POCSAG_LEDS)
setPOCSAG(ledValue); setPOCSAGInt(ledValue);
#endif #endif
#if !defined(USE_ALTERNATE_FM_LEDS) #if !defined(USE_ALTERNATE_FM_LEDS)
setFM(ledValue); setFMInt(ledValue);
#endif
#if !defined(USE_ALTERNATE_DPMR_LEDS)
setDPMRInt(ledValue);
#endif #endif
#endif #endif
::delay(250); delayInt(250);
} }
#if defined(MODE_LEDS) #if defined(MODE_LEDS)
setDStar(false); setDStarInt(false);
setDMR(false); setDMRInt(false);
setYSF(false); setYSFInt(false);
setP25(false); setP25Int(false);
#if !defined(USE_ALTERNATE_NXDN_LEDS) #if !defined(USE_ALTERNATE_NXDN_LEDS)
setNXDN(false); setNXDNInt(false);
#endif #endif
#if !defined(USE_ALTERNATE_M17_LEDS) #if !defined(USE_ALTERNATE_M17_LEDS)
setM17(false); setM17Int(false);
#endif #endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS) #if !defined(USE_ALTERNATE_POCSAG_LEDS)
setPOCSAG(false); setPOCSAGInt(false);
#endif #endif
#if !defined(USE_ALTERNATE_FM_LEDS) #if !defined(USE_ALTERNATE_FM_LEDS)
setFM(false); setFMInt(false);
#endif #endif
setDStar(true); #if !defined(USE_ALTERNATE_DPMR_LEDS)
setDPMRInt(false);
#endif
setDStarInt(true);
::delay(250); delayInt(250);
setDMR(true); setDMRInt(true);
::delay(250); delayInt(250);
setYSF(true); setYSFInt(true);
::delay(250); delayInt(250);
setP25(true); setP25Int(true);
#if !defined(USE_ALTERNATE_NXDN_LEDS) #if !defined(USE_ALTERNATE_NXDN_LEDS)
::delay(250); delayInt(250);
setNXDN(true); setNXDNInt(true);
#endif #endif
#if !defined(USE_ALTERNATE_M17_LEDS) #if !defined(USE_ALTERNATE_M17_LEDS)
::delay(250); delayInt(250);
setM17(true); setM17Int(true);
#endif #endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS) #if !defined(USE_ALTERNATE_POCSAG_LEDS)
::delay(250); delayInt(250);
setPOCSAG(true); setPOCSAGInt(true);
#endif #endif
#if !defined(USE_ALTERNATE_FM_LEDS) #if !defined(USE_ALTERNATE_FM_LEDS)
::delay(250); delayInt(250);
setFM(true); setFMInt(true);
#endif
::delay(250); #if !defined(USE_ALTERNATE_DPMR_LEDS)
setFM(false); delayInt(250);
setDPMRInt(true);
delayInt(250);
setDPMRInt(false);
#endif
#if !defined(USE_ALTERNATE_FM_LEDS)
delayInt(250);
setFMInt(true);
#endif #endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS) #if !defined(USE_ALTERNATE_POCSAG_LEDS)
::delay(250); delayInt(250);
setPOCSAG(false); setPOCSAGInt(false);
#endif #endif
#if !defined(USE_ALTERNATE_M17_LEDS) #if !defined(USE_ALTERNATE_M17_LEDS)
::delay(250); delayInt(250);
setM17(false); setM17Int(false);
#endif #endif
#if !defined(USE_ALTERNATE_NXDN_LEDS) #if !defined(USE_ALTERNATE_NXDN_LEDS)
::delay(250); delayInt(250);
setNXDN(false); setNXDNInt(false);
#endif #endif
::delay(250); delayInt(250);
setP25(false); setP25Int(false);
::delay(250); delayInt(250);
setYSF(false); setYSFInt(false);
::delay(250); delayInt(250);
setDMR(false); setDMRInt(false);
::delay(250); delayInt(250);
setDStar(false); setDStarInt(false);
#endif #endif
} }
@@ -327,7 +341,7 @@ void CIO::start()
if (m_started) if (m_started)
return; return;
startHardware(); startInt();
m_started = true; m_started = true;
@@ -336,10 +350,11 @@ void CIO::start()
void CIO::process() void CIO::process()
{ {
m_ledCount++;
if (m_started) { if (m_started) {
// Two seconds timeout // Two seconds timeout
if (m_watchdog >= 48000U) { if (m_watchdog >= 48000U) {
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_M17 || m_modemState == STATE_POCSAG) { if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_M17 || m_modemState == STATE_DPMR || m_modemState == STATE_POCSAG) {
#if defined(MODE_DMR) #if defined(MODE_DMR)
if (m_modemState == STATE_DMR && m_tx) if (m_modemState == STATE_DMR && m_tx)
dmrTX.setStart(false); dmrTX.setStart(false);
@@ -351,31 +366,30 @@ void CIO::process()
} }
#if defined(CONSTANT_SRV_LED) #if defined(CONSTANT_SRV_LED)
setLED(true); setLEDInt(true);
#else #else
if (m_ledCount >= 24000U) { if (m_ledCount >= 24000U) {
m_ledCount = 0U; m_ledCount = 0U;
m_ledValue = !m_ledValue; m_ledValue = !m_ledValue;
setLED(m_ledValue); setLEDInt(m_ledValue);
} }
#endif #endif
} else { } else {
m_ledCount++;
if (m_ledCount >= 240000U) { if (m_ledCount >= 240000U) {
m_ledCount = 0U; m_ledCount = 0U;
m_ledValue = !m_ledValue; m_ledValue = !m_ledValue;
setLED(m_ledValue); setLEDInt(m_ledValue);
} }
return; return;
} }
if (m_useCOSAsLockout) if (m_useCOSAsLockout)
m_lockout = getCOS(); m_lockout = getCOSInt();
// Switch off the transmitter if needed // Switch off the transmitter if needed
if (m_txBuffer.getData() == 0U && m_tx) { if (m_txBuffer.getData() == 0U && m_tx) {
m_tx = false; m_tx = false;
setPTT(m_pttInvert ? true : false); setPTTInt(m_pttInvert ? true : false);
DEBUG1("TX OFF"); DEBUG1("TX OFF");
} }
@@ -504,9 +518,25 @@ void CIO::process()
} }
#endif #endif
#if defined(MODE_DPMR)
if (m_dpmrEnable) {
q15_t DPMRValsTmp[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, DPMRValsTmp, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_nxdnFilter, samples, DPMRValsTmp, RX_BLOCK_SIZE);
#endif
q15_t DPMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnISincFilter, DPMRValsTmp, DPMRVals, RX_BLOCK_SIZE);
dpmrRX.samples(DPMRVals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_FM) #if defined(MODE_FM)
if (m_fmEnable) { if (m_fmEnable) {
bool cos = getCOS(); bool cos = getCOSInt();
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE); fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
#else #else
@@ -625,9 +655,27 @@ void CIO::process()
} }
#endif #endif
#if defined(MODE_DPMR)
else if (m_modemState == STATE_DPMR) {
if (m_dpmrEnable) {
q15_t DPMRValsTmp[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, DPMRValsTmp, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_nxdnFilter, samples, DPMRValsTmp, RX_BLOCK_SIZE);
#endif
q15_t DPMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnISincFilter, DPMRValsTmp, DPMRVals, RX_BLOCK_SIZE);
dpmrRX.samples(DPMRVals, rssi, RX_BLOCK_SIZE);
}
}
#endif
#if defined(MODE_FM) #if defined(MODE_FM)
else if (m_modemState == STATE_FM) { else if (m_modemState == STATE_FM) {
bool cos = getCOS(); bool cos = getCOSInt();
#if defined(USE_DCBLOCKER) #if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE); fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
@@ -672,7 +720,7 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
// Switch the transmitter on if needed // Switch the transmitter on if needed
if (!m_tx) { if (!m_tx) {
m_tx = true; m_tx = true;
setPTT(m_pttInvert ? false : true); setPTTInt(m_pttInvert ? false : true);
DEBUG1("TX ON"); DEBUG1("TX ON");
} }
@@ -696,6 +744,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
case STATE_M17: case STATE_M17:
txLevel = m_m17TXLevel; txLevel = m_m17TXLevel;
break; break;
case STATE_DPMR:
txLevel = m_dpmrTXLevel;
break;
case STATE_POCSAG: case STATE_POCSAG:
txLevel = m_pocsagTXLevel; txLevel = m_pocsagTXLevel;
break; break;
@@ -734,7 +785,7 @@ uint16_t CIO::getSpace() const
void CIO::setDecode(bool dcd) void CIO::setDecode(bool dcd)
{ {
if (dcd != m_dcd) if (dcd != m_dcd)
setCOS(dcd ? true : false); setCOSInt(dcd ? true : false);
m_dcd = dcd; m_dcd = dcd;
} }
@@ -751,26 +802,28 @@ void CIO::setMode(MMDVM_STATE state)
#if defined(MODE_LEDS) #if defined(MODE_LEDS)
switch (m_modemState) { switch (m_modemState) {
case STATE_DSTAR: setDStar(false); break; case STATE_DSTAR: setDStarInt(false); break;
case STATE_DMR: setDMR(false); break; case STATE_DMR: setDMRInt(false); break;
case STATE_YSF: setYSF(false); break; case STATE_YSF: setYSFInt(false); break;
case STATE_P25: setP25(false); break; case STATE_P25: setP25Int(false); break;
case STATE_NXDN: setNXDN(false); break; case STATE_NXDN: setNXDNInt(false); break;
case STATE_M17: setM17(false); break; case STATE_M17: setM17Int(false); break;
case STATE_POCSAG: setPOCSAG(false); break; case STATE_DPMR: setDPMRInt(false); break;
case STATE_FM: setFM(false); break; case STATE_POCSAG: setPOCSAGInt(false); break;
case STATE_FM: setFMInt(false); break;
default: break; default: break;
} }
switch (state) { switch (state) {
case STATE_DSTAR: setDStar(true); break; case STATE_DSTAR: setDStarInt(true); break;
case STATE_DMR: setDMR(true); break; case STATE_DMR: setDMRInt(true); break;
case STATE_YSF: setYSF(true); break; case STATE_YSF: setYSFInt(true); break;
case STATE_P25: setP25(true); break; case STATE_P25: setP25Int(true); break;
case STATE_NXDN: setNXDN(true); break; case STATE_NXDN: setNXDNInt(true); break;
case STATE_M17: setM17(true); break; case STATE_M17: setM17Int(true); break;
case STATE_POCSAG: setPOCSAG(true); break; case STATE_DPMR: setDPMRInt(true); break;
case STATE_FM: setFM(true); break; case STATE_POCSAG: setPOCSAGInt(true); break;
case STATE_FM: setFMInt(true); break;
default: break; default: break;
} }
#endif #endif
@@ -778,7 +831,7 @@ void CIO::setMode(MMDVM_STATE state)
m_modemState = state; m_modemState = state;
} }
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout) void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t dpmrTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
{ {
m_pttInvert = pttInvert; m_pttInvert = pttInvert;
@@ -790,6 +843,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_p25TXLevel = q15_t(p25TXLevel * 128); m_p25TXLevel = q15_t(p25TXLevel * 128);
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128); m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
m_m17TXLevel = q15_t(m17TXLevel * 128); m_m17TXLevel = q15_t(m17TXLevel * 128);
m_dpmrTXLevel = q15_t(dpmrTXLevel * 128);
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128); m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
m_fmTXLevel = q15_t(fmTXLevel * 128); m_fmTXLevel = q15_t(fmTXLevel * 128);
m_ax25TXLevel = q15_t(ax25TXLevel * 128); m_ax25TXLevel = q15_t(ax25TXLevel * 128);
@@ -809,6 +863,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_p25TXLevel = -m_p25TXLevel; m_p25TXLevel = -m_p25TXLevel;
m_nxdnTXLevel = -m_nxdnTXLevel; m_nxdnTXLevel = -m_nxdnTXLevel;
m_m17TXLevel = -m_m17TXLevel; m_m17TXLevel = -m_m17TXLevel;
m_dpmrTXLevel = -m_dpmrTXLevel;
m_pocsagTXLevel = -m_pocsagTXLevel; m_pocsagTXLevel = -m_pocsagTXLevel;
} }
} }
@@ -846,190 +901,3 @@ bool CIO::hasLockout() const
{ {
return m_lockout; return m_lockout;
} }
void IRQHandler()
{
io.interrupt();
}
void CIO::interrupt()
{
TSample sample = {DC_OFFSET, MARK_NONE};
uint16_t rawRSSI = 0U;
m_txBuffer.get(sample);
::analogWrite(PIN_TX, sample.sample);
sample.sample = ::analogRead(PIN_RX);
#if defined(SEND_RSSI_DATA)
rawRSSI = ::analogRead(PIN_RSSI);
#endif
m_rxBuffer.put(sample);
m_rssiBuffer.put(rawRSSI);
m_ledCount++;
m_watchdog++;
}
void CIO::initHardware()
{
#if defined(PIN_COS)
::pinMode(PIN_COS, INPUT);
#endif
#if defined(PIN_LED)
::pinMode(PIN_LED, OUTPUT);
#endif
#if defined(PIN_PTT)
::pinMode(PIN_PTT, OUTPUT);
#endif
#if defined(PIN_COSLED)
::pinMode(PIN_COSLED, OUTPUT);
#endif
#if defined(MODE_LEDS)
#if defined(PIN_DSTAR)
::pinMode(PIN_DSTAR, OUTPUT);
#endif
#if defined(PIN_DMR)
::pinMode(PIN_DMR, OUTPUT);
#endif
#if defined(PIN_YSF)
::pinMode(PIN_YSF, OUTPUT);
#endif
#if defined(PIN_P25)
::pinMode(PIN_P25, OUTPUT);
#endif
#if defined(PIN_NXDN) && !defined(USE_ALTERNATE_NXDN_LEDS)
::pinMode(PIN_NXDN, OUTPUT);
#endif
#if defined(PIN_POCSAG) && !defined(USE_ALTERNATE_POCSAG_LEDS)
::pinMode(PIN_POCSAG, OUTPUT);
#endif
#if defined(PIN_FM) && !defined(USE_ALTERNATE_FM_LEDS)
::pinMode(PIN_FM, OUTPUT);
#endif
#if defined(PIN_M17) && !defined(USE_ALTERNATE_M17_LEDS)
::pinMode(PIN_M17, OUTPUT);
#endif
#endif
::analogReadResolution(12);
::analogWriteResolution(12);
m_timer.setPrescaleFactor((SystemCoreClock / (6 * SAMPLE_RATE)) - 1);
m_timer.setOverflow(2);
m_timer.attachInterrupt(IRQHandler);
m_timer.refresh(); // Make register changes take effect
}
void CIO::startHardware()
{
m_timer.resume();
}
bool CIO::getCOS()
{
return ::digitalRead(PIN_COS) == HIGH;
}
void CIO::setLED(bool on)
{
::digitalWrite(PIN_LED, on ? HIGH : LOW);
}
void CIO::setPTT(bool on)
{
::digitalWrite(PIN_PTT, on ? HIGH : LOW);
}
void CIO::setCOS(bool on)
{
::digitalWrite(PIN_COSLED, on ? HIGH : LOW);
}
void CIO::setDStar(bool on)
{
#if defined(MODE_LEDS) && defined(PIN_DSTAR)
::digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
#endif
}
void CIO::setDMR(bool on)
{
#if defined(MODE_LEDS) && defined(PIN_DMR)
::digitalWrite(PIN_DMR, on ? HIGH : LOW);
#endif
}
void CIO::setYSF(bool on)
{
#if defined(MODE_LEDS) && defined(PIN_YSF)
::digitalWrite(PIN_YSF, on ? HIGH : LOW);
#endif
}
void CIO::setP25(bool on)
{
#if defined(MODE_LEDS) && defined(PIN_P25)
::digitalWrite(PIN_P25, on ? HIGH : LOW);
#endif
}
void CIO::setNXDN(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_NXDN_LEDS)
::digitalWrite(PIN_YSF, on ? HIGH : LOW);
::digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
#if defined(PIN_NXDN)
::digitalWrite(PIN_NXDN, on ? HIGH : LOW);
#endif
#endif
#endif
}
void CIO::setM17(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_M17_LEDS)
::digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
::digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
#if defined(PIN_M17)
::digitalWrite(PIN_M17, on ? HIGH : LOW);
#endif
#endif
#endif
}
void CIO::setPOCSAG(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_POCSAG_LEDS)
::digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
::digitalWrite(PIN_DMR, on ? HIGH : LOW);
#else
#if defined(PIN_POCSAG)
::digitalWrite(PIN_POCSAG, on ? HIGH : LOW);
#endif
#endif
#endif
}
void CIO::setFM(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_FM_LEDS)
::digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
::digitalWrite(PIN_YSF, on ? HIGH : LOW);
#else
#if defined(PIN_FM)
::digitalWrite(PIN_FM, on ? HIGH : LOW);
#endif
#endif
#endif
}
+28 -22
View File
@@ -46,7 +46,7 @@ public:
void interrupt(); void interrupt();
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout); void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t dpmrLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
void getOverflow(bool& adcOverflow, bool& dacOverflow); void getOverflow(bool& adcOverflow, bool& dacOverflow);
@@ -58,11 +58,13 @@ public:
void resetWatchdog(); void resetWatchdog();
uint32_t getWatchdog(); uint32_t getWatchdog();
uint8_t getCPU() const;
void getUDID(uint8_t* buffer);
void selfTest(); void selfTest();
private: private:
HardwareTimer m_timer;
bool m_started; bool m_started;
CRingBuffer<TSample> m_rxBuffer; CRingBuffer<TSample> m_rxBuffer;
@@ -94,17 +96,17 @@ private:
q15_t m_boxcar5State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare q15_t m_boxcar5State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
#endif #endif
#if defined(MODE_NXDN) #if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
#if defined(USE_NXDN_BOXCAR)
arm_fir_instance_q15 m_boxcar10Filter; arm_fir_instance_q15 m_boxcar10Filter;
q15_t m_boxcar10State[40U]; // NoTaps + BlockSize - 1, 10 + 20 - 1 plus some spare q15_t m_boxcar10State[40U]; // NoTaps + BlockSize - 1, 10 + 20 - 1 plus some spare
#else #endif
#if defined(MODE_DPMR) || (defined(MODE_NXDN) && !defined(USE_NXDN_BOXCAR))
arm_fir_instance_q15 m_nxdnFilter; arm_fir_instance_q15 m_nxdnFilter;
arm_fir_instance_q15 m_nxdnISincFilter; arm_fir_instance_q15 m_nxdnISincFilter;
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
#endif #endif
#endif
#if defined(MODE_M17) #if defined(MODE_M17)
arm_fir_instance_q15 m_rrc05Filter; arm_fir_instance_q15 m_rrc05Filter;
@@ -120,6 +122,7 @@ private:
q15_t m_p25TXLevel; q15_t m_p25TXLevel;
q15_t m_nxdnTXLevel; q15_t m_nxdnTXLevel;
q15_t m_m17TXLevel; q15_t m_m17TXLevel;
q15_t m_dpmrTXLevel;
q15_t m_pocsagTXLevel; q15_t m_pocsagTXLevel;
q15_t m_fmTXLevel; q15_t m_fmTXLevel;
q15_t m_ax25TXLevel; q15_t m_ax25TXLevel;
@@ -141,24 +144,27 @@ private:
bool m_lockout; bool m_lockout;
// Hardware access routines // Hardware specific routines
void initHardware(); void initInt();
void startHardware(); void startInt();
bool getCOS(); bool getCOSInt();
void setLED(bool on); void setLEDInt(bool on);
void setPTT(bool on); void setPTTInt(bool on);
void setCOS(bool on); void setCOSInt(bool on);
void setDStar(bool on); void setDStarInt(bool on);
void setDMR(bool on); void setDMRInt(bool on);
void setYSF(bool on); void setYSFInt(bool on);
void setP25(bool on); void setP25Int(bool on);
void setNXDN(bool on); void setNXDNInt(bool on);
void setPOCSAG(bool on); void setPOCSAGInt(bool on);
void setM17(bool on); void setM17Int(bool on);
void setFM(bool on); void setDPMRInt(bool on);
void setFMInt(bool on);
void delayInt(unsigned int dly);
}; };
#endif #endif
+323
View File
@@ -0,0 +1,323 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* 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(__SAM3X8E__)
// An Arduino Due
#if defined(ARDUINO_DUE_PAPA)
#define PIN_COS 7
#define PIN_PTT 8
#define PIN_COSLED 11
#define PIN_DSTAR 16
#define PIN_DMR 17
#define PIN_YSF 18
#define PIN_P25 19
#define PIN_NXDN 20
#define PIN_POCSAG 4
#define PIN_FM 5
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
#define ADC_CDR_Chan 7
#define DACC_MR_USER_SEL_Chan DACC_MR_USER_SEL_CHANNEL0 // DAC on Due DAC0
#define DACC_CHER_Chan DACC_CHER_CH0
#elif defined(ARDUINO_DUE_ZUM_V10)
#define PIN_COS 52
#define PIN_PTT 23
#define PIN_COSLED 22
#define PIN_DSTAR 9
#define PIN_DMR 8
#define PIN_YSF 7
#define PIN_P25 6
#define PIN_NXDN 5
#define PIN_POCSAG 4
#define PIN_FM 3
#define ADC_CHER_Chan (1<<13) // ADC on Due pin A11 - Due AD13 - (1 << 13)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC13
#define ADC_CDR_Chan 13
#define DACC_MR_USER_SEL_Chan DACC_MR_USER_SEL_CHANNEL1 // DAC on Due DAC1
#define DACC_CHER_Chan DACC_CHER_CH1
#define RSSI_CHER_Chan (1<<1) // ADC on Due pin A6 - Due AD1 - (1 << 1)
#define RSSI_CDR_Chan 1
#elif defined(ARDUINO_DUE_NTH)
#define PIN_COS A7
#define PIN_PTT A8
#define PIN_COSLED A11
#define PIN_DSTAR 9
#define PIN_DMR 8
#define PIN_YSF 7
#define PIN_P25 6
#define PIN_NXDN 5
#define PIN_POCSAG 4
#define PIN_FM 3
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
#define ADC_CDR_Chan 7
#define DACC_MR_USER_SEL_Chan DACC_MR_USER_SEL_CHANNEL0 // DAC on Due DAC0
#define DACC_CHER_Chan DACC_CHER_CH0
#define RSSI_CHER_Chan (1<<1) // ADC on Due pin A6 - Due AD1 - (1 << 1)
#define RSSI_CDR_Chan 1
#else
#error "Either ARDUINO_DUE_PAPA, ARDUINO_DUE_ZUM_V10, or ARDUINO_DUE_NTH need to be defined"
#endif
const uint16_t DC_OFFSET = 2048U;
extern "C" {
void ADC_Handler()
{
io.interrupt();
}
}
void CIO::initInt()
{
// Set up the TX, COS and LED pins
pinMode(PIN_PTT, OUTPUT);
pinMode(PIN_COSLED, OUTPUT);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_COS, INPUT);
#if defined(MODE_LEDS)
// Set up the mode output pins
pinMode(PIN_DSTAR, OUTPUT);
pinMode(PIN_DMR, OUTPUT);
pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
pinMode(PIN_NXDN, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
pinMode(PIN_M17, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
pinMode(PIN_POCSAG, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
pinMode(PIN_FM, OUTPUT);
#endif
#endif
}
void CIO::startInt()
{
if (ADC->ADC_ISR & ADC_ISR_EOC_Chan) // Ensure there was an End-of-Conversion and we read the ISR reg
io.interrupt();
// Set up the ADC
NVIC_EnableIRQ(ADC_IRQn); // Enable ADC interrupt vector
ADC->ADC_IDR = 0xFFFFFFFF; // Disable interrupts
ADC->ADC_IER = ADC_CHER_Chan; // Enable End-Of-Conv interrupt
ADC->ADC_CHDR = 0xFFFF; // Disable all channels
ADC->ADC_CHER = ADC_CHER_Chan; // Enable rx input channel
#if defined(SEND_RSSI_DATA)
ADC->ADC_CHER |= RSSI_CHER_Chan; // and RSSI input
#endif
ADC->ADC_CGR = 0x15555555; // All gains set to x1
ADC->ADC_COR = 0x00000000; // All offsets off
ADC->ADC_MR = (ADC->ADC_MR & 0xFFFFFFF0) | (1 << 1) | ADC_MR_TRGEN; // 1 = trig source TIO from TC0
#if defined(EXTERNAL_OSC)
// Set up the external clock input on PA4 = AI5
REG_PIOA_ODR = 0x10; // Set pin as input
REG_PIOA_PDR = 0x10; // Disable PIO A bit 4
REG_PIOA_ABSR &= ~0x10; // Select A peripheral = TCLK1 Input
#endif
// Set up the timer
pmc_enable_periph_clk(TC_INTERFACE_ID + 0*3+0) ; // Clock the TC0 channel 0
TcChannel* t = &(TC0->TC_CHANNEL)[0]; // Pointer to TC0 registers for its channel 0
t->TC_CCR = TC_CCR_CLKDIS; // Disable internal clocking while setup regs
t->TC_IDR = 0xFFFFFFFF; // Disable interrupts
t->TC_SR; // Read int status reg to clear pending
#if defined(EXTERNAL_OSC)
t->TC_CMR = TC_CMR_TCCLKS_XC1 | // Use XC1 = TCLK1 external clock
#else
t->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 | // Use TCLK1 (prescale by 2, = 42MHz)
#endif
TC_CMR_WAVE | // Waveform mode
TC_CMR_WAVSEL_UP_RC | // Count-up PWM using RC as threshold
TC_CMR_EEVT_XC0 | // Set external events from XC0 (this setup TIOB as output)
TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR;
#if defined(EXTERNAL_OSC)
t->TC_RC = EXTERNAL_OSC / 24000; // Counter resets on RC, so sets period in terms of the external clock
t->TC_RA = EXTERNAL_OSC / 48000; // Roughly square wave
#else
t->TC_RC = 1750; // Counter resets on RC, so sets period in terms of 42MHz internal clock
t->TC_RA = 880; // Roughly square wave
#endif
t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET; // Set clear and set from RA and RC compares
t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // re-enable local clocking and switch to hardware trigger source.
// Set up the DAC
pmc_enable_periph_clk(DACC_INTERFACE_ID); // Start clocking DAC
DACC->DACC_CR = DACC_CR_SWRST; // Reset DAC
DACC->DACC_MR =
DACC_MR_TRGEN_EN | DACC_MR_TRGSEL(1) | // Trigger 1 = TIO output of TC0
DACC_MR_USER_SEL_Chan | // Select channel
(24 << DACC_MR_STARTUP_Pos); // 24 = 1536 cycles which I think is in range 23..45us since DAC clock = 42MHz
DACC->DACC_IDR = 0xFFFFFFFF; // No interrupts
DACC->DACC_CHER = DACC_CHER_Chan; // Enable channel
digitalWrite(PIN_PTT, m_pttInvert ? HIGH : LOW);
digitalWrite(PIN_COSLED, LOW);
digitalWrite(PIN_LED, HIGH);
}
void CIO::interrupt()
{
if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg
TSample sample = {DC_OFFSET, MARK_NONE};
m_txBuffer.get(sample);
DACC->DACC_CDR = sample.sample;
sample.sample = ADC->ADC_CDR[ADC_CDR_Chan];
m_rxBuffer.put(sample);
#if defined(SEND_RSSI_DATA)
m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]);
#else
m_rssiBuffer.put(0U);
#endif
m_watchdog++;
}
}
bool CIO::getCOSInt()
{
return digitalRead(PIN_COS) == HIGH;
}
void CIO::setLEDInt(bool on)
{
digitalWrite(PIN_LED, on ? HIGH : LOW);
}
void CIO::setPTTInt(bool on)
{
digitalWrite(PIN_PTT, on ? HIGH : LOW);
}
void CIO::setCOSInt(bool on)
{
digitalWrite(PIN_COSLED, on ? HIGH : LOW);
}
void CIO::setDStarInt(bool on)
{
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
}
void CIO::setDMRInt(bool on)
{
digitalWrite(PIN_DMR, on ? HIGH : LOW);
}
void CIO::setYSFInt(bool on)
{
digitalWrite(PIN_YSF, on ? HIGH : LOW);
}
void CIO::setP25Int(bool on)
{
digitalWrite(PIN_P25, on ? HIGH : LOW);
}
void CIO::setNXDNInt(bool on)
{
#if defined(USE_ALTERNATE_NXDN_LEDS)
digitalWrite(PIN_YSF, on ? HIGH : LOW);
digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
#endif
}
void CIO::setM17Int(bool on)
{
#if defined(USE_ALTERNATE_M17_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
digitalWrite(PIN_M17, on ? HIGH : LOW);
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(USE_ALTERNATE_POCSAG_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_DMR, on ? HIGH : LOW);
#else
digitalWrite(PIN_POCSAG, on ? HIGH : LOW);
#endif
}
void CIO::setFMInt(bool on)
{
#if defined(USE_ALTERNATE_FM_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_YSF, on ? HIGH : LOW);
#else
digitalWrite(PIN_FM, on ? HIGH : LOW);
#endif
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
}
uint8_t CIO::getCPU() const
{
return 0U;
}
// Code taken from https://github.com/emagii/at91sam3s/blob/master/examples/eefc_uniqueid/main.c
void CIO::getUDID(uint8_t* buffer)
{
uint32_t status;
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
do {
status = EFC1->EEFC_FSR;
} while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY );
for (uint8_t i = 0; i < 16; i+=4) {
buffer[i + 0] = *(uint32_t *)(IFLASH1_ADDR + i) >> 24;
buffer[i + 1] = *(uint32_t *)(IFLASH1_ADDR + i) >> 16;
buffer[i + 2] = *(uint32_t *)(IFLASH1_ADDR + i) >> 8;
buffer[i + 3] = *(uint32_t *)(IFLASH1_ADDR + i) >> 0;
}
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
do {
status = EFC1->EEFC_FSR;
} while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY );
}
#endif
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2019,2020 by BG5HHP
*
* 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.
*/
#ifndef _IO_PINS_H
#define _IO_PINS_H
#if !defined(CONFIG_H)
#error "Requires Config.h to be included first!"
#endif
#if defined(STM32F4_RPT_HAT_TGO)
#include "pins/pins_f4_rpt_tgo.h"
#elif defined(STM32F4_DISCOVERY)
#include "pins/pins_f4_discovery.h"
#elif defined(STM32F4_PI)
#include "pins/pins_f4_pi.h"
#elif defined(STM32F722_PI)
#include "pins/pins_f7_pi.h"
#elif defined(STM32F4_F4M)
#include "pins/pins_f4_f4m.h"
#elif defined(STM32F722_F7M)
#include "pins/pins_f7_f7m.h"
#elif defined(STM32F722_RPT_HAT)
#include "pins/pins_f7_rpt_hat.h"
#elif defined(STM32F4_NUCLEO)
#if defined(STM32F4_NUCLEO_MORPHO_HEADER)
#include "pins/pins_f4_nucleo_morpho.h"
#elif defined(STM32F4_NUCLEO_ARDUINO_HEADER)
#include "pins/pins_f4_nucleo_arduino.h"
#else
#error "Either STM32F4_NUCLEO_MORPHO_HEADER or STM32F4_NUCLEO_ARDUINO_HEADER need to be defined"
#endif
#elif defined(STM32F7_NUCLEO)
#include "pins/pins_f7_nucleo.h"
#elif defined(STM32F4_DVM)
#include "pins/pins_f4_stm32dvm_v3.h"
#elif defined(STM32F7_DVM)
#include "pins/pins_f7_stm32dvm_v5.h"
#elif defined(DRCC_DVM_NQF)
#include "pins/pins_f4_drcc_nqf.h"
#elif defined(DRCC_DVM_HHP446)
#include "pins/pins_f4_drcc_hhp446.h"
#elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
#include "pins/pins_f4_stm32eda.h"
#else
#error "A valid board type macro need to be defined."
#endif
#endif //#ifndef _IO_PINS_H
+565
View File
@@ -0,0 +1,565 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2019,2020 by BG5HHP
*
* 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(STM32F7XX)
#include "IOPins.h"
const uint16_t DC_OFFSET = 2048U;
// Sampling frequency
#define SAMP_FREQ 24000
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;
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
// PTT pin
RCC_AHB1PeriphClockCmd(RCC_Per_PTT, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_PTT;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_PTT, &GPIO_InitStruct);
// COSLED pin
RCC_AHB1PeriphClockCmd(RCC_Per_COSLED, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_COSLED;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_COSLED, &GPIO_InitStruct);
// LED pin
RCC_AHB1PeriphClockCmd(RCC_Per_LED, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_LED;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_LED, &GPIO_InitStruct);
// Init the input pins PIN_COS
RCC_AHB1PeriphClockCmd(RCC_Per_COS, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_COS;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(PORT_COS, &GPIO_InitStruct);
#if defined(MODE_LEDS)
// DSTAR pin
RCC_AHB1PeriphClockCmd(RCC_Per_DSTAR, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_DSTAR;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_DSTAR, &GPIO_InitStruct);
// DMR pin
RCC_AHB1PeriphClockCmd(RCC_Per_DMR, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_DMR;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_DMR, &GPIO_InitStruct);
// YSF pin
RCC_AHB1PeriphClockCmd(RCC_Per_YSF, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_YSF;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_YSF, &GPIO_InitStruct);
// P25 pin
RCC_AHB1PeriphClockCmd(RCC_Per_P25, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_P25;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_P25, &GPIO_InitStruct);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
// NXDN pin
RCC_AHB1PeriphClockCmd(RCC_Per_NXDN, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_NXDN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
// M17 pin
RCC_AHB1PeriphClockCmd(RCC_Per_M17, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_M17;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_M17, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
// POCSAG pin
RCC_AHB1PeriphClockCmd(RCC_Per_POCSAG, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_POCSAG;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_POCSAG, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_FM_LEDS)
// FM pin
RCC_AHB1PeriphClockCmd(RCC_Per_FM, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_FM;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_FM, &GPIO_InitStruct);
#endif
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
// DSTAR mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MDSTAR, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MDSTAR;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MDSTAR, &GPIO_InitStruct);
// DMR mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MDMR, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MDMR;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MDMR, &GPIO_InitStruct);
// YSF mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MYSF, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MYSF;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MYSF, &GPIO_InitStruct);
// P25 mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MP25, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MP25;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MP25, &GPIO_InitStruct);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
// NXDN mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MNXDN, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MNXDN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
// M17 mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MM17, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MM17;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MM17, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
// POCSAG mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MPOCSAG, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MPOCSAG;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MPOCSAG, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_FM_LEDS)
// FM mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MFM, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MFM;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MFM, &GPIO_InitStruct);
#endif
#endif
}
void CIO::startInt()
{
if ((ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET))
io.interrupt();
// 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 ADC1 clock
RCC_AHB1PeriphClockCmd(RCC_Per_RX, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// Enable ADC1 GPIO
GPIO_InitStruct.GPIO_Pin = PIN_RX;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(PORT_RX, &GPIO_InitStruct);
#if defined(SEND_RSSI_DATA)
// Enable ADC2 clock
RCC_AHB1PeriphClockCmd(RCC_Per_RSSI, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
// Enable ADC2 GPIO
GPIO_InitStruct.GPIO_Pin = PIN_RSSI;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(PORT_RSSI, &GPIO_InitStruct);
#endif
// Init ADCs in dual mode (RSSI), div clock by two
#if defined(SEND_RSSI_DATA)
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
#else
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
#endif
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, PIN_RX_CH, 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, PIN_RSSI_CH, 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 clock enable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// DAC Periph clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
// GPIO CONFIGURATION of DAC Pin
GPIO_InitStruct.GPIO_Pin = PIN_TX;
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(PIN_TX_CH, &DAC_InitStructure);
DAC_Cmd(PIN_TX_CH, ENABLE);
// Init the timer
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
#if defined(EXTERNAL_OSC) && !(defined(STM32F4_PI) || defined(STM32F722_PI))
// Configure a GPIO as external TIM2 clock source
GPIO_PinAFConfig(PORT_EXT_CLK, SRC_EXT_CLK, GPIO_AF_TIM2);
GPIO_InitStruct.GPIO_Pin = PIN_EXT_CLK;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(PORT_EXT_CLK, &GPIO_InitStruct);
#endif
TIM_TimeBaseInitTypeDef timerInitStructure;
TIM_TimeBaseStructInit (&timerInitStructure);
// TIM2 output frequency
#if defined(EXTERNAL_OSC) && !(defined(STM32F4_PI) || defined(STM32F722_PI))
timerInitStructure.TIM_Prescaler = (uint16_t) ((EXTERNAL_OSC/(2*SAMP_FREQ)) - 1);
timerInitStructure.TIM_Period = 1;
#else
timerInitStructure.TIM_Prescaler = (uint16_t) ((SystemCoreClock/(6*SAMP_FREQ)) - 1);
timerInitStructure.TIM_Period = 2;
#endif
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timerInitStructure);
#if defined(EXTERNAL_OSC) && !(defined(STM32F4_PI) || defined(STM32F722_PI))
// Enable external clock
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
#else
// Enable internal clock
TIM_InternalClockConfig(TIM2);
#endif
// Enable TIM2
TIM_Cmd(TIM2, ENABLE);
// Enable TIM2 interrupt
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()
{
TSample sample = {DC_OFFSET, MARK_NONE};
uint16_t rawRSSI = 0U;
m_txBuffer.get(sample);
// Send the value to the DAC
#if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)
DAC_SetChannel2Data(DAC_Align_12b_R, sample.sample);
#else
DAC_SetChannel1Data(DAC_Align_12b_R, sample.sample);
#endif
// 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.sample = 0U;
} else {
sample.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);
m_rssiBuffer.put(rawRSSI);
m_watchdog++;
}
bool CIO::getCOSInt()
{
return GPIO_ReadInputDataBit(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)
{
#if defined(MODE_LEDS)
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
#endif
}
void CIO::setDMRInt(bool on)
{
#if defined(MODE_LEDS)
GPIO_WriteBit(PORT_DMR, PIN_DMR, on ? Bit_SET : Bit_RESET);
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
GPIO_WriteBit(PORT_MDMR, PIN_MDMR, on ? Bit_SET : Bit_RESET);
#endif
}
void CIO::setYSFInt(bool on)
{
#if defined(MODE_LEDS)
GPIO_WriteBit(PORT_YSF, PIN_YSF, on ? Bit_SET : Bit_RESET);
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
GPIO_WriteBit(PORT_MYSF, PIN_MYSF, on ? Bit_SET : Bit_RESET);
#endif
}
void CIO::setP25Int(bool on)
{
#if defined(MODE_LEDS)
GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET);
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
GPIO_WriteBit(PORT_MP25, PIN_MP25, on ? Bit_SET : Bit_RESET);
#endif
}
void CIO::setNXDNInt(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_NXDN_LEDS)
GPIO_WriteBit(PORT_YSF, PIN_YSF, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_NXDN, PIN_NXDN, on ? Bit_SET : Bit_RESET);
#endif
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
#if defined(USE_ALTERNATE_NXDN_LEDS)
GPIO_WriteBit(PORT_MYSF, PIN_MYSF, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_MP25, PIN_MP25, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_MNXDN, PIN_MNXDN, on ? Bit_SET : Bit_RESET);
#endif
#endif
}
void CIO::setM17Int(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_M17_LEDS)
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_M17, PIN_M17, on ? Bit_SET : Bit_RESET);
#endif
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
#if defined(USE_ALTERNATE_M17_LEDS)
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_MP25, PIN_MP25, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_MM17, PIN_MM17, on ? Bit_SET : Bit_RESET);
#endif
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_POCSAG_LEDS)
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_DMR, PIN_DMR, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_POCSAG, PIN_POCSAG, on ? Bit_SET : Bit_RESET);
#endif
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
#if defined(USE_ALTERNATE_POCSAG_LEDS)
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_MDMR, PIN_MDMR, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_MPOCSAG, PIN_MPOCSAG, on ? Bit_SET : Bit_RESET);
#endif
#endif
}
void CIO::setFMInt(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_FM_LEDS)
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_YSF, PIN_YSF, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_FM, PIN_FM, on ? Bit_SET : Bit_RESET);
#endif
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
#if defined(USE_ALTERNATE_FM_LEDS)
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_MYSF, PIN_MYSF, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_MFM, PIN_MFM, on ? Bit_SET : Bit_RESET);
#endif
#endif
}
// Simple delay function for STM32
// Example from: http://thehackerworkshop.com/?p=1209
void CIO::delayInt(unsigned int dly)
{
#if defined(STM32F7XX)
unsigned int loopsPerMillisecond = (SystemCoreClock/1000);
#else
unsigned int loopsPerMillisecond = (SystemCoreClock/1000) / 3;
#endif
for (; dly > 0; dly--)
{
asm volatile //this routine waits (approximately) one millisecond
(
"mov r3, %[loopsPerMillisecond] \n\t" //load the initial loop counter
"loop: \n\t"
"subs r3, #1 \n\t"
"bne loop \n\t"
: //empty output list
: [loopsPerMillisecond] "r" (loopsPerMillisecond) //input to the asm routine
: "r3", "cc" //clobber list
);
}
}
uint8_t CIO::getCPU() const
{
return 2U;
}
void CIO::getUDID(uint8_t* buffer)
{
#if defined(STM32F4XX)
::memcpy(buffer, (void *)0x1FFF7A10, 12U);
#elif defined(STM32F722xx)
::memcpy(buffer, (void *)0x1FF07A10, 12U);
#elif defined(STM32F767xx)
::memcpy(buffer, (void *)0x1FF0F420, 12U);
#endif
}
#endif
+289
View File
@@ -0,0 +1,289 @@
/*
* Copyright (C) 2016,2017,2018,2020 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
* 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(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(EXTERNAL_OSC)
#define PIN_LED 3
#else
#define PIN_LED 13
#endif
#define PIN_COS 4
#define PIN_PTT 5
#define PIN_COSLED 6
#define PIN_DSTAR 9
#define PIN_DMR 10
#define PIN_YSF 11
#define PIN_P25 12
#if defined(__MK20DX256__)
#define PIN_NXDN 2
#define PIN_POCSAG 3
#define PIN_FM 4
#else
#define PIN_NXDN 24
#define PIN_POCSAG 25
#define PIN_FM 26
#endif
#define PIN_ADC 5 // A0, Pin 14
#define PIN_RSSI 4 // Teensy 3.5/3.6, A16, Pin 35. Teensy 3.1/3.2, A17, Pin 28
#define PDB_CHnC1_TOS 0x0100
#define PDB_CHnC1_EN 0x0001
const uint16_t DC_OFFSET = 2048U;
extern "C" {
void adc0_isr()
{
io.interrupt();
}
}
void CIO::initInt()
{
// Set up the TX, COS and LED pins
pinMode(PIN_PTT, OUTPUT);
pinMode(PIN_COSLED, OUTPUT);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_COS, INPUT);
#if defined(MODE_LEDS)
// Set up the mode output pins
pinMode(PIN_DSTAR, OUTPUT);
pinMode(PIN_DMR, OUTPUT);
pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
pinMode(PIN_NXDN, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
pinMode(PIN_M17, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
pinMode(PIN_POCSAG, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_FM_LEDS)
pinMode(PIN_FM, OUTPUT);
#endif
#endif
}
void CIO::startInt()
{
// Initialise the DAC
SIM_SCGC2 |= SIM_SCGC2_DAC0;
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
// Initialise ADC0
SIM_SCGC6 |= SIM_SCGC6_ADC0;
ADC0_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | // Single-ended 12 bits, long sample time
ADC_CFG1_MODE(1) | ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb
ADC0_SC2 = ADC_SC2_REFSEL(0) | ADC_SC2_ADTRG; // Voltage ref external, hardware trigger
ADC0_SC3 = ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples
ADC0_SC3 |= ADC_SC3_CAL;
while (ADC0_SC3 & ADC_SC3_CAL) // Wait for calibration
;
uint16_t sum0 = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + // Plus side gain
ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
sum0 = (sum0 / 2U) | 0x8000U;
ADC0_PG = sum0;
ADC0_SC1A = ADC_SC1_AIEN | PIN_ADC; // Enable ADC interrupt, use A0
NVIC_ENABLE_IRQ(IRQ_ADC0);
#if defined(SEND_RSSI_DATA)
// Initialise ADC1
SIM_SCGC3 |= SIM_SCGC3_ADC1;
ADC1_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | // Single-ended 12 bits, long sample time
ADC_CFG1_MODE(1) | ADC_CFG1_ADLSMP;
ADC1_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb
ADC1_SC2 = ADC_SC2_REFSEL(0); // Voltage ref external, software trigger
ADC1_SC3 = ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples
ADC1_SC3 |= ADC_SC3_CAL;
while (ADC1_SC3 & ADC_SC3_CAL) // Wait for calibration
;
uint16_t sum1 = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + // Plus side gain
ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
sum1 = (sum1 / 2U) | 0x8000U;
ADC1_PG = sum1;
#endif
#if defined(EXTERNAL_OSC)
// Set ADC0 to trigger from the LPTMR at 24 kHz
SIM_SOPT7 = SIM_SOPT7_ADC0ALTTRGEN | // Enable ADC0 alternate trigger
SIM_SOPT7_ADC0TRGSEL(14); // Trigger ADC0 by LPTMR0
CORE_PIN13_CONFIG = PORT_PCR_MUX(3);
SIM_SCGC5 |= SIM_SCGC5_LPTIMER; // Enable Low Power Timer Access
LPTMR0_CSR = 0; // Disable
LPTMR0_PSR = LPTMR_PSR_PBYP; // Bypass prescaler/filter
LPTMR0_CMR = (EXTERNAL_OSC / 24000) - 1; // Frequency divided by CMR + 1
LPTMR0_CSR = LPTMR_CSR_TPS(2) | // Pin: 0=CMP0, 1=xtal, 2=pin13
LPTMR_CSR_TMS; // Mode Select, 0=timer, 1=counter
LPTMR0_CSR |= LPTMR_CSR_TEN; // Enable
#else
// Setup PDB for ADC0 at 24 kHz
SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock
PDB0_MOD = (F_BUS / 24000) - 1; // Timer period - 1
PDB0_IDLY = 0; // Interrupt delay
PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0
PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode
PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_LDOK; // No prescaling
PDB0_SC |= PDB_SC_SWTRIG; // Software trigger (reset and restart counter)
#endif
digitalWrite(PIN_PTT, m_pttInvert ? HIGH : LOW);
digitalWrite(PIN_COSLED, LOW);
digitalWrite(PIN_LED, HIGH);
}
void CIO::interrupt()
{
TSample sample = {DC_OFFSET, MARK_NONE};
m_txBuffer.get(sample);
*(int16_t *)&(DAC0_DAT0L) = sample.sample;
if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
sample.sample = ADC0_RA;
m_rxBuffer.put(sample);
}
#if defined(SEND_RSSI_DATA)
if ((ADC1_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
uint16_t rssi = ADC1_RA;
m_rssiBuffer.put(rssi);
} else {
m_rssiBuffer.put(0U);
}
ADC1_SC1A = PIN_RSSI; // Start the next RSSI conversion
#else
m_rssiBuffer.put(0U);
#endif
m_watchdog++;
}
bool CIO::getCOSInt()
{
return digitalRead(PIN_COS) == HIGH;
}
void CIO::setLEDInt(bool on)
{
digitalWrite(PIN_LED, on ? HIGH : LOW);
}
void CIO::setPTTInt(bool on)
{
digitalWrite(PIN_PTT, on ? HIGH : LOW);
}
void CIO::setCOSInt(bool on)
{
digitalWrite(PIN_COSLED, on ? HIGH : LOW);
}
void CIO::setDStarInt(bool on)
{
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
}
void CIO::setDMRInt(bool on)
{
digitalWrite(PIN_DMR, on ? HIGH : LOW);
}
void CIO::setYSFInt(bool on)
{
digitalWrite(PIN_YSF, on ? HIGH : LOW);
}
void CIO::setP25Int(bool on)
{
digitalWrite(PIN_P25, on ? HIGH : LOW);
}
void CIO::setNXDNInt(bool on)
{
#if defined(USE_ALTERNATE_NXDN_LEDS)
digitalWrite(PIN_YSF, on ? HIGH : LOW);
digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
#endif
}
void CIO::setM17Int(bool on)
{
#if defined(USE_ALTERNATE_M17_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
digitalWrite(PIN_M17, on ? HIGH : LOW);
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(USE_ALTERNATE_POCSAG_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_DMR, on ? HIGH : LOW);
#else
digitalWrite(PIN_POCSAG, on ? HIGH : LOW);
#endif
}
void CIO::setFMInt(bool on)
{
#if defined(USE_ALTERNATE_FM_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_YSF, on ? HIGH : LOW);
#else
digitalWrite(PIN_FM, on ? HIGH : LOW);
#endif
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
}
uint8_t CIO::getCPU() const
{
return 1U;
}
void CIO::getUDID(uint8_t* buffer)
{
::memcpy(buffer, (void *)0x4058, 16U);
}
#endif
View File
View File
View File
View File
+24 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017,2018,2020,2021,2024 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT * Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* *
@@ -18,6 +18,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#if defined(STM32F4XX) || defined(STM32F7XX)
#include "Config.h" #include "Config.h"
#include "Globals.h" #include "Globals.h"
@@ -30,6 +32,7 @@ bool m_ysfEnable = true;
bool m_p25Enable = true; bool m_p25Enable = true;
bool m_nxdnEnable = true; bool m_nxdnEnable = true;
bool m_m17Enable = true; bool m_m17Enable = true;
bool m_dpmrEnable = true;
bool m_pocsagEnable = true; bool m_pocsagEnable = true;
bool m_fmEnable = true; bool m_fmEnable = true;
bool m_ax25Enable = true; bool m_ax25Enable = true;
@@ -84,6 +87,11 @@ CM17TX m17TX;
CCalM17 calM17; CCalM17 calM17;
#endif #endif
#if defined(MODE_NXDN)
CDPMRRX dpmrRX;
CDPMRTX dpmrTX;
#endif
#if defined(MODE_POCSAG) #if defined(MODE_POCSAG)
CPOCSAGTX pocsagTX; CPOCSAGTX pocsagTX;
CCalPOCSAG calPOCSAG; CCalPOCSAG calPOCSAG;
@@ -152,6 +160,11 @@ void loop()
m17TX.process(); m17TX.process();
#endif #endif
#if defined(MODE_DPMR)
if (m_dpmrEnable && m_modemState == STATE_DPMR)
dpmrTX.process();
#endif
#if defined(MODE_POCSAG) #if defined(MODE_POCSAG)
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy())) if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
pocsagTX.process(); pocsagTX.process();
@@ -205,3 +218,13 @@ void loop()
if (m_modemState == STATE_IDLE) if (m_modemState == STATE_IDLE)
cwIdTX.process(); cwIdTX.process();
} }
int main()
{
setup();
for (;;)
loop();
}
#endif
+218
View File
@@ -0,0 +1,218 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2021,2024 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* 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"
// Global variables
MMDVM_STATE m_modemState = STATE_IDLE;
bool m_dstarEnable = true;
bool m_dmrEnable = true;
bool m_ysfEnable = true;
bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_m17Enable = true;
bool m_dpmrEnable = true;
bool m_pocsagEnable = true;
bool m_fmEnable = true;
bool m_ax25Enable = true;
bool m_duplex = true;
bool m_tx = false;
bool m_dcd = false;
#if defined(MODE_DSTAR)
CDStarRX dstarRX;
CDStarTX dstarTX;
CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX;
#endif
#if defined(MODE_DMR)
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
CYSFRX ysfRX;
CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
CP25RX p25RX;
CP25TX p25TX;
CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalNXDN calNXDN;
#endif
#if defined(MODE_M17)
CM17RX m17RX;
CM17TX m17TX;
CCalM17 calM17;
#endif
#if defined(MODE_NXDN)
CDPMRRX dpmrRX;
CDPMRTX dpmrTX;
#endif
#if defined(MODE_POCSAG)
CPOCSAGTX pocsagTX;
CCalPOCSAG calPOCSAG;
#endif
#if defined(MODE_FM)
CFM fm;
CCalFM calFM;
#endif
#if defined(MODE_AX25)
CAX25RX ax25RX;
CAX25TX ax25TX;
#endif
CCalRSSI calRSSI;
CCWIdTX cwIdTX;
CSerialPort serial;
CIO io;
void setup()
{
serial.start();
}
void loop()
{
serial.process();
io.process();
// The following is for transmitting
#if defined(MODE_DSTAR)
if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process();
#endif
#if defined(MODE_DMR)
if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_duplex)
dmrTX.process();
else
dmrDMOTX.process();
}
#endif
#if defined(MODE_YSF)
if (m_ysfEnable && m_modemState == STATE_YSF)
ysfTX.process();
#endif
#if defined(MODE_P25)
if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process();
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
#endif
#if defined(MODE_M17)
if (m_m17Enable && m_modemState == STATE_M17)
m17TX.process();
#endif
#if defined(MODE_DPMR)
if (m_dpmrEnable && m_modemState == STATE_DPMR)
dpmrTX.process();
#endif
#if defined(MODE_POCSAG)
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
pocsagTX.process();
#endif
#if defined(MODE_AX25)
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
ax25TX.process();
#endif
#if defined(MODE_FM)
if (m_fmEnable && m_modemState == STATE_FM)
fm.process();
#endif
#if defined(MODE_DSTAR)
if (m_modemState == STATE_DSTARCAL)
calDStarTX.process();
#endif
#if defined(MODE_DMR)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
calDMR.process();
#endif
#if defined(MODE_FM)
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
calFM.process();
#endif
#if defined(MODE_P25)
if (m_modemState == STATE_P25CAL1K)
calP25.process();
#endif
#if defined(MODE_NXDN)
if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process();
#endif
#if defined(MODE_M17)
if (m_modemState == STATE_M17CAL)
calM17.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process();
#endif
if (m_modemState == STATE_IDLE)
cwIdTX.process();
}
+413
View File
@@ -0,0 +1,413 @@
# Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
# Copyright (C) 2016 by Jim McLaughlin KI6ZUM
# 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.
# MMDVM source files
MMDVM_PATH=.
# STM32 library paths
F4_LIB_PATH=./STM32F4XX_Lib
F7_LIB_PATH=./STM32F7XX_Lib
# MCU external clock frequency (Hz)
CLK_MMDVM_PI=12000000
CLK_NUCLEO=8000000
CLK_12MHZ=12000000
# Directory Structure
BINDIR=bin
OBJDIR_F4=obj_f4
OBJDIR_F7=obj_f7
# Output files
BINELF_F4=mmdvm_f4.elf
BINHEX_F4=mmdvm_f4.hex
BINBIN_F4=mmdvm_f4.bin
BINELF_F7=mmdvm_f7.elf
BINHEX_F7=mmdvm_f7.hex
BINBIN_F7=mmdvm_f7.bin
# Header directories
INC_F4= . $(F4_LIB_PATH)/CMSIS/Include/ $(F4_LIB_PATH)/Device/ $(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/include/
INCLUDES_F4=$(INC_F4:%=-I%)
INC_F7= . $(F7_LIB_PATH)/CMSIS/Include/ $(F7_LIB_PATH)/Device/ $(F7_LIB_PATH)/STM32F7xx_StdPeriph_Driver/inc/
INCLUDES_F7=$(INC_F7:%=-I%)
# CMSIS libraries
INCLUDES_LIBS_F4=$(F4_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a
INCLUDES_LIBS_F7=$(F7_LIB_PATH)/CMSIS/Lib/GCC/libarm_cortexM7lfsp_math.a
# STM32F4 Standard Peripheral Libraries source path
STD_LIB_F4=$(F4_LIB_PATH)/STM32F4xx_StdPeriph_Driver/source
# STM32F7 Standard Peripheral Libraries source path
STD_LIB_F7=$(F7_LIB_PATH)/STM32F7xx_StdPeriph_Driver/src
# STM32F4 system source path
SYS_DIR_F4=$(F4_LIB_PATH)/Device
STARTUP_DIR_F4=$(F4_LIB_PATH)/Device/startup
# STM32F7 system source path
SYS_DIR_F7=$(F7_LIB_PATH)/Device
STARTUP_DIR_F7=$(F7_LIB_PATH)/Device/startup
# 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
# "SystemRoot" is only defined in Windows
ifdef SYSTEMROOT
CLEANCMD=del /S *.o *.hex *.bin *.elf GitVersion.h
MDDIRS=md $@
else ifdef SystemRoot
CLEANCMD=del /S *.o *.hex *.bin *.elf GitVersion.h
MDDIRS=md $@
else
CLEANCMD=rm -f $(OBJ_F4) $(OBJ_F7) $(BINDIR)/*.hex $(BINDIR)/*.bin $(BINDIR)/*.elf GitVersion.h
MDDIRS=mkdir $@
endif
# Default reference oscillator frequencies
ifndef $(OSC)
ifeq ($(MAKECMDGOALS),pi)
OSC=$(CLK_MMDVM_PI)
else ifeq ($(MAKECMDGOALS),pi-f722)
OSC=$(CLK_MMDVM_PI)
else ifeq ($(MAKECMDGOALS),drcc_nqf)
OSC=$(CLK_12MHZ)
else
OSC=$(CLK_NUCLEO)
endif
endif
# Build object lists
CXXSRC=$(wildcard $(MMDVM_PATH)/*.cpp)
CSRC_STD_F4=$(wildcard $(STD_LIB_F4)/*.c)
SYS_F4=$(wildcard $(SYS_DIR_F4)/*.c)
STARTUP_F4=$(wildcard $(STARTUP_DIR_F4)/*.c)
CSRC_STD_F7=$(wildcard $(STD_LIB_F7)/*.c)
SYS_F7=$(wildcard $(SYS_DIR_F7)/*.c)
STARTUP_F7=$(wildcard $(STARTUP_DIR_F7)/*.c)
OBJ_F4=$(CXXSRC:$(MMDVM_PATH)/%.cpp=$(OBJDIR_F4)/%.o) $(CSRC_STD_F4:$(STD_LIB_F4)/%.c=$(OBJDIR_F4)/%.o) $(SYS_F4:$(SYS_DIR_F4)/%.c=$(OBJDIR_F4)/%.o) $(STARTUP_F4:$(STARTUP_DIR_F4)/%.c=$(OBJDIR_F4)/%.o)
OBJ_F7=$(CXXSRC:$(MMDVM_PATH)/%.cpp=$(OBJDIR_F7)/%.o) $(CSRC_STD_F7:$(STD_LIB_F7)/%.c=$(OBJDIR_F7)/%.o) $(SYS_F7:$(SYS_DIR_F7)/%.c=$(OBJDIR_F7)/%.o) $(STARTUP_F7:$(STARTUP_DIR_F7)/%.c=$(OBJDIR_F7)/%.o)
# MCU flags
MCFLAGS_F4=-mcpu=cortex-m4 -mthumb -mlittle-endian -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb-interwork
MCFLAGS_F7=-mcpu=cortex-m7 -mthumb -mlittle-endian -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mthumb-interwork
# Compile flags
# STM32F4 Discovery board:
DEFS_DIS=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_DISCOVERY -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM-Pi board:
DEFS_PI=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM-F4M F0DEI board:
DEFS_F4M=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_F4M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# STM32F4 Nucleo-64 F446RE board:
DEFS_NUCLEO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_NUCLEO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# STM32F7 Nucleo-144 F767ZI board:
DEFS_NUCLEO_F767=-DUSE_HAL_DRIVER -DSTM32F767xx -DSTM32F7XX -DSTM32F7_NUCLEO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM-Pi F722 board:
DEFS_PI_F722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM-F7M F0DEI board:
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board:
DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# RB STM32F4_DVM board:
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# RB STM32F7 DVM board:
DEFS_DVM722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F7_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM_RPT_Hat BG4TGO, BG5HHP board:
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# DRCC_DVM BG7NQF board:
DEFS_DRCC_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DDRCC_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# WA0EDA F405 MTR2K, MASTR3 board:
DEFS_EDA_405=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_EDA_405 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# WA0EDA F446 MTR2K, MASTR3 board:
DEFS_EDA_446=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_EDA_446 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# Build compiler flags
CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4)
CXXFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4)
CFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7)
CXXFLAGS_F7=-c $(MCFLAGS_F7) $(INCLUDES_F7)
# Linker flags
LDFLAGS_F4 =-T stm32f4xx_link.ld $(MCFLAGS_F4) --specs=nosys.specs $(INCLUDES_LIBS_F4)
LDFLAGS_F767 =-T stm32f767_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_LIBS_F7)
LDFLAGS_F722 =-T stm32f722_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_LIBS_F7)
# Common flags
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
LDFLAGS=-Os --specs=nano.specs -Wl,-Map=bin/mmdvm.map
# Build Rules
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm drcc_nqf clean
# Default target: Nucleo-64 F446RE board
all: nucleo
pi: GitVersion.h
pi: CFLAGS+=$(CFLAGS_F4) $(DEFS_PI)
pi: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_PI)
pi: LDFLAGS+=$(LDFLAGS_F4)
pi: release_f4
pi-f722: GitVersion.h
pi-f722: CFLAGS+=$(CFLAGS_F7) $(DEFS_PI_F722)
pi-f722: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_PI_F722)
pi-f722: LDFLAGS+=$(LDFLAGS_F722)
pi-f722: release_f7
f4m: GitVersion.h
f4m: CFLAGS+=$(CFLAGS_F4) $(DEFS_F4M)
f4m: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_F4M)
f4m: LDFLAGS+=$(LDFLAGS_F4)
f4m: release_f4
f7m: GitVersion.h
f7m: CFLAGS+=$(CFLAGS_F7) $(DEFS_F7M)
f7m: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_F7M)
f7m: LDFLAGS+=$(LDFLAGS_F722)
f7m: release_f7
rpt_hat: GitVersion.h
rpt_hat: CFLAGS+=$(CFLAGS_F7) $(DEFS_RPT_HAT)
rpt_hat: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_RPT_HAT)
rpt_hat: LDFLAGS+=$(LDFLAGS_F722)
rpt_hat: release_f7
rpt_hat_tgo: GitVersion.h
rpt_hat_tgo: CFLAGS+=$(CFLAGS_F4) $(DEFS_RPT_HAT_TGO)
rpt_hat_tgo: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_RPT_HAT_TGO)
rpt_hat_tgo: LDFLAGS+=$(LDFLAGS_F4)
rpt_hat_tgo: release_f4
nucleo: GitVersion.h
nucleo: CFLAGS+=$(CFLAGS_F4) $(DEFS_NUCLEO)
nucleo: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_NUCLEO)
nucleo: LDFLAGS+=$(LDFLAGS_F4)
nucleo: release_f4
dis: GitVersion.h
dis: CFLAGS+=$(CFLAGS_F4) $(DEFS_DIS)
dis: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DIS)
dis: LDFLAGS+=$(LDFLAGS_F4)
dis: release_f4
f767: GitVersion.h
f767: CFLAGS+=$(CFLAGS_F7) $(DEFS_NUCLEO_F767)
f767: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_NUCLEO_F767)
f767: LDFLAGS+=$(LDFLAGS_F767)
f767: release_f7
dvm: GitVersion.h
dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
dvm: LDFLAGS+=$(LDFLAGS_F4)
dvm: release_f4
dvm722: GitVersion.h
dvm722: CFLAGS+=$(CFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
dvm722: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
dvm722: LDFLAGS+=$(LDFLAGS_F722)
dvm722: release_f7
drcc_nqf: GitVersion.h
drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
drcc_nqf: release_f4
hhp446: GitVersion.h
hhp446: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
hhp446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
hhp446: LDFLAGS+=$(LDFLAGS_F4)
hhp446: release_f4
eda405: GitVersion.h
eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405)
eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405)
eda405: LDFLAGS+=$(LDFLAGS_F4)
eda405: release_f4
eda446: GitVersion.h
eda446: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_446)
eda446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_446)
eda446: LDFLAGS+=$(LDFLAGS_F4)
eda446: release_f4
release_f4: $(BINDIR)
release_f4: $(OBJDIR_F4)
release_f4: $(BINDIR)/$(BINHEX_F4)
release_f4: $(BINDIR)/$(BINBIN_F4)
release_f7: $(BINDIR)
release_f7: $(OBJDIR_F7)
release_f7: $(BINDIR)/$(BINHEX_F7)
release_f7: $(BINDIR)/$(BINBIN_F7)
$(BINDIR):
$(MDDIRS)
$(OBJDIR_F4):
$(MDDIRS)
$(OBJDIR_F7):
$(MDDIRS)
$(BINDIR)/$(BINHEX_F4): $(BINDIR)/$(BINELF_F4)
$(CP) -O ihex $< $@
@echo "Objcopy from ELF to IHEX complete!\n"
$(BINDIR)/$(BINBIN_F4): $(BINDIR)/$(BINELF_F4)
$(CP) -O binary $< $@
@echo "Objcopy from ELF to BINARY complete!\n"
$(BINDIR)/$(BINELF_F4): $(OBJ_F4)
$(CXX) $(OBJ_F4) $(LDFLAGS) -o $@
@echo "Linking complete!\n"
$(SIZE) $(BINDIR)/$(BINELF_F4)
$(BINDIR)/$(BINHEX_F7): $(BINDIR)/$(BINELF_F7)
$(CP) -O ihex $< $@
@echo "Objcopy from ELF to IHEX complete!\n"
$(BINDIR)/$(BINBIN_F7): $(BINDIR)/$(BINELF_F7)
$(CP) -O binary $< $@
@echo "Objcopy from ELF to BINARY complete!\n"
$(BINDIR)/$(BINELF_F7): $(OBJ_F7)
$(CXX) $(OBJ_F7) $(LDFLAGS) -o $@
@echo "Linking complete!\n"
$(SIZE) $(BINDIR)/$(BINELF_F7)
$(OBJDIR_F4)/%.o: $(MMDVM_PATH)/%.cpp
$(CXX) $(CXXFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F7)/%.o: $(MMDVM_PATH)/%.cpp
$(CXX) $(CXXFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F4)/%.o: $(STD_LIB_F4)/%.c
$(CC) $(CFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F7)/%.o: $(STD_LIB_F7)/%.c
$(CC) $(CFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F4)/%.o: $(SYS_DIR_F4)/%.c
$(CC) $(CFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F4)/%.o: $(STARTUP_DIR_F4)/%.c
$(CC) $(CFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F7)/%.o: $(SYS_DIR_F7)/%.c
$(CC) $(CFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
$(OBJDIR_F7)/%.o: $(STARTUP_DIR_F7)/%.c
$(CC) $(CFLAGS) $< -o $@
@echo "Compiled "$<"!\n"
clean:
$(CLEANCMD)
deploy:
ifneq ($(wildcard /usr/bin/openocd),)
/usr/bin/openocd -f /usr/share/openocd/scripts/interface/stlink-v2-1.cfg -f /usr/share/openocd/scripts/target/stm32f4x.cfg -c "program bin/$(BINELF_F4) verify reset exit"
endif
ifneq ($(wildcard /usr/local/bin/openocd),)
/usr/local/bin/openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2-1.cfg -f /usr/local/share/openocd/scripts/target/stm32f4x.cfg -c "program bin/$(BINELF_F4) verify reset exit"
endif
ifneq ($(wildcard /opt/openocd/bin/openocd),)
/opt/openocd/bin/openocd -f /opt/openocd/share/openocd/scripts/interface/stlink-v2-1.cfg -f /opt/openocd/share/openocd/scripts/target/stm32f4x.cfg -c "program bin/$(BINELF_F4) verify reset exit"
endif
deploy-f7:
ifneq ($(wildcard /usr/bin/openocd),)
/usr/bin/openocd -f /usr/share/openocd/scripts/interface/stlink-v2-1.cfg -f /usr/share/openocd/scripts/target/stm32f7x.cfg -c "program bin/$(BINELF_F7) verify reset exit"
endif
ifneq ($(wildcard /usr/local/bin/openocd),)
/usr/local/bin/openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2-1.cfg -f /usr/local/share/openocd/scripts/target/stm32f7x.cfg -c "program bin/$(BINELF_F7) verify reset exit"
endif
ifneq ($(wildcard /opt/openocd/bin/openocd),)
/opt/openocd/bin/openocd -f /opt/openocd/share/openocd/scripts/interface/stlink-v2-1.cfg -f /opt/openocd/share/openocd/scripts/target/stm32f7x.cfg -c "program bin/$(BINELF_F7) verify reset exit"
endif
deploy-pi:
ifneq ($(wildcard /usr/local/bin/stm32flash),)
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
endif
ifneq ($(wildcard /usr/bin/stm32flash),)
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
endif
deploy-f4m: deploy-pi
deploy-dvm: deploy-pi
deploy-eda405: deploy-pi
deploy-eda446: deploy-pi
deploy-pi-f7:
ifneq ($(wildcard /usr/local/bin/stm32flash),)
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
else ifneq ($(wildcard /usr/bin/stm32flash),)
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
endif
deploy-f7m: deploy-pi-f7
deploy-rpt_hat: deploy-pi-f7
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifdef SYSTEMROOT
echo #define GITVERSION "0000000" > $@
else ifdef SystemRoot
echo #define GITVERSION "0000000" > $@
else
ifneq ("$(wildcard .git/index)","")
echo "#define GITVERSION \"$(shell git rev-parse --short HEAD)\"" > $@
else
echo "#define GITVERSION \"0000000\"" > $@
endif
endif
flash_f4:
@echo "flashing firmware..."
st-flash write bin/$(BINBIN_F4) 0x8000000
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/make
# makefile for the arduino due (works with arduino IDE 1.6.12)
#
# The original file can be found at https://github.com/pauldreik/arduino-due-makefile
#
# USAGE: put this file in the same dir as your .ino file is.
# configure the PORT variable and ADIR at the top of the file
# to match your local configuration.
# Type make upload to compile and upload.
#
#user specific settings:
#where to find the IDE
ADIR:=$(HOME)/.arduino15
#which serial port to use (add a file with SUBSYSTEMS=="usb",
#ATTRS{product}=="Arduino Due Prog. Port", ATTRS{idProduct}=="003d",
#ATTRS{idVendor}=="2341", SYMLINK+="arduino_due" in /etc/udev/rules.d/
#to get this working). Do not prefix the port with /dev/, just take
#the basename.
PORT:=ttyACM0
#if you want to verify the bossac upload, define this to -v
VERIFY:=-v
#end of user configuration.
#then some general settings. They should not be necessary to modify.
#CXX:=$(ADIR)/tools/g++_arm_none_eabi/bin/arm-none-eabi-g++
CXX:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-g++
#CC:=$(ADIR)/tools/g++_arm_none_eabi/bin/arm-none-eabi-gcc
CC:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-gcc
OBJCOPY:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-objcopy
C:=$(CC)
#SAM:=arduino/sam/
SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.12
#CMSIS:=arduino/sam/system/CMSIS/
#LIBSAM:=arduino/sam/system/libsam
TMPDIR:=$(PWD)/build
AR:=$(ADIR)/tools/g++_arm_none_eabi/bin/arm-none-eabi-ar
AR:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-ar
#all these values are hard coded and should maybe be configured somehow else,
#like olikraus does in his makefile.
DEFINES:=-Dprintf=iprintf -DF_CPU=84000000 -DARDUINO=10611 -D__SAM3X8E__ -DUSB_PID=0x003e -DUSB_VID=0x2341 -DUSBCON \
-DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM '-DUSB_MANUFACTURER="Arduino LLC"' '-DUSB_PRODUCT="Arduino Due"' \
-DMADEBYMAKEFILE
INCLUDES:=-I$(SAM)/system/libsam -I$(SAM)/system/CMSIS/CMSIS/Include/ \
-I$(SAM)/system/CMSIS/Device/ATMEL/ -I$(SAM)/cores/arduino \
-I$(SAM)/variants/arduino_due_x
#also include the current dir for convenience
INCLUDES += -I.
#compilation flags common to both c and c++
COMMON_FLAGS:=-g -Os -w -ffunction-sections -fdata-sections -nostdlib \
--param max-inline-insns-single=500 -mcpu=cortex-m3 -mthumb \
-fno-threadsafe-statics
#for compiling c (do not warn, this is not our code)
CFLAGS:=$(COMMON_FLAGS) -std=gnu11
#for compiling c++
CXXFLAGS:=$(COMMON_FLAGS) -fno-rtti -fno-exceptions -std=gnu++11 -Wall -Wextra
#let the results be named after the project
PROJNAME:=$(shell basename *.ino .ino)
#we will make a new mainfile from the ino file.
NEWMAINFILE:=$(TMPDIR)/$(PROJNAME).ino.cpp
#our own sourcefiles is the (converted) ino file and any local cpp files
MYSRCFILES:=$(NEWMAINFILE) $(shell ls *.cpp 2>/dev/null)
MYOBJFILES:=$(addsuffix .o,$(addprefix $(TMPDIR)/,$(notdir $(MYSRCFILES))))
#These source files are the ones forming core.a
CORESRCXX:=$(shell ls ${SAM}/cores/arduino/*.cpp ${SAM}/cores/arduino/USB/*.cpp ${SAM}/variants/arduino_due_x/variant.cpp)
CORESRC:=$(shell ls ${SAM}/cores/arduino/*.c)
#hey this one is needed too: $(SAM)/cores/arduino/wiring_pulse_asm.S" add -x assembler-with-cpp
#and this one: /1.6.11/cores/arduino/avr/dtostrf.c but it seems to work
#anyway, probably because I do not use that functionality.
#convert the core source files to object files. assume no clashes.
COREOBJSXX:=$(addprefix $(TMPDIR)/core/,$(notdir $(CORESRCXX)) )
COREOBJSXX:=$(addsuffix .o,$(COREOBJSXX))
COREOBJS:=$(addprefix $(TMPDIR)/core/,$(notdir $(CORESRC)) )
COREOBJS:=$(addsuffix .o,$(COREOBJS))
default:
@echo default rule, does nothing. Try make compile or make upload.
#This rule is good to just make sure stuff compiles, without having to wait
#for bossac.
compile: GitVersion.h $(TMPDIR)/$(PROJNAME).elf $(TMPDIR)/$(PROJNAME).bin
#This is a make rule template to create object files from the source files.
# arg 1=src file
# arg 2=object file
# arg 3= XX if c++, empty if c
define OBJ_template
$(2): $(1)
$(C$(3)) -MD -c $(C$(3)FLAGS) $(DEFINES) $(INCLUDES) $(1) -o $(2)
endef
#now invoke the template both for c++ sources
$(foreach src,$(CORESRCXX), $(eval $(call OBJ_template,$(src),$(addsuffix .o,$(addprefix $(TMPDIR)/core/,$(notdir $(src)))),XX) ) )
#...and for c sources:
$(foreach src,$(CORESRC), $(eval $(call OBJ_template,$(src),$(addsuffix .o,$(addprefix $(TMPDIR)/core/,$(notdir $(src)))),) ) )
#and our own c++ sources
$(foreach src,$(MYSRCFILES), $(eval $(call OBJ_template,$(src),$(addsuffix .o,$(addprefix $(TMPDIR)/,$(notdir $(src)))),XX) ) )
clean:
test ! -d $(TMPDIR) || rm -rf $(TMPDIR)
$(RM) GitVersion.h
.PHONY: .FORCE upload default
$(TMPDIR):
mkdir -p $(TMPDIR)
$(TMPDIR)/core:
mkdir -p $(TMPDIR)/core
#creates the cpp file from the .ino file
$(NEWMAINFILE): $(PROJNAME).ino
cat $(SAM)/cores/arduino/main.cpp > $(NEWMAINFILE)
cat $(PROJNAME).ino >> $(NEWMAINFILE)
echo 'extern "C" void __cxa_pure_virtual() {while (true);}' >> $(NEWMAINFILE)
#include the dependencies for our own files
-include $(MYOBJFILES:.o=.d)
#create the core library from the core objects. Do this EXACTLY as the
#arduino IDE does it, seems *really* picky about this.
#Sorry for the hard coding.
$(TMPDIR)/core.a: $(TMPDIR)/core $(COREOBJS) $(COREOBJSXX)
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/wiring_shift.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/wiring_analog.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/itoa.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/cortex_handlers.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/hooks.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/wiring.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/WInterrupts.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/syscalls_sam3.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/iar_calls_sam3.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/wiring_digital.c.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/Print.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/USARTClass.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/WString.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/PluggableUSB.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/USBCore.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/CDC.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/wiring_pulse.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/UARTClass.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/main.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/new.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/watchdog.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/Stream.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/RingBuffer.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/IPAddress.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/Reset.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/WMath.cpp.o
$(AR) rcs $(TMPDIR)/core.a $(TMPDIR)/core/variant.cpp.o
#link our own object files with core to form the elf file
$(TMPDIR)/$(PROJNAME).elf: $(TMPDIR)/core.a $(TMPDIR)/core/syscalls_sam3.c.o $(MYOBJFILES)
$(CC) -mcpu=cortex-m3 -mthumb -Os -Wl,--gc-sections -T$(SAM)/variants/arduino_due_x/linker_scripts/gcc/flash.ld -Wl,-Map,$(NEWMAINFILE).map -o $@ -L$(TMPDIR) -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group -u _sbrk -u link -u _close -u _fstat -u _isatty -u _lseek -u _read -u _write -u _exit -u kill -u _getpid $(MYOBJFILES) $(TMPDIR)/core/variant.cpp.o $(SAM)/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a $(SAM)/system/CMSIS/CMSIS/Lib/GCC/libarm_cortexM3l_math.a $(TMPDIR)/core.a -Wl,--end-group -lm -gcc
#copy from the hex to our bin file (why?)
$(TMPDIR)/$(PROJNAME).bin: $(TMPDIR)/$(PROJNAME).elf
$(OBJCOPY) -O binary $< $@
#upload to the arduino by first resetting it (stty) and the running bossac
upload: compile
stty -F /dev/$(PORT) cs8 1200 hupcl
$(ADIR)/packages/arduino/tools/bossac/1.6.1-arduino/bossac -i --port=$(PORT) -U false -e -w $(VERIFY) -b $(TMPDIR)/$(PROJNAME).bin -R
# Export the current git version if the index file exists, else 000...
GitVersion.h: .FORCE
ifneq ("$(wildcard .git/index)","")
echo "#define GITVERSION \"$(shell git rev-parse --short HEAD)\"" > $@
else
echo "#define GITVERSION \"0000000\"" > $@
endif
.FORCE:

Some files were not shown because too many files have changed in this diff Show More