mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-15 16:24:11 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a904b5fb4e | ||
|
|
c3246dbcb7 | ||
|
|
edd60caad3 | ||
|
|
b8a0f7b1cf | ||
|
|
28e564738e | ||
|
|
029e6df4b9 | ||
|
|
508018c89c |
@@ -4,6 +4,3 @@
|
||||
[submodule "STM32F7XX_Lib"]
|
||||
path = STM32F7XX_Lib
|
||||
url = https://github.com/juribeparada/STM32F7XX_Lib.git
|
||||
[submodule "STM32F10X_Lib"]
|
||||
path = STM32F10X_Lib
|
||||
url = https://github.com/shawnchain/STM32F10X_Lib.git
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||
* 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
|
||||
@@ -20,7 +20,7 @@
|
||||
#define CONFIG_H
|
||||
|
||||
// Allow for the selection of which modes to compile into the firmware. This is particularly useful for processors
|
||||
// which have limited code space and processing power like the STM32F103, which is found on older/cheaper boards.
|
||||
// which have limited code space and processing power.
|
||||
|
||||
// Enable D-Star support.
|
||||
#define MODE_DSTAR
|
||||
@@ -38,6 +38,9 @@
|
||||
#define MODE_NXDN
|
||||
#define USE_NXDN_BOXCAR
|
||||
|
||||
// Enable dPMR support.
|
||||
#define MODE_DPMR
|
||||
|
||||
// Enable M17 support.
|
||||
#define MODE_M17
|
||||
|
||||
@@ -67,7 +70,7 @@
|
||||
// #define EXTERNAL_OSC 19200000
|
||||
|
||||
// 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 (Arduino Due, STM32F1_POG, etc). 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, Teensy 3.x. External FM might 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
|
||||
@@ -78,13 +81,8 @@
|
||||
// For the original Arduino Due pin layout
|
||||
// #define ARDUINO_DUE_PAPA
|
||||
|
||||
#if defined(STM32F1)
|
||||
// For the SQ6POG board
|
||||
#define STM32F1_POG
|
||||
#else
|
||||
// For the ZUM V1.0 and V1.0.1 boards pin layout
|
||||
// #define ARDUINO_DUE_ZUM_V10
|
||||
#endif
|
||||
|
||||
// For the SP8NTH board
|
||||
// #define ARDUINO_DUE_NTH
|
||||
@@ -105,6 +103,9 @@
|
||||
// Use the modem as a serial repeater for Nextion displays
|
||||
#define SERIAL_REPEATER
|
||||
|
||||
// Set the baud rate of the modem serial repeater for Nextion displays
|
||||
#define SERIAL_REPEATER_BAUD_RATE 9600
|
||||
|
||||
// Use the modem as an I2C repeater for OLED displays
|
||||
// #define I2C_REPEATER
|
||||
|
||||
@@ -127,11 +128,8 @@
|
||||
// Use the D-Star and YSF LEDs for FM
|
||||
#define USE_ALTERNATE_FM_LEDS
|
||||
|
||||
#if defined(STM32F1_POG)
|
||||
// Slower boards need to run their serial at 115200 baud
|
||||
#undef SERIAL_SPEED
|
||||
#define SERIAL_SPEED 115200
|
||||
#endif
|
||||
// Use the DMR and YSF LEDs for dPMR
|
||||
#define USE_ALTERNATE_DPMR_LEDS
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+120
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+6
-11
@@ -42,8 +42,7 @@ class CFMDirectFormI
|
||||
public:
|
||||
|
||||
// convenience function which takes the a0 argument but ignores it!
|
||||
CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2,
|
||||
const q31_t, const q31_t a1, const q31_t a2)
|
||||
CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2, const q31_t, const q31_t a1, const q31_t a2)
|
||||
{
|
||||
// FIR coefficients
|
||||
c_b0 = b0;
|
||||
@@ -57,21 +56,21 @@ public:
|
||||
|
||||
CFMDirectFormI(const CFMDirectFormI &my)
|
||||
{
|
||||
// delay line
|
||||
// delay line
|
||||
m_x2 = my.m_x2; // x[n-2]
|
||||
m_y2 = my.m_y2; // y[n-2]
|
||||
m_x1 = my.m_x1; // x[n-1]
|
||||
m_y1 = my.m_y1; // y[n-1]
|
||||
|
||||
// coefficients
|
||||
// coefficients
|
||||
c_b0 = my.c_b0;
|
||||
c_b1 = my.c_b1;
|
||||
c_b2 = my.c_b2; // FIR
|
||||
c_a1 = my.c_a1;
|
||||
c_a2 = my.c_a2; // IIR
|
||||
}
|
||||
}
|
||||
|
||||
void reset ()
|
||||
void reset()
|
||||
{
|
||||
m_x1 = 0;
|
||||
m_x2 = 0;
|
||||
@@ -83,11 +82,7 @@ public:
|
||||
inline q15_t filter(const q15_t in)
|
||||
{
|
||||
// calculate the output
|
||||
register q31_t out_upscaled = c_b0 * in
|
||||
+ c_b1 * m_x1
|
||||
+ c_b2 * m_x2
|
||||
- c_a1 * m_y1
|
||||
- c_a2 * m_y2;
|
||||
q31_t out_upscaled = c_b0 * in + c_b1 * m_x1 + c_b2 * m_x2 - c_a1 * m_y1 - c_a2 * m_y2;
|
||||
|
||||
q15_t out = __SSAT(out_upscaled >> 15, 15);
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
* 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
|
||||
@@ -23,15 +23,12 @@
|
||||
#include "stm32f4xx.h"
|
||||
#elif defined(STM32F7XX)
|
||||
#include "stm32f7xx.h"
|
||||
#elif defined(STM32F105xC)
|
||||
#include "stm32f1xx.h"
|
||||
#include "STM32Utils.h"
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h.
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__) || defined(STM32F105xC)
|
||||
#if defined(__SAM3X8E__)
|
||||
#define ARM_MATH_CM3
|
||||
#elif defined(STM32F7XX)
|
||||
#define ARM_MATH_CM7
|
||||
@@ -52,6 +49,7 @@ enum MMDVM_STATE {
|
||||
STATE_NXDN = 5,
|
||||
STATE_POCSAG = 6,
|
||||
STATE_M17 = 7,
|
||||
STATE_DPMR = 8,
|
||||
STATE_FM = 10,
|
||||
STATE_AX25 = 11,
|
||||
|
||||
@@ -82,6 +80,8 @@ enum MMDVM_STATE {
|
||||
#include "DMRDMOTX.h"
|
||||
#include "DStarRX.h"
|
||||
#include "DStarTX.h"
|
||||
#include "DPMRRX.h"
|
||||
#include "DPMRTX.h"
|
||||
#include "DMRRX.h"
|
||||
#include "DMRTX.h"
|
||||
#include "YSFRX.h"
|
||||
@@ -118,7 +118,7 @@ const uint16_t RX_BLOCK_SIZE = 2U;
|
||||
const uint16_t TX_RINGBUFFER_SIZE = 500U;
|
||||
const uint16_t RX_RINGBUFFER_SIZE = 600U;
|
||||
|
||||
#if defined(STM32F105xC) || defined(__MK20DX256__)
|
||||
#if defined(__MK20DX256__)
|
||||
const uint16_t TX_BUFFER_LEN = 2000U;
|
||||
#else
|
||||
const uint16_t TX_BUFFER_LEN = 4000U;
|
||||
@@ -133,6 +133,7 @@ extern bool m_p25Enable;
|
||||
extern bool m_nxdnEnable;
|
||||
extern bool m_pocsagEnable;
|
||||
extern bool m_m17Enable;
|
||||
extern bool m_dpmrEnable;
|
||||
extern bool m_fmEnable;
|
||||
extern bool m_ax25Enable;
|
||||
|
||||
@@ -194,6 +195,13 @@ extern CM17TX m17TX;
|
||||
extern CCalM17 calM17;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
extern CDPMRRX dpmrRX;
|
||||
extern CDPMRTX dpmrTX;
|
||||
|
||||
extern CCalNXDN calNXDN;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_FM)
|
||||
extern CFM fm;
|
||||
extern CCalFM calFM;
|
||||
|
||||
@@ -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) 2015 by Jim Mclaughlin KI6ZUM
|
||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||
*
|
||||
@@ -44,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;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_NXDN)
|
||||
#if defined(USE_NXDN_BOXCAR)
|
||||
#if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
|
||||
// One symbol boxcar filter
|
||||
static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000};
|
||||
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
|
||||
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,
|
||||
@@ -62,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};
|
||||
const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DSTAR)
|
||||
// Generated using gaussfir(0.5, 4, 5) in MATLAB
|
||||
@@ -103,17 +103,16 @@ m_rrc02State2(),
|
||||
m_boxcar5Filter(),
|
||||
m_boxcar5State(),
|
||||
#endif
|
||||
#if defined(MODE_NXDN)
|
||||
#if defined(USE_NXDN_BOXCAR)
|
||||
#if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
|
||||
m_boxcar10Filter(),
|
||||
m_boxcar10State(),
|
||||
#else
|
||||
#endif
|
||||
#if defined(MODE_DPMR) || (defined(MODE_NXDN) && !defined(USE_NXDN_BOXCAR))
|
||||
m_nxdnFilter(),
|
||||
m_nxdnISincFilter(),
|
||||
m_nxdnState(),
|
||||
m_nxdnISincState(),
|
||||
#endif
|
||||
#endif
|
||||
#if defined(MODE_M17)
|
||||
m_rrc05Filter(),
|
||||
m_rrc05State(),
|
||||
@@ -127,6 +126,7 @@ m_ysfTXLevel(128 * 128),
|
||||
m_p25TXLevel(128 * 128),
|
||||
m_nxdnTXLevel(128 * 128),
|
||||
m_m17TXLevel(128 * 128),
|
||||
m_dpmrTXLevel(128 * 128),
|
||||
m_pocsagTXLevel(128 * 128),
|
||||
m_fmTXLevel(128 * 128),
|
||||
m_ax25TXLevel(128 * 128),
|
||||
@@ -177,13 +177,14 @@ m_lockout(false)
|
||||
m_boxcar5Filter.pCoeffs = BOXCAR5_FILTER;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_NXDN)
|
||||
#if defined(USE_NXDN_BOXCAR)
|
||||
#if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
|
||||
::memset(m_boxcar10State, 0x00U, 40U * sizeof(q15_t));
|
||||
m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN;
|
||||
m_boxcar10Filter.pState = m_boxcar10State;
|
||||
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_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
|
||||
|
||||
@@ -195,7 +196,6 @@ m_lockout(false)
|
||||
m_nxdnISincFilter.pState = m_nxdnISincState;
|
||||
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MODE_M17)
|
||||
::memset(m_rrc05State, 0x00U, 70U * sizeof(q15_t));
|
||||
@@ -236,6 +236,9 @@ void CIO::selfTest()
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
setFMInt(ledValue);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_DPMR_LEDS)
|
||||
setDPMRInt(ledValue);
|
||||
#endif
|
||||
#endif
|
||||
delayInt(250);
|
||||
}
|
||||
@@ -256,6 +259,9 @@ void CIO::selfTest()
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
setFMInt(false);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_DPMR_LEDS)
|
||||
setDPMRInt(false);
|
||||
#endif
|
||||
setDStarInt(true);
|
||||
|
||||
@@ -286,9 +292,19 @@ void CIO::selfTest()
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
delayInt(250);
|
||||
setFMInt(true);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_DPMR_LEDS)
|
||||
delayInt(250);
|
||||
setDPMRInt(true);
|
||||
|
||||
delayInt(250);
|
||||
setFMInt(false);
|
||||
setDPMRInt(false);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||
delayInt(250);
|
||||
setFMInt(true);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
@@ -338,7 +354,7 @@ void CIO::process()
|
||||
if (m_started) {
|
||||
// Two seconds timeout
|
||||
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 (m_modemState == STATE_DMR && m_tx)
|
||||
dmrTX.setStart(false);
|
||||
@@ -502,6 +518,22 @@ void CIO::process()
|
||||
}
|
||||
#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 (m_fmEnable) {
|
||||
bool cos = getCOSInt();
|
||||
@@ -623,6 +655,24 @@ void CIO::process()
|
||||
}
|
||||
#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)
|
||||
else if (m_modemState == STATE_FM) {
|
||||
bool cos = getCOSInt();
|
||||
@@ -694,6 +744,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
||||
case STATE_M17:
|
||||
txLevel = m_m17TXLevel;
|
||||
break;
|
||||
case STATE_DPMR:
|
||||
txLevel = m_dpmrTXLevel;
|
||||
break;
|
||||
case STATE_POCSAG:
|
||||
txLevel = m_pocsagTXLevel;
|
||||
break;
|
||||
@@ -755,6 +808,7 @@ void CIO::setMode(MMDVM_STATE state)
|
||||
case STATE_P25: setP25Int(false); break;
|
||||
case STATE_NXDN: setNXDNInt(false); break;
|
||||
case STATE_M17: setM17Int(false); break;
|
||||
case STATE_DPMR: setDPMRInt(false); break;
|
||||
case STATE_POCSAG: setPOCSAGInt(false); break;
|
||||
case STATE_FM: setFMInt(false); break;
|
||||
default: break;
|
||||
@@ -767,6 +821,7 @@ void CIO::setMode(MMDVM_STATE state)
|
||||
case STATE_P25: setP25Int(true); break;
|
||||
case STATE_NXDN: setNXDNInt(true); break;
|
||||
case STATE_M17: setM17Int(true); break;
|
||||
case STATE_DPMR: setDPMRInt(true); break;
|
||||
case STATE_POCSAG: setPOCSAGInt(true); break;
|
||||
case STATE_FM: setFMInt(true); break;
|
||||
default: break;
|
||||
@@ -776,7 +831,7 @@ void CIO::setMode(MMDVM_STATE 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;
|
||||
|
||||
@@ -788,6 +843,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
||||
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
||||
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
||||
m_m17TXLevel = q15_t(m17TXLevel * 128);
|
||||
m_dpmrTXLevel = q15_t(dpmrTXLevel * 128);
|
||||
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
|
||||
m_fmTXLevel = q15_t(fmTXLevel * 128);
|
||||
m_ax25TXLevel = q15_t(ax25TXLevel * 128);
|
||||
@@ -807,6 +863,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
||||
m_p25TXLevel = -m_p25TXLevel;
|
||||
m_nxdnTXLevel = -m_nxdnTXLevel;
|
||||
m_m17TXLevel = -m_m17TXLevel;
|
||||
m_dpmrTXLevel = -m_dpmrTXLevel;
|
||||
m_pocsagTXLevel = -m_pocsagTXLevel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*
|
||||
* 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
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
@@ -96,17 +96,17 @@ private:
|
||||
q15_t m_boxcar5State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||
#endif
|
||||
|
||||
#if defined(MODE_NXDN)
|
||||
#if defined(USE_NXDN_BOXCAR)
|
||||
#if defined(MODE_NXDN) && defined(USE_NXDN_BOXCAR)
|
||||
arm_fir_instance_q15 m_boxcar10Filter;
|
||||
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_nxdnISincFilter;
|
||||
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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MODE_M17)
|
||||
arm_fir_instance_q15 m_rrc05Filter;
|
||||
@@ -122,6 +122,7 @@ private:
|
||||
q15_t m_p25TXLevel;
|
||||
q15_t m_nxdnTXLevel;
|
||||
q15_t m_m17TXLevel;
|
||||
q15_t m_dpmrTXLevel;
|
||||
q15_t m_pocsagTXLevel;
|
||||
q15_t m_fmTXLevel;
|
||||
q15_t m_ax25TXLevel;
|
||||
@@ -160,6 +161,7 @@ private:
|
||||
void setNXDNInt(bool on);
|
||||
void setPOCSAGInt(bool on);
|
||||
void setM17Int(bool on);
|
||||
void setDPMRInt(bool on);
|
||||
void setFMInt(bool on);
|
||||
|
||||
void delayInt(unsigned int dly);
|
||||
|
||||
-500
@@ -1,500 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
|
||||
*
|
||||
* 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(STM32F1)
|
||||
|
||||
#if defined(STM32F1_POG)
|
||||
/*
|
||||
Pin definitions for STM32F1 POG Board:
|
||||
|
||||
PTT PB12 output
|
||||
COSLED PB5 output
|
||||
LED PB4 output
|
||||
COS PB13 input/PD
|
||||
|
||||
DSTAR PB7 output
|
||||
DMR PB6 output
|
||||
YSF PB8 output
|
||||
P25 PB9 output
|
||||
NXDN PB10 output
|
||||
POCSAG PB11 output
|
||||
|
||||
RX PB0 analog input (ADC1_8)
|
||||
RSSI PB1 analog input (ADC2_9)
|
||||
TX PA4 analog output (DAC_OUT1)
|
||||
|
||||
EXT_CLK PA15 input (AF: TIM2_CH1_ETR)
|
||||
|
||||
USART1_TXD PA9 output (AF)
|
||||
USART1_RXD PA10 input (AF)
|
||||
|
||||
*/
|
||||
|
||||
#define PIN_PTT 12
|
||||
#define PORT_PTT GPIOB
|
||||
#define BB_PTT *((bitband_t)BITBAND_PERIPH(&PORT_PTT->ODR, PIN_PTT))
|
||||
#define PIN_COSLED 5
|
||||
#define PORT_COSLED GPIOB
|
||||
#define BB_COSLED *((bitband_t)BITBAND_PERIPH(&PORT_COSLED->ODR, PIN_COSLED))
|
||||
#define PIN_LED 4
|
||||
#define PORT_LED GPIOB
|
||||
#define BB_LED *((bitband_t)BITBAND_PERIPH(&PORT_LED->ODR, PIN_LED))
|
||||
#define PIN_COS 13
|
||||
#define PORT_COS GPIOB
|
||||
#define BB_COS *((bitband_t)BITBAND_PERIPH(&PORT_COS->IDR, PIN_COS))
|
||||
|
||||
#define PIN_DSTAR 7
|
||||
#define PORT_DSTAR GPIOB
|
||||
#define BB_DSTAR *((bitband_t)BITBAND_PERIPH(&PORT_DSTAR->ODR, PIN_DSTAR))
|
||||
#define PIN_DMR 6
|
||||
#define PORT_DMR GPIOB
|
||||
#define BB_DMR *((bitband_t)BITBAND_PERIPH(&PORT_DMR->ODR, PIN_DMR))
|
||||
#define PIN_YSF 8
|
||||
#define PORT_YSF GPIOB
|
||||
#define BB_YSF *((bitband_t)BITBAND_PERIPH(&PORT_YSF->ODR, PIN_YSF))
|
||||
#define PIN_P25 9
|
||||
#define PORT_P25 GPIOB
|
||||
#define BB_P25 *((bitband_t)BITBAND_PERIPH(&PORT_P25->ODR, PIN_P25))
|
||||
#define PIN_NXDN 10
|
||||
#define PORT_NXDN GPIOB
|
||||
#define BB_NXDN *((bitband_t)BITBAND_PERIPH(&PORT_NXDN->ODR, PIN_NXDN))
|
||||
#define PIN_POCSAG 11
|
||||
#define PORT_POCSAG GPIOB
|
||||
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
|
||||
|
||||
#define PIN_RX 0
|
||||
#define PIN_RX_ADC_CH 8
|
||||
#define PORT_RX GPIOB
|
||||
#define PIN_RSSI 1
|
||||
#define PIN_RSSI_ADC_CH 9
|
||||
#define PORT_RSSI GPIOB
|
||||
#define PIN_TX 4
|
||||
#define PIN_TX_DAC_CH 1
|
||||
#define PORT_TX GPIOA
|
||||
|
||||
#define PIN_EXT_CLK 15
|
||||
#define SRC_EXT_CLK 15
|
||||
#define PORT_EXT_CLK GPIOA
|
||||
|
||||
#define PIN_USART1_TXD 9
|
||||
#define PORT_USART1_TXD GPIOA
|
||||
#define PIN_USART1_RXD 10
|
||||
#define PORT_USART1_RXD GPIOA
|
||||
|
||||
#else // defined(STM32F1_POG)
|
||||
#error "Either STM32F1_POG, or sth need to be defined"
|
||||
#endif // defined(STM32F1_POG)
|
||||
|
||||
const uint16_t DC_OFFSET = 2048U;
|
||||
|
||||
// Sampling frequency
|
||||
#define SAMP_FREQ 24000
|
||||
|
||||
extern "C" {
|
||||
void TIM2_IRQHandler() {
|
||||
if ((TIM2->SR & TIM_SR_UIF) == TIM_SR_UIF) {
|
||||
TIM2->SR = ~TIM_SR_UIF; // clear UI flag
|
||||
io.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void delay(uint32_t cnt)
|
||||
{
|
||||
while(cnt--)
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
// source: http://www.freddiechopin.info/
|
||||
void GPIOConfigPin(GPIO_TypeDef *port_ptr, uint32_t pin, uint32_t mode_cnf_value)
|
||||
{
|
||||
volatile uint32_t *cr_ptr;
|
||||
uint32_t cr_value;
|
||||
|
||||
cr_ptr = &port_ptr->CRL; // configuration of pins [0,7] is in CRL
|
||||
|
||||
if (pin >= 8) // is pin in [8; 15]?
|
||||
{ // configuration of pins [8,15] is in CRH
|
||||
cr_ptr++; // advance to next struct element CRL -> CRH
|
||||
pin -= 8; // crop the pin number
|
||||
}
|
||||
|
||||
cr_value = *cr_ptr; // localize the CRL / CRH value
|
||||
|
||||
cr_value &= ~(0xF << (pin * 4)); // clear the MODE and CNF fields (now that pin is an analog input)
|
||||
cr_value |= (mode_cnf_value << (pin * 4)); // save new MODE and CNF value for desired pin
|
||||
|
||||
*cr_ptr = cr_value; // save localized value to CRL / CRL
|
||||
}
|
||||
|
||||
#if defined(STM32F1_POG)
|
||||
void FancyLEDEffect()
|
||||
{
|
||||
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25};
|
||||
|
||||
for(int i=0; i<7; i++){
|
||||
*foo[i] = 0x01;
|
||||
}
|
||||
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||
delay(SystemCoreClock/1000*100);
|
||||
for(int i=0; i<7; i++){
|
||||
*foo[i] = 0x00;
|
||||
}
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||
delay(SystemCoreClock/1000*20);
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||
|
||||
*foo[0] = 0x01;
|
||||
for(int i=1; i<7; i++){
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*foo[i-1] = 0x00;
|
||||
*foo[i] = 0x01;
|
||||
}
|
||||
for(int i=5; i>=0; i--){
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*foo[i+1] = 0x00;
|
||||
*foo[i] = 0x01;
|
||||
}
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*foo[5+1-6] = 0x00;
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||
delay(SystemCoreClock/1000*10);
|
||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1|GPIO_CRL_CNF0_1);
|
||||
delay(SystemCoreClock/1000*50);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void GPIOInit()
|
||||
{
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN
|
||||
| RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN
|
||||
| RCC_APB2ENR_AFIOEN; // enable all GPIOs
|
||||
|
||||
// set all ports to input with pull-down
|
||||
GPIOA->CRL = 0x88888888;
|
||||
GPIOA->CRH = 0x88888888;
|
||||
GPIOA->ODR = 0;
|
||||
GPIOB->CRL = 0x88888888;
|
||||
GPIOB->CRH = 0x88888888;
|
||||
GPIOB->ODR = 0;
|
||||
GPIOC->CRL = 0x88888888;
|
||||
GPIOC->CRH = 0x88888888;
|
||||
GPIOC->ODR = 0;
|
||||
GPIOD->CRL = 0x88888888;
|
||||
GPIOD->CRH = 0x88888888;
|
||||
GPIOD->ODR = 0;
|
||||
|
||||
// configure ports
|
||||
GPIOConfigPin(PORT_PTT, PIN_PTT, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_COSLED, PIN_COSLED, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_LED, PIN_LED, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_COS, PIN_COS, GPIO_CRL_CNF0_1);
|
||||
|
||||
GPIOConfigPin(PORT_DSTAR, PIN_DSTAR, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_DMR, PIN_DMR, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_YSF, PIN_YSF, GPIO_CRL_MODE0_1);
|
||||
GPIOConfigPin(PORT_P25, PIN_P25, GPIO_CRL_MODE0_1);
|
||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||
GPIOConfigPin(PORT_M17, PIN_M17, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
|
||||
#endif
|
||||
|
||||
GPIOConfigPin(PORT_RX, PIN_RX, 0);
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
GPIOConfigPin(PORT_RSSI, PIN_RSSI, 0);
|
||||
#endif
|
||||
GPIOConfigPin(PORT_TX, PIN_TX, 0);
|
||||
|
||||
#if defined(EXTERNAL_OSC)
|
||||
#if defined(STM32F1_POG)
|
||||
GPIOConfigPin(PORT_EXT_CLK, PIN_EXT_CLK, GPIO_CRL_CNF0_0);
|
||||
AFIO->MAPR = (AFIO->MAPR & ~AFIO_MAPR_TIM2_REMAP) | AFIO_MAPR_TIM2_REMAP_0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1|GPIO_CRL_CNF0_1);
|
||||
GPIOConfigPin(PORT_USART1_RXD, PIN_USART1_RXD, GPIO_CRL_CNF0_0);
|
||||
|
||||
AFIO->MAPR = (AFIO->MAPR & ~AFIO_MAPR_SWJ_CFG) | AFIO_MAPR_SWJ_CFG_1;
|
||||
}
|
||||
|
||||
|
||||
static inline void ADCInit()
|
||||
{
|
||||
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE_Msk)
|
||||
| RCC_CFGR_ADCPRE_DIV6; // ADC clock divided by 6 (72MHz/6 = 12MHz)
|
||||
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
RCC->APB2ENR |= RCC_APB2ENR_ADC2EN;
|
||||
#endif
|
||||
|
||||
// Init ADCs in dual mode (RSSI)
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
ADC1->CR1 = ADC_CR1_DUALMOD_1|ADC_CR1_DUALMOD_2; // Regular simultaneous mode
|
||||
#endif
|
||||
|
||||
// Set sampling time to 7.5 cycles
|
||||
if (PIN_RX_ADC_CH < 10) {
|
||||
ADC1->SMPR2 = ADC_SMPR2_SMP0_0 << (3*PIN_RX_ADC_CH);
|
||||
} else {
|
||||
ADC1->SMPR1 = ADC_SMPR1_SMP10_0 << (3*PIN_RX_ADC_CH);
|
||||
}
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
if (PIN_RSSI_ADC_CH < 10) {
|
||||
ADC2->SMPR2 = ADC_SMPR2_SMP0_0 << (3*PIN_RSSI_ADC_CH);
|
||||
} else {
|
||||
ADC2->SMPR1 = ADC_SMPR1_SMP10_0 << (3*PIN_RSSI_ADC_CH);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set conversion channel (single conversion)
|
||||
ADC1->SQR3 = PIN_RX_ADC_CH;
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
ADC2->SQR3 = PIN_RSSI_ADC_CH;
|
||||
#endif
|
||||
|
||||
// Enable ADC
|
||||
ADC1->CR2 |= ADC_CR2_ADON;
|
||||
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
// Enable ADC2
|
||||
ADC2->CR2 |= ADC_CR2_ADON;
|
||||
#endif
|
||||
|
||||
// Start calibration
|
||||
delay(6*2);
|
||||
ADC1->CR2 |= ADC_CR2_CAL;
|
||||
while((ADC1->CR2 & ADC_CR2_CAL) == ADC_CR2_CAL)
|
||||
;
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
ADC2->CR2 |= ADC_CR2_CAL;
|
||||
while((ADC2->CR2 & ADC_CR2_CAL) == ADC_CR2_CAL)
|
||||
;
|
||||
#endif
|
||||
|
||||
// Trigger first conversion
|
||||
ADC1->CR2 |= ADC_CR2_ADON;
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
ADC2->CR2 |= ADC_CR2_ADON;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void DACInit()
|
||||
{
|
||||
RCC->APB1ENR |= RCC_APB1ENR_DACEN;
|
||||
|
||||
DAC->CR = DAC_CR_EN1;
|
||||
}
|
||||
|
||||
|
||||
static inline void TimerInit()
|
||||
{
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
|
||||
|
||||
#if defined(EXTERNAL_OSC)
|
||||
// Enable external clock, prescaler /4
|
||||
TIM2->SMCR = TIM_SMCR_ECE | TIM_SMCR_ETPS_1;
|
||||
#endif
|
||||
|
||||
// TIM2 output frequency
|
||||
TIM2->PSC = 0;
|
||||
#if defined(EXTERNAL_OSC)
|
||||
// TimerCount = ExternalOsc
|
||||
// /4 (external clock prescaler)
|
||||
// /SAMP_FREQ
|
||||
TIM2->ARR = (uint16_t) ((EXTERNAL_OSC/(4*SAMP_FREQ)) - 1);
|
||||
#else
|
||||
TIM2->ARR = (uint16_t) ((SystemCoreClock/(SAMP_FREQ)) - 1);
|
||||
#endif
|
||||
|
||||
// Enable TIse 1%-tolerance comM2 interrupt
|
||||
TIM2->DIER = TIM_DIER_UIE;
|
||||
NVIC_EnableIRQ(TIM2_IRQn);
|
||||
|
||||
// Enable TIM2
|
||||
TIM2->CR1 |= TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
|
||||
void CIO::initInt()
|
||||
{
|
||||
GPIOInit();
|
||||
ADCInit();
|
||||
DACInit();
|
||||
#if defined(STM32F1_POG)
|
||||
FancyLEDEffect();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::startInt()
|
||||
{
|
||||
TimerInit();
|
||||
|
||||
BB_COSLED = 0;
|
||||
BB_LED = 1;
|
||||
}
|
||||
|
||||
void CIO::interrupt()
|
||||
{
|
||||
TSample sample = {DC_OFFSET, MARK_NONE};
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
uint16_t rawRSSI = 0U;
|
||||
#endif
|
||||
bitband_t eoc = (bitband_t)BITBAND_PERIPH(&ADC1->SR, ADC_SR_EOS_Pos);
|
||||
bitband_t adon = (bitband_t)BITBAND_PERIPH(&ADC1->CR2, ADC_CR2_ADON_Pos);
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
bitband_t rssi_adon = (bitband_t)BITBAND_PERIPH(&ADC2->CR2, ADC_CR2_ADON_Pos);
|
||||
#endif
|
||||
|
||||
if (*eoc) {
|
||||
// trigger next conversion
|
||||
*adon = 1;
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
*rssi_adon = 1;
|
||||
#endif
|
||||
|
||||
m_txBuffer.get(sample);
|
||||
DAC->DHR12R1 = sample.sample; // Send the value to the DAC
|
||||
|
||||
// Read value from ADC1 and ADC2
|
||||
sample.sample = ADC1->DR; // read conversion result; EOC is cleared by this read
|
||||
m_rxBuffer.put(sample);
|
||||
#if defined(SEND_RSSI_DATA)
|
||||
rawRSSI = ADC2->DR;
|
||||
m_rssiBuffer.put(rawRSSI);
|
||||
#endif
|
||||
|
||||
m_watchdog++;
|
||||
}
|
||||
}
|
||||
|
||||
bool CIO::getCOSInt()
|
||||
{
|
||||
return BB_COS;
|
||||
}
|
||||
|
||||
void CIO::setLEDInt(bool on)
|
||||
{
|
||||
BB_LED = !!on;
|
||||
}
|
||||
|
||||
void CIO::setPTTInt(bool on)
|
||||
{
|
||||
BB_PTT = !!on;
|
||||
}
|
||||
|
||||
void CIO::setCOSInt(bool on)
|
||||
{
|
||||
BB_COSLED = !!on;
|
||||
}
|
||||
|
||||
void CIO::setDStarInt(bool on)
|
||||
{
|
||||
BB_DSTAR = !!on;
|
||||
}
|
||||
|
||||
void CIO::setDMRInt(bool on)
|
||||
{
|
||||
BB_DMR = !!on;
|
||||
}
|
||||
|
||||
void CIO::setYSFInt(bool on)
|
||||
{
|
||||
BB_YSF = !!on;
|
||||
}
|
||||
|
||||
void CIO::setP25Int(bool on)
|
||||
{
|
||||
BB_P25 = !!on;
|
||||
}
|
||||
|
||||
void CIO::setNXDNInt(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_NXDN_LEDS)
|
||||
BB_YSF = !!on;
|
||||
BB_P25 = !!on;
|
||||
#else
|
||||
BB_NXDN = !!on;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setM17Int(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||
BB_DSTAR = !!on;
|
||||
BB_P25 = !!on;
|
||||
#else
|
||||
BB_M17 = !!on;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setPOCSAGInt(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||
BB_DSTAR = !!on;
|
||||
BB_DMR = !!on;
|
||||
#else
|
||||
BB_POCSAG = !!on;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::setFMInt(bool on)
|
||||
{
|
||||
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||
BB_DSTAR = !!on;
|
||||
BB_YSF = !!on;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CIO::delayInt(unsigned int dly)
|
||||
{
|
||||
delay(dly);
|
||||
}
|
||||
|
||||
uint8_t CIO::getCPU() const
|
||||
{
|
||||
return 2U;
|
||||
}
|
||||
|
||||
void CIO::getUDID(uint8_t* buffer)
|
||||
{
|
||||
#if defined(STM32F105xC)
|
||||
::memcpy(buffer, (void *)0x1FFFF7E8, 12U);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 Colin Durbridge G4EML
|
||||
*
|
||||
@@ -18,7 +18,7 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if defined(STM32F4XX) || defined(STM32F7XX) || defined(STM32F105xC)
|
||||
#if defined(STM32F4XX) || defined(STM32F7XX)
|
||||
|
||||
#include "Config.h"
|
||||
#include "Globals.h"
|
||||
@@ -32,6 +32,7 @@ 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;
|
||||
@@ -86,6 +87,11 @@ CM17TX m17TX;
|
||||
CCalM17 calM17;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_NXDN)
|
||||
CDPMRRX dpmrRX;
|
||||
CDPMRTX dpmrTX;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_POCSAG)
|
||||
CPOCSAGTX pocsagTX;
|
||||
CCalPOCSAG calPOCSAG;
|
||||
@@ -154,6 +160,11 @@ void loop()
|
||||
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();
|
||||
|
||||
@@ -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 Colin Durbridge G4EML
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -29,6 +29,7 @@ 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;
|
||||
@@ -83,6 +84,11 @@ CM17TX m17TX;
|
||||
CCalM17 calM17;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_NXDN)
|
||||
CDPMRRX dpmrRX;
|
||||
CDPMRTX dpmrTX;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_POCSAG)
|
||||
CPOCSAGTX pocsagTX;
|
||||
CCalPOCSAG calPOCSAG;
|
||||
@@ -151,6 +157,11 @@ void loop()
|
||||
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();
|
||||
|
||||
Binary file not shown.
-165
@@ -1,165 +0,0 @@
|
||||
# The name for the project
|
||||
TARGET:=mmdvm
|
||||
|
||||
# The CPU architecture (will be used for -mcpu)
|
||||
MCPU:=cortex-m3
|
||||
MCU:=STM32F105xC
|
||||
|
||||
# The source files of the project
|
||||
CSRC:=
|
||||
CXXSRC:=$(wildcard *.cpp)
|
||||
|
||||
# Include directory for the system include files and system source file
|
||||
SYSDIR:=system_stm32f1xx
|
||||
SYSSRC:=$(SYSDIR)/system_stm32f1xx.c
|
||||
|
||||
# Other include directories
|
||||
INCDIR:=
|
||||
|
||||
# Definitions
|
||||
CDEFS:=
|
||||
CXXDEFS:=
|
||||
|
||||
# The name of the startup file which matches to the architecture (MCPU)
|
||||
STARTUP:=$(SYSDIR)/startup_stm32f105xc.S
|
||||
STARTUP_DEFS=
|
||||
|
||||
# Include directory for CMSIS
|
||||
CMSISDIR:=STM32F10X_Lib/CMSIS
|
||||
|
||||
# Libraries
|
||||
LIBDIR:=
|
||||
LIBS:=-larm_cortexM3l_math
|
||||
|
||||
# Name of the linker script
|
||||
LDSCRIPT:=$(SYSDIR)/gcc.ld
|
||||
|
||||
# Target objects and binaries directory
|
||||
OBJDIR:=obj
|
||||
BINDIR:=bin
|
||||
|
||||
# Port definition for programming via bootloader (using stm32flash)
|
||||
BL_PORT:=ttyUSB0
|
||||
|
||||
|
||||
|
||||
# Internal Variables
|
||||
ELF:=$(BINDIR)/$(TARGET).elf
|
||||
HEX:=$(BINDIR)/$(TARGET).hex
|
||||
DIS:=$(BINDIR)/$(TARGET).dis
|
||||
MAP:=$(BINDIR)/$(TARGET).map
|
||||
OBJ:=$(CSRC:%.c=$(OBJDIR)/%.o) $(CXXSRC:%.cpp=$(OBJDIR)/%.o)
|
||||
OBJ+=$(SYSSRC:$(SYSDIR)/%.c=$(OBJDIR)/%.o) $(STARTUP:$(SYSDIR)/%.S=$(OBJDIR)/%.o)
|
||||
|
||||
# Replace standard build tools by arm tools
|
||||
CC:=arm-none-eabi-gcc
|
||||
CXX:=arm-none-eabi-g++
|
||||
AS:=arm-none-eabi-gcc
|
||||
LD:=arm-none-eabi-g++
|
||||
OBJCOPY:=arm-none-eabi-objcopy
|
||||
OBJDUMP:=arm-none-eabi-objdump
|
||||
SIZE:=arm-none-eabi-size
|
||||
|
||||
# Common flags
|
||||
COMMON_FLAGS =-mthumb -mlittle-endian -mcpu=$(MCPU)
|
||||
COMMON_FLAGS+= -Wall
|
||||
COMMON_FLAGS+= -I. -I$(CMSISDIR)/Include -I$(CMSISDIR)/Device/ST/STM32F1xx/Include -I$(SYSDIR)
|
||||
COMMON_FLAGS+= $(addprefix -I,$(INCDIR))
|
||||
COMMON_FLAGS+= -D$(MCU) -DMADEBYMAKEFILE -DSTM32F1
|
||||
COMMON_FLAGS+= -Os -flto -ffunction-sections -fdata-sections
|
||||
COMMON_FLAGS+= -g
|
||||
# Assembler flags
|
||||
ASFLAGS:=$(COMMON_FLAGS)
|
||||
# C flags
|
||||
CFLAGS:=$(COMMON_FLAGS) $(addprefix -D,$(CDEFS))
|
||||
CFLAGS+= -std=gnu11 -nostdlib
|
||||
# CXX flags
|
||||
CXXFLAGS:=$(COMMON_FLAGS) $(addprefix -D,$(CXXDEFS))
|
||||
CXXFLAGS+= -nostdlib -fno-exceptions -fno-rtti
|
||||
# LD flags
|
||||
LDFLAGS:=$(COMMON_FLAGS) -Wl,--gc-sections -Wl,-Map=$(MAP) -Wl,--no-wchar-size-warning
|
||||
LDFLAGS+= --specs=nosys.specs --specs=nano.specs
|
||||
LDFLAGS+= -L$(CMSISDIR)/Lib/GCC/ $(addprefix -L,$(LIBDIR))
|
||||
LDLIBS:=-T$(LDSCRIPT) $(LIBS)
|
||||
|
||||
# Dependecies
|
||||
DEPENDS:=$(CSRC:%.c=$(OBJDIR)/%.d) $(CXXSRC:%.cpp=$(OBJDIR)/%.d)
|
||||
|
||||
|
||||
# Additional Suffixes
|
||||
.SUFFIXES: .elf .hex
|
||||
|
||||
# Targets
|
||||
.PHONY: all
|
||||
all: GitVersion.h $(DIS) $(HEX)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
.PHONY: program
|
||||
program: $(HEX) $(ELF)
|
||||
openocd -f openocd.cfg \
|
||||
-c "program $(HEX) verify reset exit"
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
.PHONY: program_bl
|
||||
program_bl: $(HEX) $(ELF)
|
||||
stm32flash -w $(HEX) -v /dev/$(BL_PORT)
|
||||
$(SIZE) $(ELF)
|
||||
|
||||
.PHONY: run
|
||||
run: $(HEX) $(ELF)
|
||||
openocd -f openocd.cfg \
|
||||
-c "init" -c "reset" -c "exit"
|
||||
|
||||
.PHONY: debug
|
||||
debug: $(ELF)
|
||||
./debug.sh $(ELF)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) $(OBJ) $(HEX) $(ELF) $(DIS) $(MAP) $(DEPENDS) GitVersion.h
|
||||
|
||||
# implicit rules
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O ihex $< $@
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
$(CC) -MMD $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
$(CXX) -MMD $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: $(SYSDIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: $(SYSDIR)/%.S
|
||||
$(AS) $(ASFLAGS) -c $< -o $@
|
||||
|
||||
# explicit rules
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
$(BINDIR):
|
||||
mkdir -p $(BINDIR)
|
||||
|
||||
$(ELF): $(OBJDIR) $(BINDIR) $(OBJ)
|
||||
$(LD) $(OBJ) $(LDFLAGS) $(LDLIBS) -o $@
|
||||
|
||||
$(DIS): $(ELF)
|
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
# include dependecies
|
||||
-include $(DEPENDS)
|
||||
|
||||
# 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
|
||||
@@ -1,6 +1,6 @@
|
||||
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion, P25, NXDN, M17, POCSAG, AX.25, and FM modes.
|
||||
|
||||
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3, M4, or M7 processors with a minimum clock speed greater of 70 MHz, and access to at least one analogue to digital converter, one digital to analogue converter, as well as a number of GPIO pins.
|
||||
It runs on the Arduino Due, the ST-Micro STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3, M4, or M7 processors with a minimum clock speed greater of 80 MHz, and access to at least one analogue to digital converter, one digital to analogue converter, as well as a number of GPIO pins.
|
||||
|
||||
In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. The STM32 support is supplied via the ARM GCC compiler. The Teensy support uses Teensyduino.
|
||||
|
||||
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Wojciech Krutnik N0CALL
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* FIFO ring buffer
|
||||
* source:
|
||||
* http://stackoverflow.com/questions/6822548/correct-way-of-implementing-a-uart-receive-buffer-in-a-small-arm-microcontroller
|
||||
* (modified)
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(RINGBUFF_H)
|
||||
#define RINGBUFF_H
|
||||
|
||||
#define RINGBUFF_SIZE(ringBuff) (ringBuff.size) /* serial buffer in bytes (power 2) */
|
||||
#define RINGBUFF_MASK(ringBuff) (ringBuff.size-1U) /* buffer size mask */
|
||||
|
||||
/* Buffer read / write macros */
|
||||
#define RINGBUFF_RESET(ringBuff) (ringBuff).rdIdx = ringBuff.wrIdx = 0
|
||||
#define RINGBUFF_WRITE(ringBuff, dataIn) (ringBuff).data[RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx++] = (dataIn)
|
||||
#define RINGBUFF_READ(ringBuff) ((ringBuff).data[RINGBUFF_MASK(ringBuff) & ((ringBuff).rdIdx++)])
|
||||
#define RINGBUFF_EMPTY(ringBuff) ((ringBuff).rdIdx == (ringBuff).wrIdx)
|
||||
#define RINGBUFF_FULL(ringBuff) ((RINGBUFF_MASK(ringBuff) & ringBuff.rdIdx) == (RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx))
|
||||
#define RINGBUFF_COUNT(ringBuff) (RINGBUFF_MASK(ringBuff) & ((ringBuff).wrIdx - (ringBuff).rdIdx))
|
||||
|
||||
/* Buffer type */
|
||||
#define DECLARE_RINGBUFFER_TYPE(name, _size) \
|
||||
typedef struct{ \
|
||||
uint32_t size; \
|
||||
uint32_t wrIdx; \
|
||||
uint32_t rdIdx; \
|
||||
uint8_t data[_size]; \
|
||||
}name##_t
|
||||
|
||||
#endif
|
||||
+1
-4
@@ -24,15 +24,12 @@
|
||||
#include "stm32f4xx.h"
|
||||
#elif defined(STM32F7XX)
|
||||
#include "stm32f7xx.h"
|
||||
#elif defined(STM32F105xC)
|
||||
#include "stm32f1xx.h"
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#undef PI
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__) || defined(STM32F105xC)
|
||||
#if defined(__SAM3X8E__)
|
||||
#define ARM_MATH_CM3
|
||||
#elif defined(STM32F7XX)
|
||||
#define ARM_MATH_CM7
|
||||
|
||||
Submodule STM32F10X_Lib deleted from 417e0c2f4a
+200
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013,2015-2021 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2013,2015-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
|
||||
@@ -60,6 +60,11 @@ const uint8_t MMDVM_P25_HDR = 0x30U;
|
||||
const uint8_t MMDVM_P25_LDU = 0x31U;
|
||||
const uint8_t MMDVM_P25_LOST = 0x32U;
|
||||
|
||||
const uint8_t MMDVM_DPMR_HEADER = 0x35U;
|
||||
const uint8_t MMDVM_DPMR_DATA = 0x36U;
|
||||
const uint8_t MMDVM_DPMR_LOST = 0x37U;
|
||||
const uint8_t MMDVM_DPMR_EOT = 0x38U;
|
||||
|
||||
const uint8_t MMDVM_NXDN_DATA = 0x40U;
|
||||
const uint8_t MMDVM_NXDN_LOST = 0x41U;
|
||||
|
||||
@@ -300,7 +305,15 @@ void CSerialPort::getStatus()
|
||||
reply[15U] = 0U;
|
||||
#endif
|
||||
|
||||
reply[16U] = 0x00U;
|
||||
#if defined(MODE_DPMR)
|
||||
if (m_dpmrEnable)
|
||||
reply[16U] = dpmrTX.getSpace();
|
||||
else
|
||||
reply[16U] = 0U;
|
||||
#else
|
||||
reply[16U] = 0U;
|
||||
#endif
|
||||
|
||||
reply[17U] = 0x00U;
|
||||
reply[18U] = 0x00U;
|
||||
reply[19U] = 0x00U;
|
||||
@@ -341,6 +354,9 @@ void CSerialPort::getVersion()
|
||||
#if defined(MODE_FM)
|
||||
reply[4U] |= 0x40U;
|
||||
#endif
|
||||
#if defined(MODE_DPMR)
|
||||
reply[4U] |= 0x80U;
|
||||
#endif
|
||||
|
||||
reply[5U] = 0x00U;
|
||||
#if defined(MODE_POCSAG)
|
||||
@@ -403,6 +419,9 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
#if defined(MODE_M17)
|
||||
bool m17Enable = (data[1U] & 0x40U) == 0x40U;
|
||||
#endif
|
||||
#if defined(MODE_DPMR)
|
||||
bool dpmrEnable = (data[1U] & 0x80U) == 0x80U;
|
||||
#endif
|
||||
#if defined(MODE_POCSAG)
|
||||
bool pocsagEnable = (data[2U] & 0x01U) == 0x01U;
|
||||
#endif
|
||||
@@ -416,9 +435,13 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
|
||||
MMDVM_STATE modemState = MMDVM_STATE(data[4U]);
|
||||
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_M17 && modemState != STATE_POCSAG && modemState != STATE_FM &&
|
||||
modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_M17CAL && modemState != STATE_POCSAGCAL &&
|
||||
modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF &&
|
||||
modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_M17 && modemState != STATE_POCSAG &&
|
||||
modemState != STATE_FM && modemState != STATE_DPMR && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL &&
|
||||
modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K &&
|
||||
modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_M17CAL && modemState != STATE_POCSAGCAL &&
|
||||
modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K &&
|
||||
modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
return 4U;
|
||||
|
||||
#if defined(MODE_DSTAR)
|
||||
@@ -469,6 +492,14 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
return 4U;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
if (modemState == STATE_DPMR && !dpmrEnable)
|
||||
return 4U;
|
||||
#else
|
||||
if (modemState == STATE_DPMR)
|
||||
return 4U;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_POCSAG)
|
||||
if (modemState == STATE_POCSAG && !pocsagEnable)
|
||||
return 4U;
|
||||
@@ -500,6 +531,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
uint8_t pocsagTXLevel = data[15U];
|
||||
uint8_t fmTXLevel = data[16U];
|
||||
uint8_t ax25TXLevel = data[17U];
|
||||
uint8_t dpmrTXLevel = data[18U];
|
||||
|
||||
#if defined(MODE_YSF)
|
||||
uint8_t ysfTXHang = data[20U];
|
||||
@@ -513,6 +545,9 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
#if defined(MODE_M17)
|
||||
uint8_t m17TXHang = data[23U];
|
||||
#endif
|
||||
#if defined(MODE_DPMR)
|
||||
uint8_t dpmrTXHang = data[24U];
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DMR)
|
||||
uint8_t colorCode = data[26U];
|
||||
@@ -570,6 +605,11 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
m17TX.setTXDelay(txDelay);
|
||||
m17TX.setParams(m17TXHang);
|
||||
#endif
|
||||
#if defined(MODE_DPMR)
|
||||
m_dpmrEnable = dpmrEnable;
|
||||
dpmrTX.setTXDelay(txDelay);
|
||||
dpmrTX.setParams(dpmrTXHang);
|
||||
#endif
|
||||
#if defined(MODE_POCSAG)
|
||||
m_pocsagEnable = pocsagEnable;
|
||||
pocsagTX.setTXDelay(txDelay);
|
||||
@@ -583,7 +623,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||
m_fmEnable = fmEnable;
|
||||
#endif
|
||||
|
||||
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, m17TXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset, useCOSAsLockout);
|
||||
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, m17TXLevel, dpmrTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset, useCOSAsLockout);
|
||||
|
||||
io.start();
|
||||
|
||||
@@ -697,9 +737,13 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint16_t length)
|
||||
if (modemState == m_modemState)
|
||||
return 0U;
|
||||
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_M17 && modemState != STATE_POCSAG && modemState != STATE_FM &&
|
||||
modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_M17CAL && modemState != STATE_POCSAGCAL &&
|
||||
modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K && modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF &&
|
||||
modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_M17 && modemState != STATE_DPMR &&
|
||||
modemState != STATE_POCSAG && modemState != STATE_FM && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL &&
|
||||
modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K &&
|
||||
modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K && modemState != STATE_M17CAL && modemState != STATE_POCSAGCAL &&
|
||||
modemState != STATE_FMCAL10K && modemState != STATE_FMCAL12K && modemState != STATE_FMCAL15K && modemState != STATE_FMCAL20K &&
|
||||
modemState != STATE_FMCAL25K && modemState != STATE_FMCAL30K)
|
||||
return 4U;
|
||||
|
||||
#if defined(MODE_DSTAR)
|
||||
@@ -750,6 +794,14 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint16_t length)
|
||||
return 4U;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
if (modemState == STATE_DPMR && !m_dpmrEnable)
|
||||
return 4U;
|
||||
#else
|
||||
if (modemState == STATE_DPMR)
|
||||
return 4U;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_POCSAG)
|
||||
if (modemState == STATE_POCSAG && !m_pocsagEnable)
|
||||
return 4U;
|
||||
@@ -792,6 +844,9 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
||||
case STATE_M17:
|
||||
DEBUG1("Mode set to M17");
|
||||
break;
|
||||
case STATE_DPMR:
|
||||
DEBUG1("Mode set to dPMR");
|
||||
break;
|
||||
case STATE_POCSAG:
|
||||
DEBUG1("Mode set to POCSAG");
|
||||
break;
|
||||
@@ -881,6 +936,11 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
|
||||
m17RX.reset();
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
if (modemState != STATE_DPMR)
|
||||
dpmrRX.reset();
|
||||
#endif
|
||||
|
||||
#if defined(MODE_FM)
|
||||
if (modemState != STATE_FM)
|
||||
fm.reset();
|
||||
@@ -896,7 +956,11 @@ void CSerialPort::start()
|
||||
beginInt(1U, SERIAL_SPEED);
|
||||
|
||||
#if defined(SERIAL_REPEATER)
|
||||
beginInt(3U, 9600);
|
||||
#if defined(SERIAL_REPEATER_BAUD_RATE)
|
||||
beginInt(3U, SERIAL_REPEATER_BAUD_RATE);
|
||||
#else
|
||||
beginInt(3U, 9600);
|
||||
#endif
|
||||
#endif
|
||||
#if defined(I2C_REPEATER)
|
||||
beginInt(10U, 9600);
|
||||
@@ -1357,6 +1421,50 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
case MMDVM_DPMR_HEADER:
|
||||
if (m_dpmrEnable) {
|
||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DPMR)
|
||||
err = dpmrTX.writeHeader(buffer, length);
|
||||
}
|
||||
if (err == 0U) {
|
||||
if (m_modemState == STATE_IDLE)
|
||||
setMode(STATE_DPMR);
|
||||
} else {
|
||||
DEBUG2("Received invalid dPMR header", err);
|
||||
sendNAK(type, err);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DPMR_DATA:
|
||||
if (m_dpmrEnable) {
|
||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DPMR)
|
||||
err = dpmrTX.writeData(buffer, length);
|
||||
}
|
||||
if (err == 0U) {
|
||||
if (m_modemState == STATE_IDLE)
|
||||
setMode(STATE_DPMR);
|
||||
} else {
|
||||
DEBUG2("Received invalid dPMR data", err);
|
||||
sendNAK(type, err);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DPMR_EOT:
|
||||
if (m_dpmrEnable) {
|
||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DPMR)
|
||||
err = dpmrTX.writeEOT(buffer, length);
|
||||
}
|
||||
if (err == 0U) {
|
||||
if (m_modemState == STATE_IDLE)
|
||||
setMode(STATE_DPMR);
|
||||
} else {
|
||||
DEBUG2("Received invalid dPMR EOT", err);
|
||||
sendNAK(type, err);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(MODE_POCSAG)
|
||||
case MMDVM_POCSAG_DATA:
|
||||
if (m_pocsagEnable) {
|
||||
@@ -1787,6 +1895,88 @@ void CSerialPort::writeM17Lost()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
void CSerialPort::writeDPMRHeader(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (m_modemState != STATE_DPMR && m_modemState != STATE_IDLE)
|
||||
return;
|
||||
|
||||
if (!m_dpmrEnable)
|
||||
return;
|
||||
|
||||
uint8_t reply[130U];
|
||||
|
||||
reply[0U] = MMDVM_FRAME_START;
|
||||
reply[1U] = 0U;
|
||||
reply[2U] = MMDVM_DPMR_HEADER;
|
||||
|
||||
uint8_t count = 3U;
|
||||
for (uint8_t i = 0U; i < length; i++, count++)
|
||||
reply[count] = data[i];
|
||||
|
||||
reply[1U] = count;
|
||||
|
||||
writeInt(1U, reply, count);
|
||||
}
|
||||
|
||||
void CSerialPort::writeDPMRData(const uint8_t* data, uint8_t length)
|
||||
{
|
||||
if (m_modemState != STATE_DPMR && m_modemState != STATE_IDLE)
|
||||
return;
|
||||
|
||||
if (!m_dpmrEnable)
|
||||
return;
|
||||
|
||||
uint8_t reply[130U];
|
||||
|
||||
reply[0U] = MMDVM_FRAME_START;
|
||||
reply[1U] = 0U;
|
||||
reply[2U] = MMDVM_DPMR_DATA;
|
||||
|
||||
uint8_t count = 3U;
|
||||
for (uint8_t i = 0U; i < length; i++, count++)
|
||||
reply[count] = data[i];
|
||||
|
||||
reply[1U] = count;
|
||||
|
||||
writeInt(1U, reply, count);
|
||||
}
|
||||
|
||||
void CSerialPort::writeDPMREOT()
|
||||
{
|
||||
if (m_modemState != STATE_DPMR && m_modemState != STATE_IDLE)
|
||||
return;
|
||||
|
||||
if (!m_dpmrEnable)
|
||||
return;
|
||||
|
||||
uint8_t reply[3U];
|
||||
|
||||
reply[0U] = MMDVM_FRAME_START;
|
||||
reply[1U] = 3U;
|
||||
reply[2U] = MMDVM_DPMR_EOT;
|
||||
|
||||
writeInt(1U, reply, 3);
|
||||
}
|
||||
|
||||
void CSerialPort::writeDPMRLost()
|
||||
{
|
||||
if (m_modemState != STATE_DPMR && m_modemState != STATE_IDLE)
|
||||
return;
|
||||
|
||||
if (!m_dpmrEnable)
|
||||
return;
|
||||
|
||||
uint8_t reply[3U];
|
||||
|
||||
reply[0U] = MMDVM_FRAME_START;
|
||||
reply[1U] = 3U;
|
||||
reply[2U] = MMDVM_DPMR_LOST;
|
||||
|
||||
writeInt(1U, reply, 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MODE_FM)
|
||||
void CSerialPort::writeFMData(const uint8_t* data, uint16_t length)
|
||||
{
|
||||
|
||||
+8
-1
@@ -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
|
||||
*
|
||||
* 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
|
||||
@@ -71,6 +71,13 @@ public:
|
||||
void writeM17EOT();
|
||||
#endif
|
||||
|
||||
#if defined(MODE_DPMR)
|
||||
void writeDPMRHeader(const uint8_t* header, uint8_t length);
|
||||
void writeDPMRData(const uint8_t* data, uint8_t length);
|
||||
void writeDPMRLost();
|
||||
void writeDPMREOT();
|
||||
#endif
|
||||
|
||||
#if defined(MODE_AX25)
|
||||
void writeAX25Data(const uint8_t* data, uint16_t length);
|
||||
#endif
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
|
||||
*
|
||||
* 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 "RingBuff.h"
|
||||
|
||||
#include "SerialPort.h"
|
||||
|
||||
/*
|
||||
Pin definitions (configuration in IOSTM_CMSIS.c):
|
||||
|
||||
- Host communication:
|
||||
USART1 - TXD PA9 - RXD PA10
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#if defined(STM32F1)
|
||||
|
||||
// BaudRate calculator macro
|
||||
// source: STM32 HAL Library (stm32f1xx_hal_usart.h)
|
||||
#define USART_DIV(__PCLK__, __BAUD__) (((__PCLK__)*25)/(4*(__BAUD__)))
|
||||
#define USART_DIVMANT(__PCLK__, __BAUD__) (USART_DIV((__PCLK__), (__BAUD__))/100)
|
||||
#define USART_DIVFRAQ(__PCLK__, __BAUD__) (((USART_DIV((__PCLK__), (__BAUD__)) - (USART_DIVMANT((__PCLK__), (__BAUD__)) * 100)) * 16 + 50) / 100)
|
||||
#define USART_BRR(__PCLK__, __BAUD__) ((USART_DIVMANT((__PCLK__), (__BAUD__)) << 4)|(USART_DIVFRAQ((__PCLK__), (__BAUD__)) & 0x0F))
|
||||
|
||||
#define USART_BUFFER_SIZE 256U
|
||||
DECLARE_RINGBUFFER_TYPE(USARTBuffer, USART_BUFFER_SIZE);
|
||||
|
||||
/* ************* USART1 ***************** */
|
||||
static volatile USARTBuffer_t txBuffer1={.size=USART_BUFFER_SIZE};
|
||||
static volatile USARTBuffer_t rxBuffer1={.size=USART_BUFFER_SIZE};
|
||||
|
||||
|
||||
extern "C" {
|
||||
bitband_t txe = (bitband_t)BITBAND_PERIPH(&USART1->SR, USART_SR_TXE_Pos);
|
||||
bitband_t rxne = (bitband_t)BITBAND_PERIPH(&USART1->SR, USART_SR_RXNE_Pos);
|
||||
bitband_t txeie = (bitband_t)BITBAND_PERIPH(&USART1->CR1, USART_CR1_TXEIE_Pos);
|
||||
|
||||
RAMFUNC void USART1_IRQHandler()
|
||||
{
|
||||
/* Transmitting data */
|
||||
if(*txe){
|
||||
if(!(RINGBUFF_EMPTY(txBuffer1))){
|
||||
USART1->DR = RINGBUFF_READ(txBuffer1);
|
||||
}else{ /* Buffer empty */
|
||||
*txeie = 0; /* Don't send further data */
|
||||
}
|
||||
}
|
||||
|
||||
/* Receiving data */
|
||||
if(*rxne){
|
||||
RINGBUFF_WRITE(rxBuffer1, USART1->DR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void USART1Init(int speed)
|
||||
{
|
||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||
|
||||
USART1->BRR = USART_BRR(72000000UL, speed);
|
||||
|
||||
USART1->CR1 = USART_CR1_UE | USART_CR1_TE |
|
||||
USART_CR1_RE | USART_CR1_RXNEIE; // Enable USART and RX interrupt
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
}
|
||||
|
||||
RAMFUNC void USART1TxData(const uint8_t* data, uint16_t length)
|
||||
{
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
|
||||
/* Check remaining space in buffer */
|
||||
if(RINGBUFF_COUNT(txBuffer1) + length > RINGBUFF_SIZE(txBuffer1)){
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Append data to buffer */
|
||||
while(length--){
|
||||
RINGBUFF_WRITE(txBuffer1, *(data++));
|
||||
}
|
||||
|
||||
/* Start sending data */
|
||||
USART1->CR1 |= USART_CR1_TXEIE;
|
||||
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void CSerialPort::beginInt(uint8_t n, int speed)
|
||||
{
|
||||
switch (n) {
|
||||
case 1U:
|
||||
USART1Init(speed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int CSerialPort::availableForReadInt(uint8_t n)
|
||||
{
|
||||
switch (n) {
|
||||
case 1U:
|
||||
return !RINGBUFF_EMPTY(rxBuffer1);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int CSerialPort::availableForWriteInt(uint8_t n)
|
||||
{
|
||||
switch (n) {
|
||||
case 1U:
|
||||
return !RINGBUFF_FULL(txBuffer1);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CSerialPort::readInt(uint8_t n)
|
||||
{
|
||||
switch (n) {
|
||||
case 1U:
|
||||
return RINGBUFF_READ(rxBuffer1);
|
||||
default:
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush)
|
||||
{
|
||||
bitband_t tc = (bitband_t)BITBAND_PERIPH(&USART1->SR, USART_SR_TC_Pos);
|
||||
|
||||
switch (n) {
|
||||
case 1U:
|
||||
USART1TxData(data, length);
|
||||
*tc = 0;
|
||||
|
||||
if (flush) {
|
||||
while (!RINGBUFF_EMPTY(txBuffer1) || !tc)
|
||||
;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -23,9 +23,6 @@
|
||||
#include "stm32f4xx.h"
|
||||
#elif defined(STM32F7XX)
|
||||
#include "stm32f7xx.h"
|
||||
#elif defined(STM32F105xC)
|
||||
#include "stm32f1xx.h"
|
||||
#include <cstddef>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020,2021,2022 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2020,2021,2022,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
|
||||
@@ -19,7 +19,7 @@
|
||||
#if !defined(VERSION_H)
|
||||
#define VERSION_H
|
||||
|
||||
#define VERSION "20221121"
|
||||
#define VERSION "20241003"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# mmdvmmenu.sh
|
||||
#
|
||||
# Copyright (C) 2016 by Paul Nannery KC2VRJ
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
###############################################################################
|
||||
#
|
||||
# On a Linux based system, such as a Raspberry Pi, this script will perform
|
||||
# Modification of the Config.h file for most options. It makes a Back up when
|
||||
# you start the script if none is present. You must recompile and load firmware
|
||||
# onto the Arduino Due if changes are made.
|
||||
#
|
||||
###############################################################################
|
||||
#
|
||||
# CONFIGURATION
|
||||
#
|
||||
# Location of Config.h
|
||||
conf=Config.h
|
||||
#Location of backup file
|
||||
confbak=Config.h.bak
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Do not edit below here
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
|
||||
# Check for backup file and make one if not present
|
||||
|
||||
if [ ! -f $confbak ];then
|
||||
|
||||
cp -f $conf $confbak
|
||||
|
||||
fi
|
||||
|
||||
while :
|
||||
do
|
||||
clear
|
||||
cat<<EOF
|
||||
==============================================================
|
||||
MMDVM Configuration Options
|
||||
--------------------------------------------------------------
|
||||
Please enter your choice:
|
||||
|
||||
(1) Enable 12.000 MHZ Clock
|
||||
(2) Enable 12.288 MHZ Clock
|
||||
(3) Enable 14.400 MHz Clock
|
||||
(4) Enable 19.200 MHz Clock
|
||||
(5) Use the COS to lockout the modem
|
||||
(6) Use pins to output the current mode
|
||||
(7) Use layout for the PAPA board
|
||||
(8) Use layout for ZUM V1.0 and V1.0.1 boards
|
||||
(9) Use layout for SP8NTH board
|
||||
(0) Use modem as display driver
|
||||
(A) Return to Default
|
||||
|
||||
(Q)uit
|
||||
---------------------------------------------------------------
|
||||
EOF
|
||||
read -n1 -s
|
||||
case "$REPLY" in
|
||||
"1") sed -e 's/\/\/ #define EXTERNAL_OSC 12000000/#define EXTERNAL_OSC 12000000/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "12.000 MHz clock enabled";;
|
||||
"2") sed -e 's/\/\/ #define EXTERNAL_OSC 12288000/#define EXTERNAL_OSC 12288000/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "12.288 MHz clock enabled";;
|
||||
"3") sed -e 's/\/\/ #define EXTERNAL_OSC 14400000/#define EXTERNAL_OSC 14400000/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "14.400 MHz clock enabled";;
|
||||
"4") sed -e 's/\/\/ #define EXTERNAL_OSC 19200000/#define EXTERNAL_OSC 19200000/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "19.200 MHz clock enabled";;
|
||||
"5") sed -e 's/\/\/ #define USE_COS_AS_LOCKOUT /#define USE_COS_AS_LOCKOUT/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "COS as Lockout enabled";;
|
||||
"6") sed -e 's/\/\/ #define MODE_LEDS/#define MODE_LEDS/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "Mode pins enabled";;
|
||||
"7") sed -e 's/\/\/ #define ARDUINO_DUE_PAPA/#define ARDUINO_DUE_PAPA/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "Layout for the PAPA board enabled";;
|
||||
"8") sed -e 's/\/\/ #define ARDUINO_DUE_ZUM_V10/#define ARDUINO_DUE_ZUM_V10/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "Layout for ZUM V1.0 and V1.0.1 boards enabled";;
|
||||
"9") sed -e 's/\/\/ #define ARDUINO_DUE_NTH/#define ARDUINO_DUE_NTH/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "Layout for SP8NTH board enabled";;
|
||||
"0") sed -e 's/\/\/ #define SERIAL_REPEATER/#define SERIAL_REPEATER/' $conf > $conf.tmp && mv -f $conf.tmp $conf && echo "Modem display driver enabled";;
|
||||
"A") mv -f $confbak $conf ;;
|
||||
"a") mv -f $confbak $conf ;;
|
||||
"Q") echo "If any changes are made you need to (re-)upload the firmware to MMDVM" && exit;;
|
||||
"q") echo "If any changes are made you need to (re-)upload the firmware to MMDVM" && exit;;
|
||||
* ) echo "invalid option" ;;
|
||||
esac
|
||||
sleep 1
|
||||
done
|
||||
@@ -1,187 +0,0 @@
|
||||
/* Linker script to configure memory regions.
|
||||
* STM32F105RB
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
|
||||
}
|
||||
|
||||
/* Linker script to place sections and symbol values. Should be used together
|
||||
* with other linker script that defines memory regions FLASH and RAM.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Reset_Handler : Entry of reset handler
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __copy_table_start__
|
||||
* __copy_table_end__
|
||||
* __zero_table_start__
|
||||
* __zero_table_end__
|
||||
* __etext
|
||||
* __data_start__
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __data_end__
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* end
|
||||
* __HeapLimit
|
||||
* __StackLimit
|
||||
* __StackTop
|
||||
* __stack
|
||||
*/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
|
||||
/* .ctors */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
/* .dtors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
*(.rodata*)
|
||||
|
||||
KEEP(*(.eh_frame*))
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* To copy multiple ROM to RAM sections,
|
||||
* uncomment .copy.table section and,
|
||||
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.copy.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__copy_table_start__ = .;
|
||||
LONG (__etext)
|
||||
LONG (__data_start__)
|
||||
LONG (__data_end__ - __data_start__)
|
||||
LONG (__etext2)
|
||||
LONG (__data2_start__)
|
||||
LONG (__data2_end__ - __data2_start__)
|
||||
__copy_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* To clear multiple BSS sections,
|
||||
* uncomment .zero.table section and,
|
||||
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.zero.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__zero_table_start__ = .;
|
||||
LONG (__bss_start__)
|
||||
LONG (__bss_end__ - __bss_start__)
|
||||
LONG (__bss2_start__)
|
||||
LONG (__bss2_end__ - __bss2_start__)
|
||||
__zero_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
__etext = .;
|
||||
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
*(vtable)
|
||||
*(.data*)
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(4);
|
||||
/* All data end */
|
||||
__data_end__ = .;
|
||||
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (COPY):
|
||||
{
|
||||
__end__ = .;
|
||||
PROVIDE(end = .);
|
||||
*(.heap*)
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later */
|
||||
.stack_dummy (COPY):
|
||||
{
|
||||
*(.stack*)
|
||||
} > RAM
|
||||
|
||||
/* Set stack top to end of RAM, and stack limit move down by
|
||||
* size of stack_dummy section */
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
}
|
||||
@@ -1,427 +0,0 @@
|
||||
/* File: startup_ARMCM3.S
|
||||
* Purpose: startup file for Cortex-M3 devices. Should use with
|
||||
* GCC for ARM Embedded Processors
|
||||
* Version: V2.0
|
||||
* Date: 16 August 2013
|
||||
*/
|
||||
/* Copyright (c) 2011 - 2013 ARM LIMITED
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
- Neither the name of ARM nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
*
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------*/
|
||||
#if defined(STM32F105xC)
|
||||
|
||||
.syntax unified
|
||||
.arch armv7-m
|
||||
|
||||
.section .stack
|
||||
.align 3
|
||||
#ifdef __STACK_SIZE
|
||||
.equ Stack_Size, __STACK_SIZE
|
||||
#else
|
||||
.equ Stack_Size, 0xc00
|
||||
#endif
|
||||
.globl __StackTop
|
||||
.globl __StackLimit
|
||||
__StackLimit:
|
||||
.space Stack_Size
|
||||
.size __StackLimit, . - __StackLimit
|
||||
__StackTop:
|
||||
.size __StackTop, . - __StackTop
|
||||
|
||||
.section .heap
|
||||
.align 3
|
||||
#ifdef __HEAP_SIZE
|
||||
.equ Heap_Size, __HEAP_SIZE
|
||||
#else
|
||||
.equ Heap_Size, 0
|
||||
#endif
|
||||
.globl __HeapBase
|
||||
.globl __HeapLimit
|
||||
__HeapBase:
|
||||
.if Heap_Size
|
||||
.space Heap_Size
|
||||
.endif
|
||||
.size __HeapBase, . - __HeapBase
|
||||
__HeapLimit:
|
||||
.size __HeapLimit, . - __HeapLimit
|
||||
|
||||
|
||||
.equ BootRAM, 0xF1E0F85F
|
||||
|
||||
.section .isr_vector
|
||||
.align 2
|
||||
.globl __isr_vector
|
||||
__isr_vector:
|
||||
.long __StackTop /* Top of Stack */
|
||||
.long Reset_Handler /* Reset Handler */
|
||||
.long NMI_Handler /* NMI Handler */
|
||||
.long HardFault_Handler /* Hard Fault Handler */
|
||||
.long MemManage_Handler /* MPU Fault Handler */
|
||||
.long BusFault_Handler /* Bus Fault Handler */
|
||||
.long UsageFault_Handler /* Usage Fault Handler */
|
||||
.long 0 /* Reserved */
|
||||
.long 0 /* Reserved */
|
||||
.long 0 /* Reserved */
|
||||
.long 0 /* Reserved */
|
||||
.long SVC_Handler /* SVCall Handler */
|
||||
.long DebugMon_Handler /* Debug Monitor Handler */
|
||||
.long 0 /* Reserved */
|
||||
.long PendSV_Handler /* PendSV Handler */
|
||||
.long SysTick_Handler /* SysTick Handler */
|
||||
|
||||
/* External interrupts */
|
||||
.long WWDG_IRQHandler
|
||||
.long PVD_IRQHandler
|
||||
.long TAMPER_IRQHandler
|
||||
.long RTC_IRQHandler
|
||||
.long FLASH_IRQHandler
|
||||
.long RCC_IRQHandler
|
||||
.long EXTI0_IRQHandler
|
||||
.long EXTI1_IRQHandler
|
||||
.long EXTI2_IRQHandler
|
||||
.long EXTI3_IRQHandler
|
||||
.long EXTI4_IRQHandler
|
||||
.long DMA1_Channel1_IRQHandler
|
||||
.long DMA1_Channel2_IRQHandler
|
||||
.long DMA1_Channel3_IRQHandler
|
||||
.long DMA1_Channel4_IRQHandler
|
||||
.long DMA1_Channel5_IRQHandler
|
||||
.long DMA1_Channel6_IRQHandler
|
||||
.long DMA1_Channel7_IRQHandler
|
||||
.long ADC1_2_IRQHandler
|
||||
.long CAN1_TX_IRQHandler
|
||||
.long CAN1_RX0_IRQHandler
|
||||
.long CAN1_RX1_IRQHandler
|
||||
.long CAN1_SCE_IRQHandler
|
||||
.long EXTI9_5_IRQHandler
|
||||
.long TIM1_BRK_IRQHandler
|
||||
.long TIM1_UP_IRQHandler
|
||||
.long TIM1_TRG_COM_IRQHandler
|
||||
.long TIM1_CC_IRQHandler
|
||||
.long TIM2_IRQHandler
|
||||
.long TIM3_IRQHandler
|
||||
.long TIM4_IRQHandler
|
||||
.long I2C1_EV_IRQHandler
|
||||
.long I2C1_ER_IRQHandler
|
||||
.long I2C2_EV_IRQHandler
|
||||
.long I2C2_ER_IRQHandler
|
||||
.long SPI1_IRQHandler
|
||||
.long SPI2_IRQHandler
|
||||
.long USART1_IRQHandler
|
||||
.long USART2_IRQHandler
|
||||
.long USART3_IRQHandler
|
||||
.long EXTI15_10_IRQHandler
|
||||
.long RTC_Alarm_IRQHandler
|
||||
.long OTG_FS_WKUP_IRQHandler
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long TIM5_IRQHandler
|
||||
.long SPI3_IRQHandler
|
||||
.long UART4_IRQHandler
|
||||
.long UART5_IRQHandler
|
||||
.long TIM6_IRQHandler
|
||||
.long TIM7_IRQHandler
|
||||
.long DMA2_Channel1_IRQHandler
|
||||
.long DMA2_Channel2_IRQHandler
|
||||
.long DMA2_Channel3_IRQHandler
|
||||
.long DMA2_Channel4_IRQHandler
|
||||
.long DMA2_Channel5_IRQHandler
|
||||
.long 0
|
||||
.long 0
|
||||
.long CAN2_TX_IRQHandler
|
||||
.long CAN2_RX0_IRQHandler
|
||||
.long CAN2_RX1_IRQHandler
|
||||
.long CAN2_SCE_IRQHandler
|
||||
.long OTG_FS_IRQHandler
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long BootRAM /* @0x1E0. This is for boot in RAM mode for
|
||||
STM32F10x Connectivity line Devices. */
|
||||
|
||||
.size __isr_vector, . - __isr_vector
|
||||
|
||||
.text
|
||||
.thumb
|
||||
.thumb_func
|
||||
.align 2
|
||||
.globl Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
/* Firstly it copies data from read only memory to RAM. There are two schemes
|
||||
* to copy. One can copy more than one sections. Another can only copy
|
||||
* one section. The former scheme needs more instructions and read-only
|
||||
* data to implement than the latter.
|
||||
* Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */
|
||||
|
||||
#ifdef __STARTUP_COPY_MULTIPLE
|
||||
/* Multiple sections scheme.
|
||||
*
|
||||
* Between symbol address __copy_table_start__ and __copy_table_end__,
|
||||
* there are array of triplets, each of which specify:
|
||||
* offset 0: LMA of start of a section to copy from
|
||||
* offset 4: VMA of start of a section to copy to
|
||||
* offset 8: size of the section to copy. Must be multiply of 4
|
||||
*
|
||||
* All addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r4, =__copy_table_start__
|
||||
ldr r5, =__copy_table_end__
|
||||
|
||||
.L_loop0:
|
||||
cmp r4, r5
|
||||
bge .L_loop0_done
|
||||
ldr r1, [r4]
|
||||
ldr r2, [r4, #4]
|
||||
ldr r3, [r4, #8]
|
||||
|
||||
.L_loop0_0:
|
||||
subs r3, #4
|
||||
ittt ge
|
||||
ldrge r0, [r1, r3]
|
||||
strge r0, [r2, r3]
|
||||
bge .L_loop0_0
|
||||
|
||||
adds r4, #12
|
||||
b .L_loop0
|
||||
|
||||
.L_loop0_done:
|
||||
#else
|
||||
/* Single section scheme.
|
||||
*
|
||||
* The ranges of copy from/to are specified by following symbols
|
||||
* __etext: LMA of start of the section to copy from. Usually end of text
|
||||
* __data_start__: VMA of start of the section to copy to
|
||||
* __data_end__: VMA of end of the section to copy to
|
||||
*
|
||||
* All addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r1, =__etext
|
||||
ldr r2, =__data_start__
|
||||
ldr r3, =__data_end__
|
||||
|
||||
.L_loop1:
|
||||
cmp r2, r3
|
||||
ittt lt
|
||||
ldrlt r0, [r1], #4
|
||||
strlt r0, [r2], #4
|
||||
blt .L_loop1
|
||||
#endif /*__STARTUP_COPY_MULTIPLE */
|
||||
|
||||
/* This part of work usually is done in C library startup code. Otherwise,
|
||||
* define this macro to enable it in this startup.
|
||||
*
|
||||
* There are two schemes too. One can clear multiple BSS sections. Another
|
||||
* can only clear one section. The former is more size expensive than the
|
||||
* latter.
|
||||
*
|
||||
* Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former.
|
||||
* Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later.
|
||||
*/
|
||||
#ifdef __STARTUP_CLEAR_BSS_MULTIPLE
|
||||
/* Multiple sections scheme.
|
||||
*
|
||||
* Between symbol address __copy_table_start__ and __copy_table_end__,
|
||||
* there are array of tuples specifying:
|
||||
* offset 0: Start of a BSS section
|
||||
* offset 4: Size of this BSS section. Must be multiply of 4
|
||||
*/
|
||||
ldr r3, =__zero_table_start__
|
||||
ldr r4, =__zero_table_end__
|
||||
|
||||
.L_loop2:
|
||||
cmp r3, r4
|
||||
bge .L_loop2_done
|
||||
ldr r1, [r3]
|
||||
ldr r2, [r3, #4]
|
||||
movs r0, 0
|
||||
|
||||
.L_loop2_0:
|
||||
subs r2, #4
|
||||
itt ge
|
||||
strge r0, [r1, r2]
|
||||
bge .L_loop2_0
|
||||
|
||||
adds r3, #8
|
||||
b .L_loop2
|
||||
.L_loop2_done:
|
||||
#elif defined (__STARTUP_CLEAR_BSS)
|
||||
/* Single BSS section scheme.
|
||||
*
|
||||
* The BSS section is specified by following symbols
|
||||
* __bss_start__: start of the BSS section.
|
||||
* __bss_end__: end of the BSS section.
|
||||
*
|
||||
* Both addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r1, =__bss_start__
|
||||
ldr r2, =__bss_end__
|
||||
|
||||
movs r0, 0
|
||||
.L_loop3:
|
||||
cmp r1, r2
|
||||
itt lt
|
||||
strlt r0, [r1], #4
|
||||
blt .L_loop3
|
||||
#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */
|
||||
|
||||
#ifndef __NO_SYSTEM_INIT
|
||||
bl SystemInit
|
||||
#endif
|
||||
|
||||
#ifndef __START
|
||||
#define __START _start
|
||||
#endif
|
||||
bl __START
|
||||
|
||||
.pool
|
||||
.size Reset_Handler, . - Reset_Handler
|
||||
|
||||
.align 1
|
||||
.thumb_func
|
||||
.weak Default_Handler
|
||||
.type Default_Handler, %function
|
||||
Default_Handler:
|
||||
b .
|
||||
.size Default_Handler, . - Default_Handler
|
||||
|
||||
/* Macro to define default handlers. Default handler
|
||||
* will be weak symbol and just dead loops. They can be
|
||||
* overwritten by other handlers */
|
||||
.macro def_irq_handler handler_name
|
||||
.weak \handler_name
|
||||
.set \handler_name, Default_Handler
|
||||
.endm
|
||||
|
||||
def_irq_handler NMI_Handler
|
||||
def_irq_handler HardFault_Handler
|
||||
def_irq_handler MemManage_Handler
|
||||
def_irq_handler BusFault_Handler
|
||||
def_irq_handler UsageFault_Handler
|
||||
def_irq_handler SVC_Handler
|
||||
def_irq_handler DebugMon_Handler
|
||||
def_irq_handler PendSV_Handler
|
||||
def_irq_handler SysTick_Handler
|
||||
def_irq_handler WWDG_IRQHandler
|
||||
def_irq_handler PVD_IRQHandler
|
||||
def_irq_handler TAMPER_IRQHandler
|
||||
def_irq_handler RTC_IRQHandler
|
||||
def_irq_handler FLASH_IRQHandler
|
||||
def_irq_handler RCC_IRQHandler
|
||||
def_irq_handler EXTI0_IRQHandler
|
||||
def_irq_handler EXTI1_IRQHandler
|
||||
def_irq_handler EXTI2_IRQHandler
|
||||
def_irq_handler EXTI3_IRQHandler
|
||||
def_irq_handler EXTI4_IRQHandler
|
||||
def_irq_handler DMA1_Channel1_IRQHandler
|
||||
def_irq_handler DMA1_Channel2_IRQHandler
|
||||
def_irq_handler DMA1_Channel3_IRQHandler
|
||||
def_irq_handler DMA1_Channel4_IRQHandler
|
||||
def_irq_handler DMA1_Channel5_IRQHandler
|
||||
def_irq_handler DMA1_Channel6_IRQHandler
|
||||
def_irq_handler DMA1_Channel7_IRQHandler
|
||||
def_irq_handler ADC1_2_IRQHandler
|
||||
def_irq_handler CAN1_TX_IRQHandler
|
||||
def_irq_handler CAN1_RX0_IRQHandler
|
||||
def_irq_handler CAN1_RX1_IRQHandler
|
||||
def_irq_handler CAN1_SCE_IRQHandler
|
||||
def_irq_handler EXTI9_5_IRQHandler
|
||||
def_irq_handler TIM1_BRK_IRQHandler
|
||||
def_irq_handler TIM1_UP_IRQHandler
|
||||
def_irq_handler TIM1_TRG_COM_IRQHandler
|
||||
def_irq_handler TIM1_CC_IRQHandler
|
||||
def_irq_handler TIM2_IRQHandler
|
||||
def_irq_handler TIM3_IRQHandler
|
||||
def_irq_handler TIM4_IRQHandler
|
||||
def_irq_handler I2C1_EV_IRQHandler
|
||||
def_irq_handler I2C1_ER_IRQHandler
|
||||
def_irq_handler I2C2_EV_IRQHandler
|
||||
def_irq_handler I2C2_ER_IRQHandler
|
||||
def_irq_handler SPI1_IRQHandler
|
||||
def_irq_handler SPI2_IRQHandler
|
||||
def_irq_handler USART1_IRQHandler
|
||||
def_irq_handler USART2_IRQHandler
|
||||
def_irq_handler USART3_IRQHandler
|
||||
def_irq_handler EXTI15_10_IRQHandler
|
||||
def_irq_handler RTC_Alarm_IRQHandler
|
||||
def_irq_handler OTG_FS_WKUP_IRQHandler
|
||||
def_irq_handler TIM5_IRQHandler
|
||||
def_irq_handler SPI3_IRQHandler
|
||||
def_irq_handler UART4_IRQHandler
|
||||
def_irq_handler UART5_IRQHandler
|
||||
def_irq_handler TIM6_IRQHandler
|
||||
def_irq_handler TIM7_IRQHandler
|
||||
def_irq_handler DMA2_Channel1_IRQHandler
|
||||
def_irq_handler DMA2_Channel2_IRQHandler
|
||||
def_irq_handler DMA2_Channel3_IRQHandler
|
||||
def_irq_handler DMA2_Channel4_IRQHandler
|
||||
def_irq_handler DMA2_Channel5_IRQHandler
|
||||
def_irq_handler CAN2_TX_IRQHandler
|
||||
def_irq_handler CAN2_RX0_IRQHandler
|
||||
def_irq_handler CAN2_RX1_IRQHandler
|
||||
def_irq_handler CAN2_SCE_IRQHandler
|
||||
def_irq_handler OTG_FS_IRQHandler
|
||||
|
||||
.end
|
||||
|
||||
#endif
|
||||
@@ -1,227 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f1xx.c
|
||||
* @author MCD Application Team, Wojciech Krutnik
|
||||
* @version V2.2.2
|
||||
* @date 26-June-2015
|
||||
* @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
|
||||
*
|
||||
* 1. This file provides two functions and one global variable to be called from
|
||||
* user application:
|
||||
* - SystemInit(): This function is called at startup just after reset and
|
||||
* before branch to main program. This call is made inside
|
||||
* the "startup_stm32f1xx.s" file.
|
||||
*
|
||||
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
|
||||
* by the user application to setup the SysTick
|
||||
* timer or configure other parameters.
|
||||
*
|
||||
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
|
||||
* be called whenever the core clock is changed
|
||||
* during program execution.
|
||||
*
|
||||
* 2. After each device reset the HSI (8 MHz) is used as system clock source.
|
||||
* Then SystemInit() function is called, in "startup_stm32f1xx.s" file, to
|
||||
* configure the system clock before to branch to main program.
|
||||
*
|
||||
* 3. This file configures the system clock and flash as follows:
|
||||
*=============================================================================
|
||||
* Supported STM32F1xx device
|
||||
*-----------------------------------------------------------------------------
|
||||
* System Clock source | PLL
|
||||
*-----------------------------------------------------------------------------
|
||||
* SYSCLK | 72MHz
|
||||
*-----------------------------------------------------------------------------
|
||||
* HCLK | 72Mhz
|
||||
*-----------------------------------------------------------------------------
|
||||
* PCLK1 | 36MHz
|
||||
*-----------------------------------------------------------------------------
|
||||
* PCLK2 | 72MHz
|
||||
*-----------------------------------------------------------------------------
|
||||
* AHB Prescaler | 1
|
||||
*-----------------------------------------------------------------------------
|
||||
* APB1 Prescaler | 2
|
||||
*-----------------------------------------------------------------------------
|
||||
* APB2 Prescaler | 1
|
||||
*-----------------------------------------------------------------------------
|
||||
* PLLSRC | HSE/1
|
||||
*-----------------------------------------------------------------------------
|
||||
* PLLMUL | 9
|
||||
*-----------------------------------------------------------------------------
|
||||
* HSE | 8MHz
|
||||
*-----------------------------------------------------------------------------
|
||||
* Flash Latency(WS) | 2
|
||||
*-----------------------------------------------------------------------------
|
||||
* Prefetch Buffer | ON
|
||||
*-----------------------------------------------------------------------------
|
||||
*=============================================================================
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#if defined(STM32F105xC)
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f1xx_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "stm32f1xx.h"
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz.
|
||||
This value can be provided and adapted by the user application. */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz.
|
||||
This value can be provided and adapted by the user application. */
|
||||
#endif /* HSI_VALUE */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32f1xx_System_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
|
||||
uint32_t SystemCoreClock = 48000000;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
static void SetSysClock(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Setup the microcontroller system.
|
||||
* Initialize the default HSI clock source, vector table location and the PLL configuration is reset.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* Enable Prefetch Buffer, 2 wait states */
|
||||
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1;
|
||||
|
||||
/* Configure the System clock frequency, AHB/APBx prescalers */
|
||||
SetSysClock();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configures the System clock frequency and AHB/APBx prescalers
|
||||
* settings.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void SetSysClock(void)
|
||||
{
|
||||
/* Enable HSE and Clock Security System */
|
||||
RCC->CR |= RCC_CR_CSSON | RCC_CR_HSEON;
|
||||
/* Wait for HSE startup */
|
||||
while((RCC->CR & RCC_CR_HSERDY) == 0)
|
||||
;
|
||||
|
||||
/* Enable PLL with 9x multiplier and HSE clock source
|
||||
* APB1 prescaler /2 */
|
||||
RCC->CFGR = (RCC->CFGR & (~RCC_CFGR_PLLMULL)) | RCC_CFGR_PLLMULL9
|
||||
| RCC_CFGR_PLLSRC;
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
while((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_HPRE) | RCC_CFGR_HPRE_DIV1;
|
||||
/* PCLK1 = HCLK/2; PCLK2 = HCLK */
|
||||
RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PPRE1|RCC_CFGR_PPRE2))
|
||||
| RCC_CFGR_PPRE1_DIV2;
|
||||
|
||||
/* Switch SYSCLK to PLL */
|
||||
RCC->CFGR |= RCC_CFGR_SW_PLL;
|
||||
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
Reference in New Issue
Block a user