Compare commits

..
54 Commits
Author SHA1 Message Date
Jonathan Naylor 15227d9cec Merge branch 'master' into mqtt 2024-10-02 16:10:09 +01:00
Jonathan Naylor c3246dbcb7 Merge branch 'master' of https://github.com/g4klx/MMDVM 2024-10-02 16:05:48 +01:00
Jonathan Naylor 65c51bf849 Merge branch 'master' into mqtt 2024-08-01 12:55:06 +01:00
Jonathan Naylor edd60caad3 Remove the deprecated register keyword. 2024-07-31 19:25:59 +01:00
Jonathan Naylor b8a0f7b1cf Merge pull request #343 from mytechguyri/master
Added option to configure Serial Repeater baud rate
2024-03-10 18:28:44 +00:00
John Tetreault 28e564738e Added option to configure Serial Repeater baud rate so end user can set to 115,200 for high speed Nextion display 2024-03-10 14:19:21 -04:00
Jonathan Naylor a7fddc37e1 Don't send a status when the FM repeater is reset, it causes a loop. 2023-11-18 16:45:36 +00:00
Jonathan Naylor a8bf99037e Merge branch 'master' into mqtt 2023-11-09 19:13:12 +00:00
Jonathan Naylor 029e6df4b9 Remove support for STM32F1* boards, they're just too slow. 2023-11-09 19:08:15 +00:00
Jonathan Naylor 85d3086d4c Restart the RSSI ADC conversion in the STM32 interrupt to match the signal ADC. 2023-10-10 20:06:50 +01:00
Jonathan Naylor ccf3b7301e Make the type correct for silence frames. 2023-10-10 20:03:01 +01:00
Jonathan Naylor 6b3a811ae7 Simplify the serial repeater code. 2023-10-05 19:49:17 +01:00
Jonathan Naylor 508018c89c Add the MMDVM serial protocol document from December 2015. 2023-09-22 16:51:03 +01:00
Jonathan Naylor 3e079f58ad Add RSSI reporting to FM and AX.25 2023-08-02 17:34:52 +01:00
Jonathan Naylor 7ef0d992d9 Improve the status reporting for FM mode. 2023-01-18 14:30:02 +00:00
Jonathan Naylor bf23a94038 Merge pull request #334 from n0mjs710/master 2023-01-09 15:17:17 +00:00
Cort Buffington b2755864ef Adding support for WA0EDA STM32-DVM-MTR2K v2.0d with FM LED, and a (commented) line to compile for 500000 serial port speed to support the WA0EDA MODEMs and others that use Armbian + AllWinner H2/H3 SOC that does not support 4600800. 2023-01-09 07:06:42 -06:00
Jonathan Naylor 7276ca3929 Update Version.h 2022-11-21 19:14:24 +00:00
Jonathan Naylor d14b9dede3 Update Version.h 2022-11-21 19:14:14 +00:00
Jonathan Naylor de87d77ad6 Merge pull request #330 from spongegovo/pocsagax25_fix
Fixed Serial protocol issue where MMDVMHost could not send POCSAG or AX25 to the MMDVM
2022-11-21 19:13:21 +00:00
spongegovo 2626ad5580 Update SerialPort.cpp 2022-11-20 09:15:59 +11:00
Jonathan Naylor 031b078e76 Merge pull request #327 from shawnchain/fix_ax25_dac_overflow_error 2022-09-13 14:09:12 +01:00
Shawn Chain 5d987969a9 The AX25 sine value ranges from 0-4095, and inside io.write() will perform the calculation (value * q15_t(txLevel) >> 15) which may exceed 4096 and cause the DAC Overflow error 2022-09-13 20:18:03 +08:00
Jonathan Naylor f898390956 Bump the version date. 2021-12-20 23:00:13 +00:00
Jonathan Naylor f8d1cc7aed Fix crash on long data frames. 2021-12-20 22:57:40 +00:00
Jonathan Naylor cf9fa93cb9 Include the ARM copyright in the README file. 2021-12-18 22:38:26 +00:00
Jonathan Naylor 69adaf2ebb Update SerialTeensy.cpp 2021-12-18 22:34:24 +00:00
Jonathan Naylor 7f4ae790ba Update STM32Utils.h 2021-12-18 22:31:48 +00:00
Jonathan Naylor 416fc8fc8b Update the README. 2021-12-13 10:31:10 +00:00
Jonathan Naylor 5b79356ddb Merge pull request #324 from 1tilen/master
Added PB15 to comment with pins, changed STM32F4 to STM32F7 in line 23
2021-11-14 19:51:29 +00:00
Tilen 26fc87aca6 Added PB15 to comment with pins, changed STM32F4 to STM32F7 in line 23 2021-11-14 19:21:35 +01:00
Jonathan Naylor 54745130c2 Add the transmit function. 2021-10-27 21:28:43 +01:00
Jonathan Naylor f65d52bf2f Add M17 calibration mode. 2021-10-27 19:37:58 +01:00
Jonathan Naylor 5800b33f21 Split the DMR and YSF filtering 2021-10-26 20:51:21 +01:00
Jonathan Naylor 105dba2c27 Merge branch 'master' of github.com:g4klx/MMDVM 2021-10-26 17:43:51 +01:00
Jonathan Naylor 777cc9f2ea Fix typo 2021-10-26 17:43:34 +01:00
Jonathan Naylor e879b4615a Merge branch 'master' of https://github.com/g4klx/MMDVM 2021-10-25 20:03:36 +01:00
Jonathan Naylor 8d69fc59be Update the README file 2021-10-25 20:03:17 +01:00
Jonathan Naylor 2f4e9cc269 Remove unused configuration option 2021-10-25 19:47:31 +01:00
Jonathan Naylor ee07f76bd5 Split the repeater and link mode audio paths. 2021-09-30 18:16:51 +01:00
Jonathan Naylor d063a1da1e Change the EOT handling on TX. 2021-09-19 14:25:12 +01:00
Jonathan Naylor 6a4dad4c44 Change the LinkMode state machine. 2021-09-06 22:50:40 +01:00
Jonathan Naylor ed6bd66fab Rename SimpleMode to LinkMode. 2021-09-06 21:53:01 +01:00
Jonathan Naylor 1a07a6f0d1 Add more details to the simple FM state machine. 2021-09-05 19:46:01 +01:00
Jonathan Naylor 70bf47f93e Add a bery simple FM mode for internet gatewaying. 2021-09-05 19:06:56 +01:00
Jonathan Naylor a5eaafc7e0 Change a method name. 2021-08-26 17:39:52 +01:00
Jonathan Naylor 2200945857 Change the EOF sync pattern for simplicity. 2021-08-26 16:50:18 +01:00
Jonathan Naylor 63a8e61a45 Update to send and receive the new EOF marker. 2021-08-25 21:11:09 +01:00
Jonathan Naylor 7275f65e44 Reset the transmit levels to be correct. 2021-08-23 21:07:17 +01:00
Jonathan Naylor 2aabdb61ab Remove the last traces of M17 packet mode and fix a buffer overrun bug. 2021-08-08 18:55:09 +01:00
Jonathan Naylor 96c0e5b141 Fix compiler warnings when building for POG style boards. 2021-07-19 21:20:57 +01:00
Jonathan Naylor 9c883cfafd Revert "Restore SerialRB for POG builds."
This reverts commit 8a1ab88c3a.
2021-07-01 22:58:59 +01:00
Jonathan Naylor 8a1ab88c3a Restore SerialRB for POG builds. 2021-07-01 22:28:59 +01:00
Jonathan Naylor f4e1c0b401 Fix a potential issue with reporting the wrong command type in ACK and NAK messages. 2021-06-17 16:55:59 +01:00
48 changed files with 864 additions and 2979 deletions
+1 -4
View File
@@ -1,9 +1,6 @@
[submodule "STM32F4XX_Lib"]
path = STM32F4XX_Lib
url = https://github.com/juribeparada/STM32F4XX_Lib.git
[submodule "STM32F10X_Lib"]
path = STM32F10X_Lib
url = https://github.com/shawnchain/STM32F10X_Lib.git
[submodule "STM32F7XX_Lib"]
path = STM32F7XX_Lib
url = https://github.com/g4klx/STM32F7XX_Lib.git
url = https://github.com/juribeparada/STM32F7XX_Lib.git
+24 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
* Copyright 2015-2019 Mobilinkd LLC <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
@@ -85,7 +85,9 @@ m_hdlcOnes(0U),
m_hdlcFlag(false),
m_hdlcBuffer(0U),
m_hdlcBits(0U),
m_hdlcState(AX25_IDLE)
m_hdlcState(AX25_IDLE),
m_rssiAccum(0U),
m_rssiCount(0U)
{
m_delayLine = new bool[DELAY_LEN];
@@ -101,7 +103,7 @@ m_hdlcState(AX25_IDLE)
m_iirHistory[i] = 0.0F;
}
bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame)
bool CAX25Demodulator::process(q15_t* samples, const uint16_t* rssi, uint8_t length, CAX25Frame& frame)
{
bool result = false;
@@ -119,6 +121,9 @@ bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
for (uint8_t i = 0; i < length; i++) {
m_rssiAccum += rssi[i];
m_rssiCount++;
bool bit = fc[i] >= 0;
bool sample = PLL(bit);
@@ -266,6 +271,8 @@ bool CAX25Demodulator::HDLC(bool b)
// Start of frame data.
m_hdlcState = AX25_RECEIVE;
m_frame.append(m_hdlcBuffer);
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_hdlcBits = 0U;
}
break;
@@ -315,5 +322,19 @@ float32_t CAX25Demodulator::iir(float32_t input)
return result;
}
uint16_t CAX25Demodulator::getRSSI()
{
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
m_rssiAccum = 0U;
m_rssiCount = 0U;
return rssi;
}
return 0U;
}
#endif
+6 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 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
@@ -36,12 +36,14 @@ class CAX25Demodulator {
public:
CAX25Demodulator(int8_t n);
bool process(q15_t* samples, uint8_t length, CAX25Frame& frame);
bool process(q15_t* samples, const uint16_t* rssi, uint8_t length, CAX25Frame& frame);
void setTwist(int8_t n);
bool isDCD();
uint16_t getRSSI();
private:
CAX25Frame m_frame;
CAX25Twist m_twist;
@@ -63,6 +65,8 @@ private:
uint16_t m_hdlcBuffer;
uint16_t m_hdlcBits;
AX25_STATE m_hdlcState;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
bool delay(bool b);
bool NRZI(bool b);
+29 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 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
@@ -86,7 +86,7 @@ m_c(0xF6U)
initRand();
}
void CAX25RX::samples(q15_t* samples, uint8_t length)
void CAX25RX::samples(q15_t* samples, const uint16_t* rssi, uint8_t length)
{
q15_t output[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
@@ -95,32 +95,56 @@ void CAX25RX::samples(q15_t* samples, uint8_t length)
CAX25Frame frame;
bool ret = m_demod1.process(output, length, frame);
bool ret = m_demod1.process(output, rssi, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
#if defined(SEND_RSSI_DATA)
uint16_t rssi = m_demod1.getRSSI();
if (rssi > 0U)
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#endif
}
DEBUG1("Decoder 1 reported");
}
ret = m_demod2.process(output, length, frame);
ret = m_demod2.process(output, rssi, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
#if defined(SEND_RSSI_DATA)
uint16_t rssi = m_demod2.getRSSI();
if (rssi > 0U)
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#endif
}
DEBUG1("Decoder 2 reported");
}
ret = m_demod3.process(output, length, frame);
ret = m_demod3.process(output, rssi, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
#if defined(SEND_RSSI_DATA)
uint16_t rssi = m_demod3.getRSSI();
if (rssi > 0U)
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#endif
}
DEBUG1("Decoder 3 reported");
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 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
@@ -29,7 +29,7 @@ class CAX25RX {
public:
CAX25RX();
void samples(q15_t* samples, uint8_t length);
void samples(q15_t* samples, const uint16_t* rssi, uint8_t length);
void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist);
+1 -1
View File
@@ -160,7 +160,7 @@ void CAX25TX::writeBit(bool b)
m_tablePtr += 11U;
}
buffer[i] = value;
buffer[i] = value >> 1;
if (m_tablePtr >= AUDIO_TABLE_LEN)
m_tablePtr -= AUDIO_TABLE_LEN;
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2009-2015,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#include "Globals.h"
#include "CalM17.h"
#include "M17Defines.h"
const uint8_t PREAMBLE[] = {0x00U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U};
CCalM17::CCalM17() :
m_transmit(false)
{
}
void CCalM17::process()
{
m17TX.process();
if (!m_transmit)
return;
uint16_t space = m17TX.getSpace();
if (space < 2U)
return;
m17TX.writeData(PREAMBLE, M17_FRAME_LENGTH_BYTES + 1U);
}
uint8_t CCalM17::write(const uint8_t* data, uint16_t length)
{
if (length != 1U)
return 4U;
m_transmit = data[0U] == 1U;
return 0U;
}
#endif
+10 -19
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2015,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,32 +19,22 @@
#include "Config.h"
#if defined(MODE_OLED)
#if defined(MODE_M17)
#if !defined(I2C3_H)
#define I2C3_H
#if defined(STM32F7XX)
#include "stm32f7xx.h"
#include "stm32f7xx_i2c.h"
#endif
#if !defined(CALM17_H)
#define CALM17_H
class CI2C3 {
class CCalM17 {
public:
CI2C3();
CCalM17();
void init();
void process();
void write(uint16_t addr, const uint8_t* data, uint8_t length);
uint8_t write(const uint8_t* data, uint16_t length);
private:
void transferConfig(uint16_t addr, uint8_t length, uint32_t mode, uint32_t request);
void configAnalogFilter(uint32_t AnalogFilter);
void configDigitalFilter(uint32_t DigitalFilter);
void initI2C3();
void initMSP();
void initGPIO(GPIO_TypeDef* GPIOx, uint32_t Pin);
bool m_transmit;
};
#endif
+18 -26
View File
@@ -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
@@ -58,7 +58,7 @@
// Frequencies such as 10.0 Mhz (48000 * 208.333) or 20 Mhz (48000 * 416.666) are not suitable.
//
// For 12 MHz
// #define EXTERNAL_OSC 12000000
#define EXTERNAL_OSC 12000000
// For 12.288 MHz
// #define EXTERNAL_OSC 12288000
// For 14.4 MHz
@@ -66,30 +66,20 @@
// For 19.2 MHz
// #define EXTERNAL_OSC 19200000
// Use a higher baudrate for host communication. Required for FM network !
// #define SERIAL_SPEED 115200 //suitable for most older boards (Arduino, Due STM32F1_POG etc). External FM will NOT work with this !
// #define SERIAL_SPEED 230400 // Only works on newer board M4, M7, Teensy. External FM might work with this
#define SERIAL_SPEED 460800 // Only works on newer board M4, M7, Teensy. External FM should work with this
// Allow the use of the COS line to lockout the modem
// #define USE_COS_AS_LOCKOUT
// 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, 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
// Use pins to output the current mode via LEDs
// #define MODE_LEDS
// Use an OLED to show the current mode via a small screen (64x32) on I2C3
#define MODE_OLED
#define MODE_LEDS
// 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
@@ -108,7 +98,13 @@
#define SEND_RSSI_DATA
// Use the modem as a serial repeater for Nextion displays
// #define SERIAL_REPEATER
#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
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
#define USE_DCBLOCKER
@@ -121,17 +117,13 @@
// #define USE_ALTERNATE_NXDN_LEDS
// Use the D-Star and P25 LEDs for M17
// #define USE_ALTERNATE_M17_LEDS
#define USE_ALTERNATE_M17_LEDS
// Use the D-Star and DMR LEDs for POCSAG
// #define USE_ALTERNATE_POCSAG_LEDS
#define USE_ALTERNATE_POCSAG_LEDS
// Use the D-Star and YSF LEDs for FM
// #define USE_ALTERNATE_FM_LEDS
#if defined(MODE_OLED)
#undef MODE_LEDS
#endif
#define USE_ALTERNATE_FM_LEDS
#endif
+289 -39
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2021,2023 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
@@ -28,13 +28,19 @@ const uint16_t FM_SERIAL_BLOCK_SIZE = 80U;//this is the number of sample pairs t
//three times this value shall never exceed 252
const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U;
/*
* Access Mode values are:
* 0 - Carrier access with COS
* 1 - CTCSS only access without COS
* 2 - CTCSS only access with COS
* 3 - CTCSS only access with COS to start, then carrier access with COS
*/
const uint8_t FS_LISTENING = 0U;
const uint8_t FS_KERCHUNK_RF = 1U;
const uint8_t FS_RELAYING_RF = 2U;
const uint8_t FS_RELAYING_WAIT_RF = 3U;
const uint8_t FS_TIMEOUT_RF = 4U;
const uint8_t FS_TIMEOUT_WAIT_RF = 5U;
const uint8_t FS_KERCHUNK_EXT = 6U;
const uint8_t FS_RELAYING_EXT = 7U;
const uint8_t FS_RELAYING_WAIT_EXT = 8U;
const uint8_t FS_TIMEOUT_EXT = 9U;
const uint8_t FS_TIMEOUT_WAIT_EXT = 10U;
const uint8_t FS_HANG = 11U;
CFM::CFM() :
m_callsign(),
@@ -55,7 +61,6 @@ m_kerchunkTimer(),
m_ackMinTimer(),
m_ackDelayTimer(),
m_hangTimer(),
m_statusTimer(),
m_reverseTimer(),
m_needReverse(false),
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
@@ -63,6 +68,7 @@ m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
m_blanking(),
m_accessMode(1U),
m_linkMode(false),
m_cosInvert(false),
m_noiseSquelch(false),
m_rfAudioBoost(1U),
@@ -72,15 +78,26 @@ m_extEnabled(false),
m_rxLevel(1),
m_inputRFRB(2401U), // 100ms of audio + 1 sample
m_outputRFRB(2400U), // 100ms of audio
m_inputExtRB()
m_inputExtRB(),
m_rfSignal(false),
m_extSignal(false),
m_rssiAccum(0U),
m_rssiCount(0U)
{
m_statusTimer.setTimeout(1U, 0U);
m_reverseTimer.setTimeout(0U, 150U);
insertDelay(100U);
}
void CFM::samples(bool cos, q15_t* samples, uint8_t length)
void CFM::samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length)
{
if (m_linkMode)
linkSamples(cos, samples, length);
else
repeaterSamples(cos, samples, rssi, length);
}
void CFM::repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length)
{
if (m_cosInvert)
cos = !cos;
@@ -89,6 +106,11 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
uint8_t i = 0U;
for (; i < length; i++) {
if (m_state == FS_RELAYING_RF) {
m_rssiAccum += rssi[i];
m_rssiCount++;
}
// ARMv7-M has hardware integer division
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
@@ -219,6 +241,108 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
}
}
void CFM::linkSamples(bool cos, q15_t* samples, uint8_t length)
{
if (m_cosInvert)
cos = !cos;
clock(length);
uint8_t i = 0U;
for (; i < length; i++) {
// ARMv7-M has hardware integer division
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
if (m_noiseSquelch)
cos = m_squelch.process(currentRFSample);
q15_t currentExtSample;
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
inputExt = inputExt && m_extEnabled;
switch (m_accessMode) {
case 0U:
if (!inputExt && !cos && m_modemState != STATE_FM)
continue;
else
stateMachine(cos, inputExt);
break;
case 1U: {
bool ctcss = m_ctcssRX.process(currentRFSample);
// Delay the audio by 100ms to better match the CTCSS detector output
m_inputRFRB.put(currentRFSample);
m_inputRFRB.get(currentRFSample);
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
// No CTCSS detected, just carry on
continue;
} else if ((inputExt || ctcss) && m_modemState != STATE_FM) {
// We had CTCSS or external input
stateMachine(ctcss, inputExt);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(ctcss, inputExt);
}
}
break;
case 2U: {
bool ctcss = m_ctcssRX.process(currentRFSample);
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
// No CTCSS detected, just carry on
continue;
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
// We had CTCSS or external input
stateMachine(ctcss && cos, inputExt);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(ctcss && cos, inputExt);
}
}
break;
default: {
bool ctcss = m_ctcssRX.process(currentRFSample);
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
// No CTCSS detected, just carry on
continue;
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
// We had CTCSS or external input
stateMachine(ctcss && cos, inputExt);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(cos, inputExt);
}
}
break;
}
if (m_modemState != STATE_FM)
continue;
if (m_rfSignal && m_extEnabled) {
q15_t currentSample = m_blanking.process(currentRFSample);
m_downSampler.addSample(currentSample);
}
if (!m_extSignal)
continue;
q15_t currentSample = currentExtSample * m_extAudioBoost;
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
m_outputRFRB.put(currentSample);
}
}
void CFM::process()
{
uint16_t space = io.getSpace();
@@ -271,7 +395,6 @@ void CFM::reset()
m_ackMinTimer.stop();
m_ackDelayTimer.stop();
m_hangTimer.stop();
m_statusTimer.stop();
m_reverseTimer.stop();
m_ctcssRX.reset();
@@ -287,6 +410,8 @@ void CFM::reset()
m_squelch.reset();
m_needReverse = false;
m_rfSignal = false;
m_extSignal = false;
}
uint8_t CFM::setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch)
@@ -317,9 +442,10 @@ uint8_t CFM::setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_
return m_rfAck.setParams(rfAck, speed, frequency, level, level);
}
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
{
m_accessMode = accessMode;
m_linkMode = linkMode;
m_cosInvert = cosInvert;
m_noiseSquelch = noiseSquelch;
@@ -356,10 +482,14 @@ uint8_t CFM::setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t
void CFM::stateMachine(bool validRFSignal, bool validExtSignal)
{
if (m_duplex)
duplexStateMachine(validRFSignal, validExtSignal);
else
simplexStateMachine(validRFSignal, validExtSignal);
if (m_linkMode) {
linkStateMachine(validRFSignal, validExtSignal);
} else {
if (m_duplex)
duplexStateMachine(validRFSignal, validExtSignal);
else
simplexStateMachine(validRFSignal, validExtSignal);
}
}
void CFM::simplexStateMachine(bool validRFSignal, bool validExtSignal)
@@ -470,13 +600,7 @@ void CFM::clock(uint8_t length)
m_ackMinTimer.clock(length);
m_ackDelayTimer.clock(length);
m_hangTimer.clock(length);
m_statusTimer.clock(length);
m_reverseTimer.clock(length);
if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) {
serial.writeFMStatus(m_state);
m_statusTimer.start();
}
}
void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
@@ -485,12 +609,19 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
if (m_kerchunkTimer.getTimeout() > 0U) {
DEBUG1("State to KERCHUNK_RF");
m_state = FS_KERCHUNK_RF;
serial.writeFMStatus(m_state);
m_kerchunkTimer.start();
if (m_callsignAtStart && !m_callsignAtLatch)
sendCallsign();
} else {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
if (m_callsignAtStart)
sendCallsign();
}
@@ -505,20 +636,21 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
io.setDecode(true);
io.setADCDetection(true);
m_statusTimer.start();
serial.writeFMStatus(m_state);
}
} else if (validExtSignal) {
if (m_kerchunkTimer.getTimeout() > 0U) {
DEBUG1("State to KERCHUNK_EXT");
m_state = FS_KERCHUNK_EXT;
serial.writeFMStatus(m_state);
m_kerchunkTimer.start();
if (m_callsignAtStart && !m_callsignAtLatch)
sendCallsign();
} else {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
if (m_callsignAtStart)
sendCallsign();
}
@@ -530,9 +662,6 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
m_callsignTimer.start();
m_reverseTimer.stop();
m_statusTimer.start();
serial.writeFMStatus(m_state);
}
}
}
@@ -542,26 +671,22 @@ void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal)
if (validRFSignal) {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
io.setDecode(true);
io.setADCDetection(true);
m_timeoutTimer.start();
m_reverseTimer.stop();
m_statusTimer.start();
serial.writeFMStatus(m_state);
} else if (validExtSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
insertSilence(50U);
m_timeoutTimer.start();
m_reverseTimer.stop();
m_statusTimer.start();
serial.writeFMStatus(m_state);
}
}
@@ -571,6 +696,11 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
if (m_kerchunkTimer.hasExpired()) {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_kerchunkTimer.stop();
if (m_callsignAtStart && m_callsignAtLatch) {
sendCallsign();
@@ -583,11 +713,12 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_kerchunkTimer.stop();
m_timeoutTimer.stop();
m_ackMinTimer.stop();
m_callsignTimer.stop();
m_statusTimer.stop();
m_needReverse = true;
if (m_extEnabled)
serial.writeFMEOT();
@@ -597,9 +728,21 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
void CFM::relayingRFStateDuplex(bool validSignal)
{
if (validSignal) {
#if defined(SEND_RSSI_DATA)
if (m_rssiCount >= 24000U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
serial.writeFMRSSI(rssi);
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
#endif
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_ackMinTimer.stop();
m_timeoutTimer.stop();
m_timeoutTone.start();
@@ -613,6 +756,8 @@ void CFM::relayingRFStateDuplex(bool validSignal)
DEBUG1("State to RELAYING_WAIT_RF");
m_state = FS_RELAYING_WAIT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
if (m_extEnabled)
@@ -631,6 +776,7 @@ void CFM::relayingRFStateSimplex(bool validSignal)
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_timeoutTimer.stop();
@@ -643,6 +789,8 @@ void CFM::relayingRFStateSimplex(bool validSignal)
DEBUG1("State to RELAYING_WAIT_RF");
m_state = FS_RELAYING_WAIT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
if (m_extEnabled)
@@ -658,11 +806,17 @@ void CFM::relayingRFWaitStateDuplex(bool validSignal)
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
if (m_ackMinTimer.isRunning()) {
if (m_ackMinTimer.hasExpired()) {
@@ -696,11 +850,15 @@ void CFM::relayingRFWaitStateSimplex(bool validSignal)
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
}
@@ -713,6 +871,8 @@ void CFM::kerchunkExtStateDuplex(bool validSignal)
if (m_kerchunkTimer.hasExpired()) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
m_kerchunkTimer.stop();
if (m_callsignAtStart && m_callsignAtLatch) {
sendCallsign();
@@ -722,11 +882,12 @@ void CFM::kerchunkExtStateDuplex(bool validSignal)
} else {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_kerchunkTimer.stop();
m_timeoutTimer.stop();
m_ackMinTimer.stop();
m_callsignTimer.stop();
m_statusTimer.stop();
m_needReverse = true;
}
}
@@ -737,6 +898,8 @@ void CFM::relayingExtStateDuplex(bool validSignal)
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_ackMinTimer.stop();
m_timeoutTimer.stop();
m_timeoutTone.start();
@@ -744,6 +907,7 @@ void CFM::relayingExtStateDuplex(bool validSignal)
} else {
DEBUG1("State to RELAYING_WAIT_EXT");
m_state = FS_RELAYING_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
@@ -759,12 +923,14 @@ void CFM::relayingExtStateSimplex(bool validSignal)
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_timeoutTimer.stop();
}
} else {
DEBUG1("State to RELAYING_WAIT_EXT");
m_state = FS_RELAYING_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
}
@@ -774,11 +940,13 @@ void CFM::relayingExtWaitStateDuplex(bool validSignal)
if (validSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
if (m_ackMinTimer.isRunning()) {
if (m_ackMinTimer.hasExpired()) {
@@ -809,11 +977,14 @@ void CFM::relayingExtWaitStateSimplex(bool validSignal)
if (validSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
m_needReverse = true;
@@ -829,6 +1000,11 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
DEBUG1("Stop ack");
m_rfAck.stop();
m_extAck.stop();
@@ -836,6 +1012,8 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
} else if (validExtSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
DEBUG1("Stop ack");
m_rfAck.stop();
m_extAck.stop();
@@ -844,8 +1022,9 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_hangTimer.stop();
m_statusTimer.stop();
if (m_callsignAtEnd)
sendCallsign();
@@ -869,6 +1048,7 @@ void CFM::timeoutRFStateDuplex(bool validSignal)
DEBUG1("State to TIMEOUT_WAIT_RF");
m_state = FS_TIMEOUT_WAIT_RF;
serial.writeFMStatus(m_state);
if (m_callsignAtEnd)
sendCallsign();
@@ -890,6 +1070,7 @@ void CFM::timeoutRFStateSimplex(bool validSignal)
DEBUG1("State to TIMEOUT_WAIT_RF");
m_state = FS_TIMEOUT_WAIT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
@@ -903,11 +1084,14 @@ void CFM::timeoutRFWaitStateDuplex(bool validSignal)
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
m_timeoutTone.stop();
DEBUG1("Send RF ack");
m_rfAck.start();
@@ -932,11 +1116,14 @@ void CFM::timeoutRFWaitStateSimplex(bool validSignal)
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
}
@@ -948,6 +1135,7 @@ void CFM::timeoutExtStateDuplex(bool validSignal)
if (!validSignal) {
DEBUG1("State to TIMEOUT_WAIT_EXT");
m_state = FS_TIMEOUT_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
@@ -962,6 +1150,7 @@ void CFM::timeoutExtStateSimplex(bool validSignal)
if (!validSignal) {
DEBUG1("State to TIMEOUT_WAIT_EXT");
m_state = FS_TIMEOUT_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
}
@@ -971,11 +1160,14 @@ void CFM::timeoutExtWaitStateDuplex(bool validSignal)
if (validSignal) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
m_timeoutTone.stop();
DEBUG1("Send Ext ack");
m_extAck.start();
@@ -997,11 +1189,14 @@ void CFM::timeoutExtWaitStateSimplex(bool validSignal)
if (validSignal) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
m_needReverse = true;
@@ -1009,6 +1204,61 @@ void CFM::timeoutExtWaitStateSimplex(bool validSignal)
}
}
void CFM::linkStateMachine(bool validRFSignal, bool validExtSignal)
{
if (validRFSignal && !m_rfSignal) {
io.setDecode(true);
io.setADCDetection(true);
if (!m_extSignal) {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
}
m_rfSignal = true;
}
if (validExtSignal && !m_extSignal) {
if (!m_rfSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
}
insertSilence(50U);
m_extSignal = true;
}
if (!validRFSignal && m_rfSignal) {
io.setDecode(false);
io.setADCDetection(false);
if (!m_extSignal) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
}
m_rfSignal = false;
if (m_extEnabled)
serial.writeFMEOT();
}
if (!validExtSignal && m_extSignal) {
if (!m_rfSignal) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
}
m_needReverse = true;
m_extSignal = false;
}
}
void CFM::sendCallsign()
{
if (m_holdoffTimer.isRunning()) {
+14 -20
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2021,2023 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
@@ -35,27 +35,12 @@
#include "FMUpSampler.h"
#include "FMNoiseSquelch.h"
enum FM_STATE {
FS_LISTENING,
FS_KERCHUNK_RF,
FS_RELAYING_RF,
FS_RELAYING_WAIT_RF,
FS_TIMEOUT_RF,
FS_TIMEOUT_WAIT_RF,
FS_KERCHUNK_EXT,
FS_RELAYING_EXT,
FS_RELAYING_WAIT_EXT,
FS_TIMEOUT_EXT,
FS_TIMEOUT_WAIT_EXT,
FS_HANG
};
class CFM {
public:
CFM();
void samples(bool cos, q15_t* samples, uint8_t length);
void samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
void process();
@@ -63,7 +48,7 @@ public:
uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level);
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
uint8_t getSpace() const;
@@ -78,7 +63,7 @@ private:
CFMCTCSSTX m_ctcssTX;
CFMNoiseSquelch m_squelch;
CFMTimeout m_timeoutTone;
FM_STATE m_state;
uint8_t m_state;
bool m_callsignAtStart;
bool m_callsignAtEnd;
bool m_callsignAtLatch;
@@ -89,7 +74,6 @@ private:
CFMTimer m_ackMinTimer;
CFMTimer m_ackDelayTimer;
CFMTimer m_hangTimer;
CFMTimer m_statusTimer;
CFMTimer m_reverseTimer;
bool m_needReverse;
CFMDirectFormI m_filterStage1;
@@ -97,6 +81,7 @@ private:
CFMDirectFormI m_filterStage3;
CFMBlanking m_blanking;
uint8_t m_accessMode;
bool m_linkMode;
bool m_cosInvert;
bool m_noiseSquelch;
q15_t m_rfAudioBoost;
@@ -107,9 +92,16 @@ private:
CRingBuffer<q15_t> m_inputRFRB;
CRingBuffer<q15_t> m_outputRFRB;
CFMUpSampler m_inputExtRB;
bool m_rfSignal;
bool m_extSignal;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
void stateMachine(bool validRFSignal, bool validExtSignal);
void repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
void linkSamples(bool cos, q15_t* samples, uint8_t length);
void duplexStateMachine(bool validRFSignal, bool validExtSignal);
void listeningStateDuplex(bool validRFSignal, bool validExtSignal);
void kerchunkRFStateDuplex(bool validSignal);
@@ -135,6 +127,8 @@ private:
void timeoutExtStateSimplex(bool validSignal);
void timeoutExtWaitStateSimplex(bool validSignal);
void linkStateMachine(bool validRFSignal, bool validExtSignal);
void clock(uint8_t length);
void sendCallsign();
+6 -11
View File
@@ -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);
+7 -12
View File
@@ -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
@@ -72,7 +69,8 @@ enum MMDVM_STATE {
STATE_FMCAL15K = 104,
STATE_FMCAL20K = 105,
STATE_FMCAL25K = 106,
STATE_FMCAL30K = 107
STATE_FMCAL30K = 107,
STATE_M17CAL = 108
};
#include "SerialPort.h"
@@ -100,12 +98,11 @@ enum MMDVM_STATE {
#include "CalNXDN.h"
#include "CalPOCSAG.h"
#include "CalRSSI.h"
#include "I2COLED.h"
#include "CWIdTX.h"
#include "AX25RX.h"
#include "AX25TX.h"
#include "CalM17.h"
#include "Debug.h"
#include "I2C3.h"
#include "IO.h"
#include "FM.h"
@@ -118,7 +115,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;
@@ -144,10 +141,6 @@ extern bool m_dcd;
extern CSerialPort serial;
extern CIO io;
#if defined(MODE_OLED)
extern CI2COLED oled;
#endif
#if defined(MODE_DSTAR)
extern CDStarRX dstarRX;
extern CDStarTX dstarTX;
@@ -194,6 +187,8 @@ extern CCalPOCSAG calPOCSAG;
#if defined(MODE_M17)
extern CM17RX m17RX;
extern CM17TX m17TX;
extern CCalM17 calM17;
#endif
#if defined(MODE_FM)
-284
View File
@@ -1,284 +0,0 @@
/*
* Copyright (C) 2020,2021 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_OLED)
#include "I2C3.h"
#include "Globals.h"
#define I2C_WRITE_REG(REG, VAL) ((REG) = (VAL))
#define I2C_READ_REG(REG) ((REG))
#define I2C_CLEAR_FLAG(__FLAG__) (((__FLAG__) == I2C_FLAG_TXE) ? (I2C3->ISR |= (__FLAG__)) : (I2C3->ICR = (__FLAG__)))
#define I2C_GET_FLAG(__FLAG__) ((((I2C3->ISR) & (__FLAG__)) == (__FLAG__)) ? SET : RESET)
#define I2C_RESET_CR2() (I2C3->CR2 &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_HEAD10R | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_RD_WRN)))
#define I2C_MODIFY_REG(REG, CLEARMASK, SETMASK) I2C_WRITE_REG((REG), (((I2C_READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
#define TIMING_CLEAR_MASK (0xF0FFFFFFU)
#define I2C_DUALADDRESS_DISABLE (0x00000000U)
#define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN
#define I2C_GENERALCALL_DISABLE (0x00000000U)
#define I2C_NOSTRETCH_DISABLE (0x00000000U)
#define I2C_ANALOGFILTER_ENABLE 0x00000000U
#define RCC_I2C3CLKSOURCE_PCLK1 ((uint32_t)0x00000000U)
#define I2C_OA2_NOMASK ((uint8_t)0x00U)
#define GPIO_MODE_AF_OD ((uint32_t)0x00000012U)
#define GPIO_OUTPUT_TYPE ((uint32_t)0x00000010U)
#define GPIO_MODE ((uint32_t)0x00000003U)
#define GPIO_NUMBER (16U)
#define I2C_ENABLE() (SET_BIT(I2C3->CR1, I2C_CR1_PE))
#define I2C_DISABLE() (CLEAR_BIT(I2C3->CR1, I2C_CR1_PE))
#define RCC_GPIOA_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);\
tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);\
} while(0)
#define RCC_GPIOC_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);\
tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);\
} while(0)
#define RCC_I2C3_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB1ENR, RCC_APB1ENR_I2C3EN);\
tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_I2C3EN);\
} while(0)
CI2C3::CI2C3()
{
}
void CI2C3::init()
{
// Enable the I2C3 clock
I2C_MODIFY_REG(RCC->DCKCFGR2, RCC_DCKCFGR2_I2C3SEL, RCC_I2C3CLKSOURCE_PCLK1);
// Enable the GPIOs for the SCL/SDA Pins
RCC_GPIOC_CLK_ENABLE();
RCC_GPIOA_CLK_ENABLE();
initI2C3();
// Configure Analogue filter
configAnalogFilter(I2C_ANALOGFILTER_ENABLE);
// Configure Digital filter
configDigitalFilter(0U);
}
void CI2C3::write(uint16_t addr, const uint8_t* data, uint8_t length)
{
DEBUG2("OLED Data", addr);
DEBUG_DUMP(data, length);
// Shift the address to the left
addr <<= 3;
// Wait for the I2C transmitter to become free
while (I2C_GET_FLAG(I2C_FLAG_BUSY) == SET)
;
// Configure the data transfer
transferConfig(addr, length, I2C_CR2_AUTOEND, I2C_Generate_Start_Write);
// Start Writing Data
for (uint16_t i = 0U; i < length; i++) {
// Wait for the TXIS flag to be set
while (I2C_GET_FLAG(I2C_FLAG_TXIS) == RESET)
;
// Write the byte to the TXDR
I2C3->TXDR = data[i];
}
// No need to Check TC flag, with AUTOEND mode the stop is automatically generated Wait until STOPF flag is set
while (I2C_GET_FLAG(I2C_FLAG_STOPF) == RESET)
;
// Clear STOP flag
I2C_CLEAR_FLAG(I2C_FLAG_STOPF);
// Clear Configuration Register 2
I2C_RESET_CR2();
}
void CI2C3::transferConfig(uint16_t addr, uint8_t length, uint32_t mode, uint32_t request)
{
// Update CR2 register
I2C_MODIFY_REG(I2C3->CR2, ((I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | \
(I2C_CR2_RD_WRN & (uint32_t)(request >> (31U - I2C_CR2_RD_WRN_Pos))) | I2C_CR2_START | I2C_CR2_STOP)), \
(uint32_t)(((uint32_t)addr & I2C_CR2_SADD) |
(((uint32_t)length << I2C_CR2_NBYTES_Pos) & I2C_CR2_NBYTES) | (uint32_t)mode | (uint32_t)request));
}
void CI2C3::configAnalogFilter(uint32_t AnalogFilter)
{
// Disable the selected I2C peripheral
I2C_DISABLE();
// Reset I2Cx ANOFF bit
I2C3->CR1 &= ~(I2C_CR1_ANFOFF);
// Set analog filter bit
I2C3->CR1 |= AnalogFilter;
I2C_ENABLE();
}
void CI2C3::configDigitalFilter(uint32_t DigitalFilter)
{
// Disable the selected I2C peripheral
I2C_DISABLE();
// Get the old register value
uint32_t tmpreg = I2C3->CR1;
// Reset I2Cx DNF bits [11:8]
tmpreg &= ~(I2C_CR1_DNF);
// Set I2Cx DNF coefficient
tmpreg |= DigitalFilter << 8U;
// Store the new register value
I2C3->CR1 = tmpreg;
I2C_ENABLE();
}
void CI2C3::initI2C3()
{
initMSP();
/* Disable the selected I2C peripheral */
I2C_DISABLE();
/*---------------------------- I2Cx TIMINGR Configuration ------------------*/
/* Configure I2Cx: Frequency range */
I2C3->TIMINGR = 0x0010061AU & TIMING_CLEAR_MASK;
/*---------------------------- I2Cx OAR1 Configuration ---------------------*/
/* Disable Own Address1 before set the Own Address1 configuration */
I2C3->OAR1 &= ~I2C_OAR1_OA1EN;
/* Configure I2Cx: Own Address1 and ack own address1 mode */
I2C3->OAR1 = (I2C_OAR1_OA1EN | 0U);
/*---------------------------- I2Cx CR2 Configuration ----------------------*/
/* Enable the AUTOEND by default, and enable NACK (should be disable only during Slave process */
I2C3->CR2 |= (I2C_CR2_AUTOEND | I2C_CR2_NACK);
/*---------------------------- I2Cx OAR2 Configuration ---------------------*/
/* Disable Own Address2 before set the Own Address2 configuration */
I2C3->OAR2 &= ~I2C_DUALADDRESS_ENABLE;
/* Configure I2Cx: Dual mode and Own Address2 */
I2C3->OAR2 = (I2C_DUALADDRESS_DISABLE | 0U | (I2C_OA2_NOMASK << 8));
/*---------------------------- I2Cx CR1 Configuration ----------------------*/
/* Configure I2Cx: Generalcall and NoStretch mode */
I2C3->CR1 = (I2C_GENERALCALL_DISABLE | I2C_NOSTRETCH_DISABLE);
/* Enable the selected I2C peripheral */
I2C_ENABLE();
}
void CI2C3::initMSP()
{
RCC_GPIOC_CLK_ENABLE();
RCC_GPIOA_CLK_ENABLE();
/* I2C3 GPIO Configuration
PC9 ------> I2C3_SDA
PA8 ------> I2C3_SCL
*/
initGPIO(GPIOC, GPIO_Pin_9);
initGPIO(GPIOA, GPIO_Pin_8);
// Peripheral clock enable
RCC_I2C3_CLK_ENABLE();
}
void CI2C3::initGPIO(GPIO_TypeDef* GPIOx, uint32_t Pin)
{
// Configure the port pins
for (uint32_t position = 0U; position < GPIO_NUMBER; position++)
{
// Get the IO position
uint32_t ioposition = ((uint32_t)0x01) << position;
// Get the current IO position
uint32_t iocurrent = Pin & ioposition;
if (iocurrent == ioposition)
{
// Configure the IO Speed
uint32_t temp = GPIOx->OSPEEDR;
temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2));
temp |= (GPIO_High_Speed << (position * 2));
GPIOx->OSPEEDR = temp;
// Configure the IO Output Type
temp = GPIOx->OTYPER;
temp &= ~(GPIO_OTYPER_OT_0 << position) ;
temp |= (((GPIO_MODE_AF_OD & GPIO_OUTPUT_TYPE) >> 4) << position);
GPIOx->OTYPER = temp;
// Activate the Pull Up resistor for the current IO
temp = GPIOx->PUPDR;
temp &= ~(GPIO_PUPDR_PUPDR0 << (position * 2));
temp |= ((GPIO_PuPd_UP) << (position * 2));
GPIOx->PUPDR = temp;
// Configure Alternate function mapped with the current IO
temp = GPIOx->AFR[position >> 3];
temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ;
temp |= ((uint32_t)(GPIO_AF4_I2C3) << (((uint32_t)position & (uint32_t)0x07) * 4));
GPIOx->AFR[position >> 3] = temp;
// Configure IO Direction mode (Input, Output, Alternate or Analog)
temp = GPIOx->MODER;
temp &= ~(GPIO_MODER_MODER0 << (position * 2));
temp |= ((GPIO_MODE_AF_OD & GPIO_MODE) << (position * 2));
GPIOx->MODER = temp;
}
}
}
#endif
-509
View File
@@ -1,509 +0,0 @@
/*
* Copyright (C) 2020,2021 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_OLED)
#include "I2COLED.h"
#include "I2C3.h"
#include "Globals.h"
const uint8_t OLED_ADDRESS = 0x78U;
const uint8_t OLED_WIDTH = 64U;
const uint8_t OLED_HEIGHT = 32U;
const uint16_t OLED_BUFFER_SIZE = (OLED_HEIGHT * OLED_WIDTH) / 8U;
const uint8_t SSD_Command_Mode = 0x00U; /* C0 and DC bit are 0 */
const uint8_t SSD_Data_Mode = 0x40U; /* C0 bit is 0 and DC bit is 1 */
const uint8_t SSD1306_Set_Lower_Column_Start_Address = 0x00U;
const uint8_t SSD1306_Set_Higher_Column_Start_Address = 0x10U;
const uint8_t SSD1306_Set_Start_Line = 0x40U;
const uint8_t CHAR_HEIGHT = 5U;
const uint8_t CHAR_WIDTH = 7U;
// Standard ascii 5x7 font
const uint8_t FONT[] = {
0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x3EU, 0x5BU, 0x4FU, 0x5BU, 0x3EU,
0x3EU, 0x6BU, 0x4FU, 0x6BU, 0x3EU,
0x1CU, 0x3EU, 0x7CU, 0x3EU, 0x1CU,
0x18U, 0x3CU, 0x7EU, 0x3CU, 0x18U,
0x1CU, 0x57U, 0x7DU, 0x57U, 0x1CU,
0x1CU, 0x5EU, 0x7FU, 0x5EU, 0x1CU,
0x00U, 0x18U, 0x3CU, 0x18U, 0x00U,
0xFFU, 0xE7U, 0xC3U, 0xE7U, 0xFFU,
0x00U, 0x18U, 0x24U, 0x18U, 0x00U,
0xFFU, 0xE7U, 0xDBU, 0xE7U, 0xFFU,
0x30U, 0x48U, 0x3AU, 0x06U, 0x0EU,
0x26U, 0x29U, 0x79U, 0x29U, 0x26U,
0x40U, 0x7FU, 0x05U, 0x05U, 0x07U,
0x40U, 0x7FU, 0x05U, 0x25U, 0x3FU,
0x5AU, 0x3CU, 0xE7U, 0x3CU, 0x5AU,
0x7FU, 0x3EU, 0x1CU, 0x1CU, 0x08U,
0x08U, 0x1CU, 0x1CU, 0x3EU, 0x7FU,
0x14U, 0x22U, 0x7FU, 0x22U, 0x14U,
0x5FU, 0x5FU, 0x00U, 0x5FU, 0x5FU,
0x06U, 0x09U, 0x7FU, 0x01U, 0x7FU,
0x00U, 0x66U, 0x89U, 0x95U, 0x6AU,
0x60U, 0x60U, 0x60U, 0x60U, 0x60U,
0x94U, 0xA2U, 0xFFU, 0xA2U, 0x94U,
0x08U, 0x04U, 0x7EU, 0x04U, 0x08U,
0x10U, 0x20U, 0x7EU, 0x20U, 0x10U,
0x08U, 0x08U, 0x2AU, 0x1CU, 0x08U,
0x08U, 0x1CU, 0x2AU, 0x08U, 0x08U,
0x1EU, 0x10U, 0x10U, 0x10U, 0x10U,
0x0CU, 0x1EU, 0x0CU, 0x1EU, 0x0CU,
0x30U, 0x38U, 0x3EU, 0x38U, 0x30U,
0x06U, 0x0EU, 0x3EU, 0x0EU, 0x06U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x5FU, 0x00U, 0x00U,
0x00U, 0x07U, 0x00U, 0x07U, 0x00U,
0x14U, 0x7FU, 0x14U, 0x7FU, 0x14U,
0x24U, 0x2AU, 0x7FU, 0x2AU, 0x12U,
0x23U, 0x13U, 0x08U, 0x64U, 0x62U,
0x36U, 0x49U, 0x56U, 0x20U, 0x50U,
0x00U, 0x08U, 0x07U, 0x03U, 0x00U,
0x00U, 0x1CU, 0x22U, 0x41U, 0x00U,
0x00U, 0x41U, 0x22U, 0x1CU, 0x00U,
0x2AU, 0x1CU, 0x7FU, 0x1CU, 0x2AU,
0x08U, 0x08U, 0x3EU, 0x08U, 0x08U,
0x00U, 0x80U, 0x70U, 0x30U, 0x00U,
0x08U, 0x08U, 0x08U, 0x08U, 0x08U,
0x00U, 0x00U, 0x60U, 0x60U, 0x00U,
0x20U, 0x10U, 0x08U, 0x04U, 0x02U,
0x3EU, 0x51U, 0x49U, 0x45U, 0x3EU,
0x00U, 0x42U, 0x7FU, 0x40U, 0x00U,
0x72U, 0x49U, 0x49U, 0x49U, 0x46U,
0x21U, 0x41U, 0x49U, 0x4DU, 0x33U,
0x18U, 0x14U, 0x12U, 0x7FU, 0x10U,
0x27U, 0x45U, 0x45U, 0x45U, 0x39U,
0x3CU, 0x4AU, 0x49U, 0x49U, 0x31U,
0x41U, 0x21U, 0x11U, 0x09U, 0x07U,
0x36U, 0x49U, 0x49U, 0x49U, 0x36U,
0x46U, 0x49U, 0x49U, 0x29U, 0x1EU,
0x00U, 0x00U, 0x14U, 0x00U, 0x00U,
0x00U, 0x40U, 0x34U, 0x00U, 0x00U,
0x00U, 0x08U, 0x14U, 0x22U, 0x41U,
0x14U, 0x14U, 0x14U, 0x14U, 0x14U,
0x00U, 0x41U, 0x22U, 0x14U, 0x08U,
0x02U, 0x01U, 0x59U, 0x09U, 0x06U,
0x3EU, 0x41U, 0x5DU, 0x59U, 0x4EU,
0x7CU, 0x12U, 0x11U, 0x12U, 0x7CU,
0x7FU, 0x49U, 0x49U, 0x49U, 0x36U,
0x3EU, 0x41U, 0x41U, 0x41U, 0x22U,
0x7FU, 0x41U, 0x41U, 0x41U, 0x3EU,
0x7FU, 0x49U, 0x49U, 0x49U, 0x41U,
0x7FU, 0x09U, 0x09U, 0x09U, 0x01U,
0x3EU, 0x41U, 0x41U, 0x51U, 0x73U,
0x7FU, 0x08U, 0x08U, 0x08U, 0x7FU,
0x00U, 0x41U, 0x7FU, 0x41U, 0x00U,
0x20U, 0x40U, 0x41U, 0x3FU, 0x01U,
0x7FU, 0x08U, 0x14U, 0x22U, 0x41U,
0x7FU, 0x40U, 0x40U, 0x40U, 0x40U,
0x7FU, 0x02U, 0x1CU, 0x02U, 0x7FU,
0x7FU, 0x04U, 0x08U, 0x10U, 0x7FU,
0x3EU, 0x41U, 0x41U, 0x41U, 0x3EU,
0x7FU, 0x09U, 0x09U, 0x09U, 0x06U,
0x3EU, 0x41U, 0x51U, 0x21U, 0x5EU,
0x7FU, 0x09U, 0x19U, 0x29U, 0x46U,
0x26U, 0x49U, 0x49U, 0x49U, 0x32U,
0x03U, 0x01U, 0x7FU, 0x01U, 0x03U,
0x3FU, 0x40U, 0x40U, 0x40U, 0x3FU,
0x1FU, 0x20U, 0x40U, 0x20U, 0x1FU,
0x3FU, 0x40U, 0x38U, 0x40U, 0x3FU,
0x63U, 0x14U, 0x08U, 0x14U, 0x63U,
0x03U, 0x04U, 0x78U, 0x04U, 0x03U,
0x61U, 0x59U, 0x49U, 0x4DU, 0x43U,
0x00U, 0x7FU, 0x41U, 0x41U, 0x41U,
0x02U, 0x04U, 0x08U, 0x10U, 0x20U,
0x00U, 0x41U, 0x41U, 0x41U, 0x7FU,
0x04U, 0x02U, 0x01U, 0x02U, 0x04U,
0x40U, 0x40U, 0x40U, 0x40U, 0x40U,
0x00U, 0x03U, 0x07U, 0x08U, 0x00U,
0x20U, 0x54U, 0x54U, 0x78U, 0x40U,
0x7FU, 0x28U, 0x44U, 0x44U, 0x38U,
0x38U, 0x44U, 0x44U, 0x44U, 0x28U,
0x38U, 0x44U, 0x44U, 0x28U, 0x7FU,
0x38U, 0x54U, 0x54U, 0x54U, 0x18U,
0x00U, 0x08U, 0x7EU, 0x09U, 0x02U,
0x18U, 0xA4U, 0xA4U, 0x9CU, 0x78U,
0x7FU, 0x08U, 0x04U, 0x04U, 0x78U,
0x00U, 0x44U, 0x7DU, 0x40U, 0x00U,
0x20U, 0x40U, 0x40U, 0x3DU, 0x00U,
0x7FU, 0x10U, 0x28U, 0x44U, 0x00U,
0x00U, 0x41U, 0x7FU, 0x40U, 0x00U,
0x7CU, 0x04U, 0x78U, 0x04U, 0x78U,
0x7CU, 0x08U, 0x04U, 0x04U, 0x78U,
0x38U, 0x44U, 0x44U, 0x44U, 0x38U,
0xFCU, 0x18U, 0x24U, 0x24U, 0x18U,
0x18U, 0x24U, 0x24U, 0x18U, 0xFCU,
0x7CU, 0x08U, 0x04U, 0x04U, 0x08U,
0x48U, 0x54U, 0x54U, 0x54U, 0x24U,
0x04U, 0x04U, 0x3FU, 0x44U, 0x24U,
0x3CU, 0x40U, 0x40U, 0x20U, 0x7CU,
0x1CU, 0x20U, 0x40U, 0x20U, 0x1CU,
0x3CU, 0x40U, 0x30U, 0x40U, 0x3CU,
0x44U, 0x28U, 0x10U, 0x28U, 0x44U,
0x4CU, 0x90U, 0x90U, 0x90U, 0x7CU,
0x44U, 0x64U, 0x54U, 0x4CU, 0x44U,
0x00U, 0x08U, 0x36U, 0x41U, 0x00U,
0x00U, 0x00U, 0x77U, 0x00U, 0x00U,
0x00U, 0x41U, 0x36U, 0x08U, 0x00U,
0x02U, 0x01U, 0x02U, 0x04U, 0x02U,
0x3CU, 0x26U, 0x23U, 0x26U, 0x3CU,
0x1EU, 0xA1U, 0xA1U, 0x61U, 0x12U,
0x3AU, 0x40U, 0x40U, 0x20U, 0x7AU,
0x38U, 0x54U, 0x54U, 0x55U, 0x59U,
0x21U, 0x55U, 0x55U, 0x79U, 0x41U,
0x21U, 0x54U, 0x54U, 0x78U, 0x41U,
0x21U, 0x55U, 0x54U, 0x78U, 0x40U,
0x20U, 0x54U, 0x55U, 0x79U, 0x40U,
0x0CU, 0x1EU, 0x52U, 0x72U, 0x12U,
0x39U, 0x55U, 0x55U, 0x55U, 0x59U,
0x39U, 0x54U, 0x54U, 0x54U, 0x59U,
0x39U, 0x55U, 0x54U, 0x54U, 0x58U,
0x00U, 0x00U, 0x45U, 0x7CU, 0x41U,
0x00U, 0x02U, 0x45U, 0x7DU, 0x42U,
0x00U, 0x01U, 0x45U, 0x7CU, 0x40U,
0xF0U, 0x29U, 0x24U, 0x29U, 0xF0U,
0xF0U, 0x28U, 0x25U, 0x28U, 0xF0U,
0x7CU, 0x54U, 0x55U, 0x45U, 0x00U,
0x20U, 0x54U, 0x54U, 0x7CU, 0x54U,
0x7CU, 0x0AU, 0x09U, 0x7FU, 0x49U,
0x32U, 0x49U, 0x49U, 0x49U, 0x32U,
0x32U, 0x48U, 0x48U, 0x48U, 0x32U,
0x32U, 0x4AU, 0x48U, 0x48U, 0x30U,
0x3AU, 0x41U, 0x41U, 0x21U, 0x7AU,
0x3AU, 0x42U, 0x40U, 0x20U, 0x78U,
0x00U, 0x9DU, 0xA0U, 0xA0U, 0x7DU,
0x39U, 0x44U, 0x44U, 0x44U, 0x39U,
0x3DU, 0x40U, 0x40U, 0x40U, 0x3DU,
0x3CU, 0x24U, 0xFFU, 0x24U, 0x24U,
0x48U, 0x7EU, 0x49U, 0x43U, 0x66U,
0x2BU, 0x2FU, 0xFCU, 0x2FU, 0x2BU,
0xFFU, 0x09U, 0x29U, 0xF6U, 0x20U,
0xC0U, 0x88U, 0x7EU, 0x09U, 0x03U,
0x20U, 0x54U, 0x54U, 0x79U, 0x41U,
0x00U, 0x00U, 0x44U, 0x7DU, 0x41U,
0x30U, 0x48U, 0x48U, 0x4AU, 0x32U,
0x38U, 0x40U, 0x40U, 0x22U, 0x7AU,
0x00U, 0x7AU, 0x0AU, 0x0AU, 0x72U,
0x7DU, 0x0DU, 0x19U, 0x31U, 0x7DU,
0x26U, 0x29U, 0x29U, 0x2FU, 0x28U,
0x26U, 0x29U, 0x29U, 0x29U, 0x26U,
0x30U, 0x48U, 0x4DU, 0x40U, 0x20U,
0x38U, 0x08U, 0x08U, 0x08U, 0x08U,
0x08U, 0x08U, 0x08U, 0x08U, 0x38U,
0x2FU, 0x10U, 0xC8U, 0xACU, 0xBAU,
0x2FU, 0x10U, 0x28U, 0x34U, 0xFAU,
0x00U, 0x00U, 0x7BU, 0x00U, 0x00U,
0x08U, 0x14U, 0x2AU, 0x14U, 0x22U,
0x22U, 0x14U, 0x2AU, 0x14U, 0x08U,
0xAAU, 0x00U, 0x55U, 0x00U, 0xAAU,
0xAAU, 0x55U, 0xAAU, 0x55U, 0xAAU,
0x00U, 0x00U, 0x00U, 0xFFU, 0x00U,
0x10U, 0x10U, 0x10U, 0xFFU, 0x00U,
0x14U, 0x14U, 0x14U, 0xFFU, 0x00U,
0x10U, 0x10U, 0xFFU, 0x00U, 0xFFU,
0x10U, 0x10U, 0xF0U, 0x10U, 0xF0U,
0x14U, 0x14U, 0x14U, 0xFCU, 0x00U,
0x14U, 0x14U, 0xF7U, 0x00U, 0xFFU,
0x00U, 0x00U, 0xFFU, 0x00U, 0xFFU,
0x14U, 0x14U, 0xF4U, 0x04U, 0xFCU,
0x14U, 0x14U, 0x17U, 0x10U, 0x1FU,
0x10U, 0x10U, 0x1FU, 0x10U, 0x1FU,
0x14U, 0x14U, 0x14U, 0x1FU, 0x00U,
0x10U, 0x10U, 0x10U, 0xF0U, 0x00U,
0x00U, 0x00U, 0x00U, 0x1FU, 0x10U,
0x10U, 0x10U, 0x10U, 0x1FU, 0x10U,
0x10U, 0x10U, 0x10U, 0xF0U, 0x10U,
0x00U, 0x00U, 0x00U, 0xFFU, 0x10U,
0x10U, 0x10U, 0x10U, 0x10U, 0x10U,
0x10U, 0x10U, 0x10U, 0xFFU, 0x10U,
0x00U, 0x00U, 0x00U, 0xFFU, 0x14U,
0x00U, 0x00U, 0xFFU, 0x00U, 0xFFU,
0x00U, 0x00U, 0x1FU, 0x10U, 0x17U,
0x00U, 0x00U, 0xFCU, 0x04U, 0xF4U,
0x14U, 0x14U, 0x17U, 0x10U, 0x17U,
0x14U, 0x14U, 0xF4U, 0x04U, 0xF4U,
0x00U, 0x00U, 0xFFU, 0x00U, 0xF7U,
0x14U, 0x14U, 0x14U, 0x14U, 0x14U,
0x14U, 0x14U, 0xF7U, 0x00U, 0xF7U,
0x14U, 0x14U, 0x14U, 0x17U, 0x14U,
0x10U, 0x10U, 0x1FU, 0x10U, 0x1FU,
0x14U, 0x14U, 0x14U, 0xF4U, 0x14U,
0x10U, 0x10U, 0xF0U, 0x10U, 0xF0U,
0x00U, 0x00U, 0x1FU, 0x10U, 0x1FU,
0x00U, 0x00U, 0x00U, 0x1FU, 0x14U,
0x00U, 0x00U, 0x00U, 0xFCU, 0x14U,
0x00U, 0x00U, 0xF0U, 0x10U, 0xF0U,
0x10U, 0x10U, 0xFFU, 0x10U, 0xFFU,
0x14U, 0x14U, 0x14U, 0xFFU, 0x14U,
0x10U, 0x10U, 0x10U, 0x1FU, 0x00U,
0x00U, 0x00U, 0x00U, 0xF0U, 0x10U,
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
0xF0U, 0xF0U, 0xF0U, 0xF0U, 0xF0U,
0xFFU, 0xFFU, 0xFFU, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0xFFU, 0xFFU,
0x0FU, 0x0FU, 0x0FU, 0x0FU, 0x0FU,
0x38U, 0x44U, 0x44U, 0x38U, 0x44U,
0x7CU, 0x2AU, 0x2AU, 0x3EU, 0x14U,
0x7EU, 0x02U, 0x02U, 0x06U, 0x06U,
0x02U, 0x7EU, 0x02U, 0x7EU, 0x02U,
0x63U, 0x55U, 0x49U, 0x41U, 0x63U,
0x38U, 0x44U, 0x44U, 0x3CU, 0x04U,
0x40U, 0x7EU, 0x20U, 0x1EU, 0x20U,
0x06U, 0x02U, 0x7EU, 0x02U, 0x02U,
0x99U, 0xA5U, 0xE7U, 0xA5U, 0x99U,
0x1CU, 0x2AU, 0x49U, 0x2AU, 0x1CU,
0x4CU, 0x72U, 0x01U, 0x72U, 0x4CU,
0x30U, 0x4AU, 0x4DU, 0x4DU, 0x30U,
0x30U, 0x48U, 0x78U, 0x48U, 0x30U,
0xBCU, 0x62U, 0x5AU, 0x46U, 0x3DU,
0x3EU, 0x49U, 0x49U, 0x49U, 0x00U,
0x7EU, 0x01U, 0x01U, 0x01U, 0x7EU,
0x2AU, 0x2AU, 0x2AU, 0x2AU, 0x2AU,
0x44U, 0x44U, 0x5FU, 0x44U, 0x44U,
0x40U, 0x51U, 0x4AU, 0x44U, 0x40U,
0x40U, 0x44U, 0x4AU, 0x51U, 0x40U,
0x00U, 0x00U, 0xFFU, 0x01U, 0x03U,
0xE0U, 0x80U, 0xFFU, 0x00U, 0x00U,
0x08U, 0x08U, 0x6BU, 0x6BU, 0x08U,
0x36U, 0x12U, 0x36U, 0x24U, 0x36U,
0x06U, 0x0FU, 0x09U, 0x0FU, 0x06U,
0x00U, 0x00U, 0x18U, 0x18U, 0x00U,
0x00U, 0x00U, 0x10U, 0x10U, 0x00U,
0x30U, 0x40U, 0xFFU, 0x01U, 0x01U,
0x00U, 0x1FU, 0x01U, 0x01U, 0x1EU,
0x00U, 0x19U, 0x1DU, 0x17U, 0x12U,
0x00U, 0x3CU, 0x3CU, 0x3CU, 0x3CU,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
// Arduino Compatible Macro
#define _BV(bit) (1 << (bit))
CI2COLED::CI2COLED() :
m_i2c(),
m_oledBuffer(NULL)
{
m_oledBuffer = new uint8_t[OLED_BUFFER_SIZE];
clear();
}
void CI2COLED::init()
{
m_i2c.init();
// Initialise the VG-6432TSWEG02 OLED display
// Taken from https://datasheet.lcsc.com/szlcsc/1912111437_WiseChip-VG-6432TSWAG01-IIC-sh1106_C194312.pdf
sendCommand(0xAEU); // Display off
sendCommand(0x00U); // Set lower column address
sendCommand(0x12U); // Set higher column address
sendCommand(0x00U); // Set display start line
sendCommand(0xB0U); // Set page address
sendCommand(0x81U, 0x4FU); // Contract control, 128
sendCommand(0xA1U); // Set segment remap
sendCommand(0xA6U); // Normal/reverse
sendCommand(0xA8U, 0x1FU); // Multiplex ratio, duty = 1/32
sendCommand(0xC8U); // Com scan direction
sendCommand(0xD3U, 0x00U); // Set display offset
sendCommand(0xD5U, 0x80U); // Set osc division
sendCommand(0xD9U, 0x1FU); // Set pre-charge period
sendCommand(0xDAU, 0x12U); // Set COM pins
sendCommand(0xDBU, 0x40U); // Set vcomh
sendCommand(0x8DU, 0x14U); // Set charge pump enable
sendCommand(0xAFU); // Display on
}
void CI2COLED::setMode(int state)
{
clear();
switch (MMDVM_STATE(state)) {
case STATE_IDLE:
write("Idle");
break;
case STATE_DSTAR:
write("D-Star");
break;
case STATE_DMR:
write("DMR");
break;
case STATE_YSF:
write("YSF");
break;
case STATE_P25:
write("P25");
break;
case STATE_NXDN:
write("NXDN");
break;
case STATE_FM:
write("FM");
break;
case STATE_M17:
write("M17");
break;
case STATE_POCSAG:
write("POCSAG");
break;
case STATE_AX25:
write("AX.25");
break;
default:
write("Calibrate");
break;
}
display();
}
void CI2COLED::sendCommand(uint8_t c0, uint8_t c1)
{
uint8_t buff[3U];
buff[0U] = SSD_Command_Mode;
buff[1U] = c0;
buff[2U] = c1;
// Write Data on I2C
m_i2c.write(OLED_ADDRESS, buff, 3U);
}
void CI2COLED::sendCommand(uint8_t c)
{
uint8_t buff[2U];
buff[0U] = SSD_Command_Mode;
buff[1U] = c;
// Write Data on I2C
m_i2c.write(OLED_ADDRESS, buff, 2U);
}
void CI2COLED::sendData(const uint8_t* data, uint16_t length)
{
uint8_t buff[20U];
buff[0U] = SSD_Data_Mode;
::memcpy(buff + 1U, data, length * sizeof(uint8_t));
// Write Data on I2C
m_i2c.write(OLED_ADDRESS, buff, length + 1U);
}
void CI2COLED::clear()
{
::memset(m_oledBuffer, 0x00U, OLED_BUFFER_SIZE);
}
void CI2COLED::write(const char* text)
{
size_t len = ::strlen(text);
uint16_t scale = OLED_WIDTH / (len * (CHAR_WIDTH + 1U));
if (scale == 0U) scale = 1U;
uint8_t charHeight = CHAR_HEIGHT * scale;
uint8_t charWidth = (CHAR_WIDTH + 1U) * scale;
uint8_t x = (OLED_HEIGHT - charHeight) / 2U;
uint8_t y = (OLED_WIDTH - charWidth) / 2U;
for (size_t i = 0U; i < len; i++) {
write(x, y, text[i], scale);
y += charWidth;
}
}
void CI2COLED::write(uint8_t x, uint8_t y, char c, uint8_t size)
{
for (uint8_t i = 0U; i < 6U; i++) {
uint8_t line;
if (i == 5U)
line = 0U;
else
line = FONT[(c * 5U) + i];
for (uint8_t j = 0U; j < 8U; j++) {
if (line & 0x1U) {
if (size == 1U) // default size
drawPixel(x + i, y + j);
else // big size
fillRect(x + (i * size), y + (j * size), size, size);
}
line >>= 1;
}
}
}
void CI2COLED::fillRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height)
{
for (uint8_t i = x; i < (x + height - 1U); i++) {
for (uint8_t j = y; j < (y + width - 1U); j++)
drawPixel(i, j);
}
}
void CI2COLED::drawPixel(uint8_t x, uint8_t y)
{
// Get where to do the change in the buffer
uint8_t* p = m_oledBuffer + (x + (y / 8U) * OLED_WIDTH);
// x is which column
*p |= _BV((y % 8U));
}
void CI2COLED::display()
{
sendCommand(SSD1306_Set_Lower_Column_Start_Address | 0x00U); // Low col = 0
sendCommand(SSD1306_Set_Higher_Column_Start_Address | 0x00U); // High col = 0
sendCommand(SSD1306_Set_Start_Line | 0x00U); // Line #0
// loop trough all OLED buffer and send a bunch of 16 data byte in one transmission
for (uint16_t i = 0U; i < OLED_BUFFER_SIZE; i += 16U)
sendData(m_oledBuffer + i, 16U);
}
#endif
-55
View File
@@ -1,55 +0,0 @@
/*
* Copyright (C) 2020,2021 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_OLED)
#if !defined(I2COLED_H)
#define I2COLED_H
#include "I2C3.h"
class CI2COLED {
public:
CI2COLED();
void init();
void setMode(int state);
private:
CI2C3 m_i2c;
uint8_t* m_oledBuffer;
void write(const char* text);
void write(uint8_t x, uint8_t y, char c, uint8_t size);
void drawPixel(uint8_t x, uint8_t y);
void fillRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height);
void clear();
void display();
void sendCommand(uint8_t c);
void sendCommand(uint8_t c0, uint8_t c1);
void sendData(const uint8_t* c, uint16_t length);
};
#endif
#endif
+37 -28
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@@ -91,9 +91,13 @@ m_dcState(),
m_gaussianFilter(),
m_gaussianState(),
#endif
#if defined(MODE_DMR) || defined(MODE_YSF)
m_rrc02Filter(),
m_rrc02State(),
#if defined(MODE_DMR)
m_rrc02Filter1(),
m_rrc02State1(),
#endif
#if defined(MODE_YSF)
m_rrc02Filter2(),
m_rrc02State2(),
#endif
#if defined(MODE_P25)
m_boxcar5Filter(),
@@ -138,7 +142,7 @@ m_watchdog(0U),
m_lockout(false)
{
#if defined(USE_DCBLOCKER)
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
m_dcFilter.numStages = DC_FILTER_STAGES;
m_dcFilter.pState = m_dcState;
m_dcFilter.pCoeffs = DC_FILTER;
@@ -152,11 +156,18 @@ m_lockout(false)
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
#endif
#if defined(MODE_DMR) || defined(MODE_YSF)
::memset(m_rrc02State, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter.pState = m_rrc02State;
m_rrc02Filter.pCoeffs = RRC_0_2_FILTER;
#if defined(MODE_DMR)
::memset(m_rrc02State1, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter1.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter1.pState = m_rrc02State1;
m_rrc02Filter1.pCoeffs = RRC_0_2_FILTER;
#endif
#if defined(MODE_YSF)
::memset(m_rrc02State2, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter2.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter2.pState = m_rrc02State2;
m_rrc02Filter2.pCoeffs = RRC_0_2_FILTER;
#endif
#if defined(MODE_P25)
@@ -458,7 +469,7 @@ void CIO::process()
#if defined(MODE_DMR)
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrc02Filter, samples, DMRVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter1, samples, DMRVals, RX_BLOCK_SIZE);
if (m_duplex)
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
@@ -471,9 +482,9 @@ void CIO::process()
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrc02Filter, dcSamples, YSFVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter2, dcSamples, YSFVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrc02Filter, samples, YSFVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter2, samples, YSFVals, RX_BLOCK_SIZE);
#endif
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
@@ -495,9 +506,9 @@ void CIO::process()
if (m_fmEnable) {
bool cos = getCOSInt();
#if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
#else
fm.samples(cos, samples, RX_BLOCK_SIZE);
fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
#endif
}
#endif
@@ -505,9 +516,9 @@ void CIO::process()
#if defined(MODE_FM) && defined(MODE_AX25)
if (m_ax25Enable) {
#if defined(USE_DCBLOCKER)
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
ax25RX.samples(dcSamples, rssi, RX_BLOCK_SIZE);
#else
ax25RX.samples(samples, RX_BLOCK_SIZE);
ax25RX.samples(samples, rssi, RX_BLOCK_SIZE);
#endif
}
#endif
@@ -531,7 +542,7 @@ void CIO::process()
else if (m_modemState == STATE_DMR) {
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrc02Filter, samples, DMRVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter1, samples, DMRVals, RX_BLOCK_SIZE);
if (m_duplex) {
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
@@ -551,9 +562,9 @@ void CIO::process()
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrc02Filter, dcSamples, YSFVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter2, dcSamples, YSFVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrc02Filter, samples, YSFVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter2, samples, YSFVals, RX_BLOCK_SIZE);
#endif
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
@@ -616,18 +627,18 @@ void CIO::process()
else if (m_modemState == STATE_FM) {
bool cos = getCOSInt();
#if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
#if defined(MODE_AX25)
if (m_ax25Enable)
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
ax25RX.samples(dcSamples, rssi, RX_BLOCK_SIZE);
#endif
#else
fm.samples(cos, samples, RX_BLOCK_SIZE);
fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
#if defined(MODE_AX25)
if (m_ax25Enable)
ax25RX.samples(samples, RX_BLOCK_SIZE);
ax25RX.samples(samples, rssi, RX_BLOCK_SIZE);
#endif
#endif
}
@@ -746,6 +757,7 @@ void CIO::setMode(MMDVM_STATE state)
case STATE_M17: setM17Int(false); break;
case STATE_POCSAG: setPOCSAGInt(false); break;
case STATE_FM: setFMInt(false); break;
default: break;
}
switch (state) {
@@ -757,13 +769,10 @@ void CIO::setMode(MMDVM_STATE state)
case STATE_M17: setM17Int(true); break;
case STATE_POCSAG: setPOCSAGInt(true); break;
case STATE_FM: setFMInt(true); break;
default: break;
}
#endif
#if defined(MODE_OLED)
oled.setMode(state);
#endif
m_modemState = state;
}
+9 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021 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
@@ -81,9 +81,14 @@ private:
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
#endif
#if defined(MODE_DMR) || defined(MODE_YSF)
arm_fir_instance_q15 m_rrc02Filter;
q15_t m_rrc02State[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#if defined(MODE_DMR)
arm_fir_instance_q15 m_rrc02Filter1;
q15_t m_rrc02State1[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
#if defined(MODE_YSF)
arm_fir_instance_q15 m_rrc02Filter2;
q15_t m_rrc02State2[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
#if defined(MODE_P25)
+8 -6
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018,2020,2023 by Jonathan Naylor G4KLX
* Copyright (C) 2019,2020 by BG5HHP
*
* This program is free software; you can redistribute it and/or modify
@@ -190,10 +190,6 @@ void CIO::initInt()
#endif
#endif
#if defined(MODE_OLED)
oled.init();
#endif
}
void CIO::startInt()
@@ -369,10 +365,16 @@ void CIO::interrupt()
#endif
}
// trigger next ADC1
// Trigger next ADC1
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
ADC_SoftwareStartConv(ADC1);
#if defined(SEND_RSSI_DATA)
// Trigger next ADC2
ADC_ClearFlag(ADC2, ADC_FLAG_EOC);
ADC_SoftwareStartConv(ADC2);
#endif
m_rxBuffer.put(sample);
m_rssiBuffer.put(rawRSSI);
-507
View File
@@ -1,507 +0,0 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020,2021 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);
#if defined(MODE_LEDS)
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
#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
#if defined(MODE_OLED)
oled.init();
#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;
}
#if defined(MODE_LEDS)
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
}
#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
+9 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017,2018,2020,2021 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
@@ -27,18 +27,17 @@ const unsigned int M17_FRAME_LENGTH_SYMBOLS = M17_FRAME_LENGTH_BITS / 2U;
const unsigned int M17_FRAME_LENGTH_SAMPLES = M17_FRAME_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;
const unsigned int M17_SYNC_LENGTH_SYMBOLS = M17_SYNC_LENGTH_BITS / 2U;
const unsigned int M17_SYNC_LENGTH_SAMPLES = M17_SYNC_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
const uint8_t M17_LINK_SETUP_SYNC_BYTES[] = {0x55U, 0xF7U};
const uint8_t M17_STREAM_SYNC_BYTES[] = {0xFFU, 0x5DU};
const uint8_t M17_PACKET_SYNC_BYTES[] = {0x75U, 0xFFU};
const uint8_t M17_SYNC_BYTES_LENGTH = 2U;
const uint8_t M17_EOF_SYNC_BYTES[] = {0x55U, 0x5DU};
const uint16_t M17_LINK_SETUP_SYNC_BITS = 0x55F7U;
const uint16_t M17_STREAM_SYNC_BITS = 0xFF5DU;
const uint16_t M17_PACKET_SYNC_BITS = 0x75FFU;
const uint16_t M17_EOF_SYNC_BITS = 0x555DU;
// 5 5 F 7
// 01 01 01 01 11 11 01 11
@@ -56,13 +55,13 @@ const int8_t M17_STREAM_SYNC_SYMBOLS_VALUES[] = {-3, -3, -3, -3, +3, +3, -3, +3}
const uint8_t M17_STREAM_SYNC_SYMBOLS = 0x0DU;
// 7 5 F F
// 01 11 01 01 11 11 11 11
// +3 -3 +3 +3 -3 -3 -3 -3
// 5 5 5 D
// 01 01 01 01 01 01 11 01
// +3 +3 +3 +3 +3 +3 -3 +3
const int8_t M17_PACKET_SYNC_SYMBOLS_VALUES[] = {+3, -3, +3, +3, -3, -3, -3, -3};
const int8_t M17_EOF_SYNC_SYMBOLS_VALUES[] = {+3, +3, +3, +3, +3, +3, -3, +3};
const uint8_t M17_PACKET_SYNC_SYMBOLS = 0xB0U;
const uint8_t M17_EOF_SYNC_SYMBOLS = 0xFDU;
#endif
+38 -51
View File
@@ -105,7 +105,6 @@ void CM17RX::samples(const q15_t* samples, uint16_t* rssi, uint8_t length)
switch (m_state) {
case M17RXS_LINK_SETUP:
case M17RXS_STREAM:
case M17RXS_PACKET:
processData(sample);
break;
default:
@@ -127,9 +126,8 @@ void CM17RX::processNone(q15_t sample)
{
bool ret1 = correlateSync(M17_LINK_SETUP_SYNC_SYMBOLS, M17_LINK_SETUP_SYNC_SYMBOLS_VALUES, M17_LINK_SETUP_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
bool ret2 = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
// bool ret3 = correlateSync(M17_PACKET_SYNC_SYMBOLS, M17_PACKET_SYNC_SYMBOLS_VALUES, M17_PACKET_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
if (ret1 || ret2 /* || ret3 */ ) {
if (ret1 || ret2) {
// On the first sync, start the countdown to the state change
if (m_countdown == 0U) {
m_rssiAccum = 0U;
@@ -144,7 +142,6 @@ void CM17RX::processNone(q15_t sample)
if (ret1) m_nextState = M17RXS_LINK_SETUP;
if (ret2) m_nextState = M17RXS_STREAM;
// if (ret3) m_nextState = M17RXS_PACKET;
}
}
@@ -168,28 +165,42 @@ void CM17RX::processNone(q15_t sample)
void CM17RX::processData(q15_t sample)
{
bool eof = false;
if (m_minSyncPtr < m_maxSyncPtr) {
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr) {
bool ret1 = correlateSync(M17_LINK_SETUP_SYNC_SYMBOLS, M17_LINK_SETUP_SYNC_SYMBOLS_VALUES, M17_LINK_SETUP_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
bool ret2 = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
// bool ret3 = correlateSync(M17_PACKET_SYNC_SYMBOLS, M17_PACKET_SYNC_SYMBOLS_VALUES, M17_PACKET_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
bool ret = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
if (ret1) m_state = M17RXS_LINK_SETUP;
if (ret2) m_state = M17RXS_STREAM;
// if (ret3) m_state = M17RXS_PACKET;
eof = correlateSync(M17_EOF_SYNC_SYMBOLS, M17_EOF_SYNC_SYMBOLS_VALUES, M17_EOF_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
if (ret) m_state = M17RXS_STREAM;
}
} else {
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr) {
bool ret1 = correlateSync(M17_LINK_SETUP_SYNC_SYMBOLS, M17_LINK_SETUP_SYNC_SYMBOLS_VALUES, M17_LINK_SETUP_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
bool ret2 = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
// bool ret3 = correlateSync(M17_PACKET_SYNC_SYMBOLS, M17_PACKET_SYNC_SYMBOLS_VALUES, M17_PACKET_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
bool ret = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
if (ret1) m_state = M17RXS_LINK_SETUP;
if (ret2) m_state = M17RXS_STREAM;
// if (ret3) m_state = M17RXS_PACKET;
eof = correlateSync(M17_EOF_SYNC_SYMBOLS, M17_EOF_SYNC_SYMBOLS_VALUES, M17_EOF_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
if (ret) m_state = M17RXS_STREAM;
}
}
if (eof) {
DEBUG4("M17RX: eof sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
io.setDecode(false);
io.setADCDetection(false);
serial.writeM17EOT();
m_state = M17RXS_NONE;
m_endPtr = NOENDPTR;
m_averagePtr = NOAVEPTR;
m_countdown = 0U;
m_nextState = M17RXS_NONE;
m_maxCorr = 0;
}
if (m_dataPtr == m_endPtr) {
// Only update the centre and threshold if they are from a good sync
if (m_lostCount == MAX_SYNC_FRAMES) {
@@ -211,9 +222,8 @@ void CM17RX::processData(q15_t sample)
case M17RXS_STREAM:
DEBUG4("M17RX: stream sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
break;
case M17RXS_PACKET:
DEBUG4("M17RX: packet sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
break;
default:
break;
}
uint8_t frame[M17_FRAME_LENGTH_BYTES + 3U];
@@ -236,8 +246,7 @@ void CM17RX::processData(q15_t sample)
m_nextState = M17RXS_NONE;
m_maxCorr = 0;
} else {
frame[0U] = 0x00U;
frame[0U] |= m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
switch (m_state) {
case M17RXS_LINK_SETUP:
@@ -246,9 +255,8 @@ void CM17RX::processData(q15_t sample)
case M17RXS_STREAM:
writeRSSIStream(frame);
break;
case M17RXS_PACKET:
writeRSSIPacket(frame);
break;
default:
break;
}
m_maxCorr = 0;
@@ -308,11 +316,11 @@ bool CM17RX::correlateSync(uint8_t syncSymbols, const int8_t* syncSymbolValues,
if (startPtr >= M17_FRAME_LENGTH_SAMPLES)
startPtr -= M17_FRAME_LENGTH_SAMPLES;
uint8_t sync[M17_SYNC_BYTES_LENGTH];
uint8_t sync[M17_SYNC_LENGTH_BYTES];
samplesToBits(startPtr, M17_SYNC_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t errs = 0U;
for (uint8_t i = 0U; i < M17_SYNC_BYTES_LENGTH; i++)
for (uint8_t i = 0U; i < M17_SYNC_LENGTH_BYTES; i++)
errs += countBits8(sync[i] ^ syncBytes[i]);
if (errs <= maxBitErrs) {
@@ -437,8 +445,8 @@ void CM17RX::writeRSSILinkSetup(uint8_t* data)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[121U] = (rssi >> 8) & 0xFFU;
data[122U] = (rssi >> 0) & 0xFFU;
data[49U] = (rssi >> 8) & 0xFFU;
data[50U] = (rssi >> 0) & 0xFFU;
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 3U);
} else {
@@ -458,8 +466,8 @@ void CM17RX::writeRSSIStream(uint8_t* data)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[121U] = (rssi >> 8) & 0xFFU;
data[122U] = (rssi >> 0) & 0xFFU;
data[49U] = (rssi >> 8) & 0xFFU;
data[50U] = (rssi >> 0) & 0xFFU;
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 3U);
} else {
@@ -473,26 +481,5 @@ void CM17RX::writeRSSIStream(uint8_t* data)
m_rssiCount = 0U;
}
void CM17RX::writeRSSIPacket(uint8_t* data)
{
#if defined(SEND_RSSI_DATA)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[121U] = (rssi >> 8) & 0xFFU;
data[122U] = (rssi >> 0) & 0xFFU;
serial.writeM17Packet(data, M17_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeM17Packet(data, M17_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeM17Packet(data, M17_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
#endif
+1 -3
View File
@@ -28,8 +28,7 @@
enum M17RX_STATE {
M17RXS_NONE,
M17RXS_LINK_SETUP,
M17RXS_STREAM,
M17RXS_PACKET
M17RXS_STREAM
};
class CM17RX {
@@ -70,7 +69,6 @@ private:
void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
void writeRSSILinkSetup(uint8_t* data);
void writeRSSIStream(uint8_t* data);
void writeRSSIPacket(uint8_t* data);
};
#endif
+6 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
@@ -33,10 +33,10 @@ static q15_t RRC_0_5_FILTER[] = {0, 0, 0, 0, -290, -174, 142, 432, 438, 90, -387
438, 432, 142, -174, -290}; // numTaps = 45, L = 5
const uint16_t RRC_0_5_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
const q15_t M17_LEVELA = 1683;
const q15_t M17_LEVELB = 561;
const q15_t M17_LEVELC = -561;
const q15_t M17_LEVELD = -1683;
const q15_t M17_LEVELA = 1481;
const q15_t M17_LEVELB = 494;
const q15_t M17_LEVELC = -494;
const q15_t M17_LEVELD = -1481;
const uint8_t M17_START_SYNC = 0x77U;
const uint8_t M17_END_SYNC = 0xFFU;
@@ -160,7 +160,7 @@ void CM17TX::writeByte(uint8_t c)
void CM17TX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
+8 -5
View File
@@ -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"
@@ -41,10 +41,6 @@ bool m_duplex = true;
bool m_tx = false;
bool m_dcd = false;
#if defined(MODE_OLED)
CI2COLED oled;
#endif
#if defined(MODE_DSTAR)
CDStarRX dstarRX;
CDStarTX dstarTX;
@@ -86,6 +82,8 @@ CCalNXDN calNXDN;
#if defined(MODE_M17)
CM17RX m17RX;
CM17TX m17TX;
CCalM17 calM17;
#endif
#if defined(MODE_POCSAG)
@@ -196,6 +194,11 @@ void loop()
calNXDN.process();
#endif
#if defined(MODE_M17)
if (m_modemState == STATE_M17CAL)
calM17.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process();
+7 -4
View File
@@ -38,10 +38,6 @@ bool m_duplex = true;
bool m_tx = false;
bool m_dcd = false;
#if defined(MODE_OLED)
CI2COLED oled;
#endif
#if defined(MODE_DSTAR)
CDStarRX dstarRX;
CDStarTX dstarTX;
@@ -83,6 +79,8 @@ CCalNXDN calNXDN;
#if defined(MODE_M17)
CM17RX m17RX;
CM17TX m17TX;
CCalM17 calM17;
#endif
#if defined(MODE_POCSAG)
@@ -193,6 +191,11 @@ void loop()
calNXDN.process();
#endif
#if defined(MODE_M17)
if (m_modemState == STATE_M17CAL)
calM17.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process();
Binary file not shown.
-165
View File
@@ -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 -1
View File
@@ -175,7 +175,7 @@ void CNXDNTX::writeByte(uint8_t c)
void CNXDNTX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
+1 -1
View File
@@ -173,7 +173,7 @@ void CP25TX::writeByte(uint8_t c)
void CP25TX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
+32 -14
View File
@@ -1,17 +1,35 @@
This is the source code of the MMDVM firmware that supports D-Star, DMR,
System Fusion, P25, NXDN, POCSAG, and FM modes.
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 clock speed
greater than 70 MHz, and access to at least one analogue to digital converter
and one digital to analogue converter.
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 being supplied via the ARM GCC compiler. The Teensy support
uses Teensyduino.
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.
This software is licenced under the GPL v2 and is intended for amateur and
educational use only. Use of this software for commercial purposes is strictly
forbidden.
This software is licenced under the GPL v2 and is primarily intended for amateur and educational use.
Portions of the ARM support code include the following copyright:
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.
-47
View File
@@ -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
+2 -5
View File
@@ -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
@@ -74,4 +71,4 @@ private:
#include "RingBuffer.impl.h"
#endif
#endif
Submodule STM32F10X_Lib deleted from 417e0c2f4a
+3 -1
View File
@@ -1,5 +1,7 @@
/*
* source: http://mightydevices.com/?p=144
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
*
* Source: http://mightydevices.com/?p=144
*
* 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
+206 -99
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013,2015-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2013,2015-2021,2023 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
@@ -67,10 +67,12 @@ const uint8_t MMDVM_M17_LINK_SETUP = 0x45U;
const uint8_t MMDVM_M17_STREAM = 0x46U;
const uint8_t MMDVM_M17_PACKET = 0x47U;
const uint8_t MMDVM_M17_LOST = 0x48U;
const uint8_t MMDVM_M17_EOT = 0x49U;
const uint8_t MMDVM_POCSAG_DATA = 0x50U;
const uint8_t MMDVM_AX25_DATA = 0x55U;
const uint8_t MMDVM_AX25_DATA_EX = 0x56U;
const uint8_t MMDVM_FM_PARAMS1 = 0x60U;
const uint8_t MMDVM_FM_PARAMS2 = 0x61U;
@@ -79,11 +81,13 @@ const uint8_t MMDVM_FM_PARAMS4 = 0x63U;
const uint8_t MMDVM_FM_DATA = 0x65U;
const uint8_t MMDVM_FM_STATUS = 0x66U;
const uint8_t MMDVM_FM_EOT = 0x67U;
const uint8_t MMDVM_FM_RSSI = 0x68U;
const uint8_t MMDVM_ACK = 0x70U;
const uint8_t MMDVM_NAK = 0x7FU;
const uint8_t MMDVM_SERIAL_DATA = 0x80U;
const uint8_t MMDVM_I2C_DATA = 0x81U;
const uint8_t MMDVM_TRANSPARENT = 0x90U;
const uint8_t MMDVM_QSO_INFO = 0x91U;
@@ -133,38 +137,36 @@ const uint8_t PROTOCOL_VERSION = 2U;
const int MAX_SERIAL_DATA = 250;
const uint16_t MAX_SERIAL_COUNT = 100U;
CSerialPort::CSerialPort() :
m_buffer(),
m_ptr(0U),
m_len(0U),
m_debug(false),
m_serialData(),
m_lastSerialAvail(0),
m_lastSerialAvailCount(0U)
{
}
void CSerialPort::sendACK()
void CSerialPort::sendACK(uint8_t type)
{
uint8_t reply[4U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 4U;
reply[2U] = MMDVM_ACK;
reply[3U] = m_buffer[2U];
reply[3U] = type;
writeInt(1U, reply, 4);
}
void CSerialPort::sendNAK(uint8_t err)
void CSerialPort::sendNAK(uint8_t type, uint8_t err)
{
uint8_t reply[5U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 5U;
reply[2U] = MMDVM_NAK;
reply[3U] = m_buffer[2U];
reply[3U] = type;
reply[4U] = err;
writeInt(1U, reply, 5);
@@ -280,27 +282,26 @@ void CSerialPort::getStatus()
reply[13U] = 0U;
#endif
reply[14U] = 0x00U;
reply[15U] = 0x00U;
#if defined(MODE_POCSAG)
if (m_pocsagEnable)
reply[16U] = pocsagTX.getSpace();
reply[14U] = pocsagTX.getSpace();
else
reply[16U] = 0U;
reply[14U] = 0U;
#else
reply[16U] = 0U;
reply[14U] = 0U;
#endif
#if defined(MODE_AX25)
if (m_ax25Enable)
reply[17U] = ax25TX.getSpace();
reply[15U] = ax25TX.getSpace();
else
reply[17U] = 0U;
reply[15U] = 0U;
#else
reply[17U] = 0U;
reply[15U] = 0U;
#endif
reply[16U] = 0x00U;
reply[17U] = 0x00U;
reply[18U] = 0x00U;
reply[19U] = 0x00U;
@@ -373,22 +374,41 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
bool rxInvert = (data[0U] & 0x01U) == 0x01U;
bool txInvert = (data[0U] & 0x02U) == 0x02U;
bool pttInvert = (data[0U] & 0x04U) == 0x04U;
#if defined(MODE_YSF)
bool ysfLoDev = (data[0U] & 0x08U) == 0x08U;
#endif
bool useCOSAsLockout = (data[0U] & 0x20U) == 0x20U;
bool simplex = (data[0U] & 0x80U) == 0x80U;
m_debug = (data[0U] & 0x10U) == 0x10U;
#if defined(MODE_DSTAR)
bool dstarEnable = (data[1U] & 0x01U) == 0x01U;
#endif
#if defined(MODE_DMR)
bool dmrEnable = (data[1U] & 0x02U) == 0x02U;
#endif
#if defined(MODE_YSF)
bool ysfEnable = (data[1U] & 0x04U) == 0x04U;
#endif
#if defined(MODE_P25)
bool p25Enable = (data[1U] & 0x08U) == 0x08U;
#endif
#if defined(MODE_NXDN)
bool nxdnEnable = (data[1U] & 0x10U) == 0x10U;
#endif
#if defined(MODE_FM)
bool fmEnable = (data[1U] & 0x20U) == 0x20U;
#endif
#if defined(MODE_M17)
bool m17Enable = (data[1U] & 0x40U) == 0x40U;
#endif
#if defined(MODE_POCSAG)
bool pocsagEnable = (data[2U] & 0x01U) == 0x01U;
#endif
#if defined(MODE_AX25)
bool ax25Enable = (data[2U] & 0x02U) == 0x02U;
#endif
uint8_t txDelay = data[3U];
if (txDelay > 50U)
@@ -396,7 +416,9 @@ 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_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_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)
@@ -479,17 +501,28 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
uint8_t fmTXLevel = data[16U];
uint8_t ax25TXLevel = data[17U];
#if defined(MODE_YSF)
uint8_t ysfTXHang = data[20U];
#endif
#if defined(MODE_P25)
uint8_t p25TXHang = data[21U];
#endif
#if defined(MODE_NXDN)
uint8_t nxdnTXHang = data[22U];
#endif
#if defined(MODE_M17)
uint8_t m17TXHang = data[23U];
#endif
#if defined(MODE_DMR)
uint8_t colorCode = data[26U];
if (colorCode > 15U)
return 4U;
uint8_t dmrDelay = data[27U];
#endif
#if defined(MODE_AX25)
int8_t ax25RXTwist = int8_t(data[28U]) - 128;
if (ax25RXTwist < -4 || ax25RXTwist > 10)
return 4U;
@@ -497,6 +530,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
uint8_t ax25TXDelay = data[29U];
uint8_t ax25SlotTime = data[30U];
uint8_t ax25PPersist = data[31U];
#endif
setMode(modemState);
@@ -619,6 +653,7 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length)
uint8_t hangTime = data[7U];
uint8_t accessMode = data[8U] & 0x0FU;
bool linkMode = (data[8U] & 0x20U) == 0x20U;
bool noiseSquelch = (data[8U] & 0x40U) == 0x40U;
bool cosInvert = (data[8U] & 0x80U) == 0x80U;
@@ -629,7 +664,7 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length)
uint8_t squelchHighThreshold = data[12U];
uint8_t squelchLowThreshold = data[13U];
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, cosInvert, noiseSquelch, squelchHighThreshold, squelchLowThreshold, rfAudioBoost, maxDev, rxLevel);
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, linkMode, cosInvert, noiseSquelch, squelchHighThreshold, squelchLowThreshold, rfAudioBoost, maxDev, rxLevel);
}
uint8_t CSerialPort::setFMParams4(const uint8_t* data, uint16_t length)
@@ -662,7 +697,9 @@ 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_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_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)
@@ -803,6 +840,9 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
case STATE_POCSAGCAL:
DEBUG1("Mode set to POCSAG Calibrate");
break;
case STATE_M17CAL:
DEBUG1("Mode set to M17 Calibrate");
break;
default: // STATE_IDLE
DEBUG1("Mode set to Idle");
break;
@@ -856,7 +896,14 @@ 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);
#endif
}
@@ -911,20 +958,6 @@ void CSerialPort::process()
}
#if defined(SERIAL_REPEATER)
// Write any outgoing serial data
uint16_t serialSpace = m_serialData.getData();
if (serialSpace > 0U) {
int avail = availableForWriteInt(3U);
if (avail < serialSpace)
serialSpace = avail;
for (uint16_t i = 0U; i < serialSpace; i++) {
uint8_t c = 0U;
m_serialData.get(c);
writeInt(3U, &c, 1U);
}
}
// Read any incoming serial data, and send out in batches
int serialAvail = availableForReadInt(3U);
if ((serialAvail > 0 && serialAvail == m_lastSerialAvail && m_lastSerialAvailCount >= MAX_SERIAL_COUNT) || (serialAvail >= MAX_SERIAL_DATA)) {
@@ -935,7 +968,7 @@ void CSerialPort::process()
}
writeSerialData(buffer, serialAvail - m_lastSerialAvail);
m_lastSerialAvailCount = 0U;
} else if (serialAvail > 0U && serialAvail == m_lastSerialAvail) {
} else if (serialAvail > 0 && serialAvail == m_lastSerialAvail) {
m_lastSerialAvailCount++;
} else {
m_lastSerialAvail = serialAvail;
@@ -960,61 +993,61 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
case MMDVM_SET_CONFIG:
err = setConfig(buffer, length);
if (err == 0U)
sendACK();
sendACK(type);
else
sendNAK(err);
sendNAK(type, err);
break;
case MMDVM_SET_MODE:
err = setMode(buffer, length);
if (err == 0U)
sendACK();
sendACK(type);
else
sendNAK(err);
sendNAK(type, err);
break;
case MMDVM_SET_FREQ:
sendACK();
sendACK(type);
break;
#if defined(MODE_FM)
case MMDVM_FM_PARAMS1:
err = setFMParams1(buffer, length);
if (err == 0U) {
sendACK();
sendACK(type);
} else {
DEBUG2("Received invalid FM params 1", err);
sendNAK(err);
sendNAK(type, err);
}
break;
case MMDVM_FM_PARAMS2:
err = setFMParams2(buffer, length);
if (err == 0U) {
sendACK();
sendACK(type);
} else {
DEBUG2("Received invalid FM params 2", err);
sendNAK(err);
sendNAK(type, err);
}
break;
case MMDVM_FM_PARAMS3:
err = setFMParams3(buffer, length);
if (err == 0U) {
sendACK();
sendACK(type);
} else {
DEBUG2("Received invalid FM params 3", err);
sendNAK(err);
sendNAK(type, err);
}
break;
case MMDVM_FM_PARAMS4:
err = setFMParams4(buffer, length);
if (err == 0U) {
sendACK();
sendACK(type);
} else {
DEBUG2("Received invalid FM params 4", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#else
@@ -1022,7 +1055,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
case MMDVM_FM_PARAMS2:
case MMDVM_FM_PARAMS3:
case MMDVM_FM_PARAMS4:
sendACK();
sendACK(type);
break;
#endif
@@ -1047,15 +1080,19 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
if (m_modemState == STATE_NXDNCAL1K)
err = calNXDN.write(buffer, length);
#endif
#if defined(MODE_M17)
if (m_modemState == STATE_M17CAL)
err = calM17.write(buffer, length);
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL)
err = calPOCSAG.write(buffer, length);
#endif
if (err == 0U) {
sendACK();
sendACK(type);
} else {
DEBUG2("Received invalid calibration data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1065,7 +1102,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
err = cwIdTX.write(buffer, length);
if (err != 0U) {
DEBUG2("Invalid CW Id data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1080,7 +1117,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_DSTAR);
} else {
DEBUG2("Received invalid D-Star header", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1094,7 +1131,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_DSTAR);
} else {
DEBUG2("Received invalid D-Star data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1108,7 +1145,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_DSTAR);
} else {
DEBUG2("Received invalid D-Star EOT", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1126,7 +1163,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_DMR);
} else {
DEBUG2("Received invalid DMR data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1144,7 +1181,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_DMR);
} else {
DEBUG2("Received invalid DMR data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1165,7 +1202,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
}
if (err != 0U) {
DEBUG2("Received invalid DMR start", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1174,7 +1211,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
err = dmrTX.writeShortLC(buffer, length);
if (err != 0U) {
DEBUG2("Received invalid DMR Short LC", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1183,7 +1220,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
err = dmrTX.writeAbort(buffer, length);
if (err != 0U) {
DEBUG2("Received invalid DMR Abort", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1199,7 +1236,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_YSF);
} else {
DEBUG2("Received invalid System Fusion data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1215,7 +1252,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_P25);
} else {
DEBUG2("Received invalid P25 header", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1229,7 +1266,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_P25);
} else {
DEBUG2("Received invalid P25 LDU", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1245,7 +1282,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_NXDN);
} else {
DEBUG2("Received invalid NXDN data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1261,7 +1298,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_M17);
} else {
DEBUG2("Received invalid M17 link setup data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
@@ -1275,11 +1312,11 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_M17);
} else {
DEBUG2("Received invalid M17 stream data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
case MMDVM_M17_PACKET:
case MMDVM_M17_EOT:
if (m_m17Enable) {
if (m_modemState == STATE_IDLE || m_modemState == STATE_M17)
err = m17TX.writeData(buffer, length);
@@ -1288,8 +1325,8 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
if (m_modemState == STATE_IDLE)
setMode(STATE_M17);
} else {
DEBUG2("Received invalid M17 packet data", err);
sendNAK(err);
DEBUG2("Received invalid M17 EOT", err);
sendNAK(type, err);
}
break;
#endif
@@ -1305,7 +1342,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_POCSAG);
} else {
DEBUG2("Received invalid POCSAG data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1321,7 +1358,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
setMode(STATE_FM);
} else {
DEBUG2("Received invalid FM data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1334,7 +1371,7 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
}
if (err != 0U) {
DEBUG2("Received invalid AX.25 data", err);
sendNAK(err);
sendNAK(type, err);
}
break;
#endif
@@ -1345,16 +1382,20 @@ void CSerialPort::processMessage(uint8_t type, const uint8_t* buffer, uint16_t l
break;
#if defined(SERIAL_REPEATER)
case MMDVM_SERIAL_DATA: {
for (uint16_t i = 0U; i < length; i++)
m_serialData.put(buffer[i]);
}
case MMDVM_SERIAL_DATA:
writeInt(3U, buffer, length);
break;
#endif
#if defined(I2C_REPEATER)
case MMDVM_I2C_DATA:
writeInt(10U, buffer, length);
break;
#endif
default:
// Handle this, send a NAK back
sendNAK(1U);
sendNAK(type, 1U);
break;
}
@@ -1681,7 +1722,7 @@ void CSerialPort::writeM17Stream(const uint8_t* data, uint8_t length)
writeInt(1U, reply, count);
}
void CSerialPort::writeM17Packet(const uint8_t* data, uint8_t length)
void CSerialPort::writeM17EOT()
{
if (m_modemState != STATE_M17 && m_modemState != STATE_IDLE)
return;
@@ -1689,19 +1730,13 @@ void CSerialPort::writeM17Packet(const uint8_t* data, uint8_t length)
if (!m_m17Enable)
return;
uint8_t reply[130U];
uint8_t reply[3U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 0U;
reply[2U] = MMDVM_M17_PACKET;
reply[1U] = 3U;
reply[2U] = MMDVM_M17_EOT;
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
reply[1U] = count;
writeInt(1U, reply, count);
writeInt(1U, reply, 3);
}
void CSerialPort::writeM17Lost()
@@ -1740,7 +1775,7 @@ void CSerialPort::writeFMData(const uint8_t* data, uint16_t length)
reply[2U] = (length + 4U) - 255U;
reply[3U] = MMDVM_FM_DATA;
for (uint8_t i = 0U; i < length; i++)
for (uint16_t i = 0U; i < length; i++)
reply[i + 4U] = data[i];
writeInt(1U, reply, length + 4U);
@@ -1748,7 +1783,7 @@ void CSerialPort::writeFMData(const uint8_t* data, uint16_t length)
reply[1U] = length + 3U;
reply[2U] = MMDVM_FM_DATA;
for (uint8_t i = 0U; i < length; i++)
for (uint16_t i = 0U; i < length; i++)
reply[i + 3U] = data[i];
writeInt(1U, reply, length + 3U);
@@ -1773,6 +1808,25 @@ void CSerialPort::writeFMStatus(uint8_t status)
writeInt(1U, reply, 4U);
}
void CSerialPort::writeFMRSSI(uint16_t rssi)
{
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
return;
if (!m_fmEnable)
return;
uint8_t reply[10U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 5U;
reply[2U] = MMDVM_FM_RSSI;
reply[3U] = (rssi >> 8) & 0xFFU;
reply[4U] = (rssi >> 0) & 0xFFU;
writeInt(1U, reply, 5U);
}
void CSerialPort::writeFMEOT()
{
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
@@ -1809,7 +1863,7 @@ void CSerialPort::writeAX25Data(const uint8_t* data, uint16_t length)
reply[2U] = (length + 4U) - 255U;
reply[3U] = MMDVM_AX25_DATA;
for (uint8_t i = 0U; i < length; i++)
for (uint16_t i = 0U; i < length; i++)
reply[i + 4U] = data[i];
writeInt(1U, reply, length + 4U);
@@ -1817,12 +1871,50 @@ void CSerialPort::writeAX25Data(const uint8_t* data, uint16_t length)
reply[1U] = length + 3U;
reply[2U] = MMDVM_AX25_DATA;
for (uint8_t i = 0U; i < length; i++)
for (uint16_t i = 0U; i < length; i++)
reply[i + 3U] = data[i];
writeInt(1U, reply, length + 3U);
}
}
void CSerialPort::writeAX25DataEx(uint16_t rssi, const uint8_t* data, uint16_t length)
{
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
return;
if (!m_ax25Enable)
return;
uint8_t reply[512U];
reply[0U] = MMDVM_FRAME_START;
if (length > 250U) {
reply[1U] = 0U;
reply[2U] = (length + 6U) - 255U;
reply[3U] = MMDVM_AX25_DATA_EX;
reply[4U] = (rssi >> 8) & 0xFFU;
reply[5U] = (rssi >> 0) & 0xFFU;
for (uint16_t i = 0U; i < length; i++)
reply[i + 6U] = data[i];
writeInt(1U, reply, length + 6U);
} else {
reply[1U] = length + 5U;
reply[2U] = MMDVM_AX25_DATA_EX;
reply[3U] = (rssi >> 8) & 0xFFU;
reply[4U] = (rssi >> 0) & 0xFFU;
for (uint16_t i = 0U; i < length; i++)
reply[i + 5U] = data[i];
writeInt(1U, reply, length + 5U);
}
}
#endif
#if defined(SERIAL_REPEATER)
@@ -1844,6 +1936,25 @@ void CSerialPort::writeSerialData(const uint8_t* data, uint8_t length)
}
#endif
#if defined(I2C_REPEATER)
void CSerialPort::writeI2CData(const uint8_t* data, uint8_t length)
{
uint8_t reply[255U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 0U;
reply[2U] = MMDVM_I2C_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);
}
#endif
void CSerialPort::writeCalData(const uint8_t* data, uint8_t length)
{
if (m_modemState != STATE_DSTARCAL)
@@ -2016,9 +2127,6 @@ void CSerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n
void CSerialPort::writeDebugDump(const uint8_t* data, uint16_t length)
{
if (length > 500U)
length = 500U;
uint8_t reply[512U];
reply[0U] = MMDVM_FRAME_START;
@@ -2028,7 +2136,7 @@ void CSerialPort::writeDebugDump(const uint8_t* data, uint16_t length)
reply[2U] = (length + 4U) - 255U;
reply[3U] = MMDVM_DEBUG_DUMP;
for (uint8_t i = 0U; i < length; i++)
for (uint16_t i = 0U; i < length; i++)
reply[i + 4U] = data[i];
writeInt(1U, reply, length + 4U);
@@ -2036,10 +2144,9 @@ void CSerialPort::writeDebugDump(const uint8_t* data, uint16_t length)
reply[1U] = length + 3U;
reply[2U] = MMDVM_DEBUG_DUMP;
for (uint8_t i = 0U; i < length; i++)
for (uint16_t i = 0U; i < length; i++)
reply[i + 3U] = data[i];
writeInt(1U, reply, length + 3U);
}
}
+10 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 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
@@ -67,17 +67,19 @@ public:
#if defined(MODE_M17)
void writeM17LinkSetup(const uint8_t* data, uint8_t length);
void writeM17Stream(const uint8_t* data, uint8_t length);
void writeM17Packet(const uint8_t* data, uint8_t length);
void writeM17Lost();
void writeM17EOT();
#endif
#if defined(MODE_AX25)
void writeAX25Data(const uint8_t* data, uint16_t length);
void writeAX25DataEx(uint16_t rssi, const uint8_t* data, uint16_t length);
#endif
#if defined(MODE_FM)
void writeFMData(const uint8_t* data, uint16_t length);
void writeFMStatus(uint8_t status);
void writeFMRSSI(uint16_t rssi);
void writeFMEOT();
#endif
@@ -85,6 +87,10 @@ public:
void writeSerialData(const uint8_t* data, uint8_t length);
#endif
#if defined(I2C_REPEATER)
void writeI2CData(const uint8_t* data, uint8_t length);
#endif
void writeCalData(const uint8_t* data, uint8_t length);
void writeRSSIData(const uint8_t* data, uint8_t length);
@@ -100,12 +106,11 @@ private:
uint16_t m_ptr;
uint16_t m_len;
bool m_debug;
CRingBuffer<uint8_t> m_serialData;
int m_lastSerialAvail;
uint16_t m_lastSerialAvailCount;
void sendACK();
void sendNAK(uint8_t err);
void sendACK(uint8_t type);
void sendNAK(uint8_t type, uint8_t err);
void getStatus();
void getVersion();
uint8_t setConfig(const uint8_t* data, uint16_t length);
+1 -1
View File
@@ -332,7 +332,7 @@ int CSerialPort::availableForReadInt(uint8_t n)
switch (n) {
case 1U:
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
return m_USART3.availble();//AvailUSART3();
return m_USART3.available();//AvailUSART3();
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F7_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
return m_USART1.available();//AvailUSART1();
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
-170
View File
@@ -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
+2
View File
@@ -1,4 +1,6 @@
/*
* Copyright (C) 2017 by Chris Huitema
*
* 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
-3
View File
@@ -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
+3 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2021,2022,2023 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,6 +19,7 @@
#if !defined(VERSION_H)
#define VERSION_H
#define VERSION "20210508"
#define VERSION "20230802"
#endif
+1 -1
View File
@@ -166,7 +166,7 @@ void CYSFTX::writeByte(uint8_t c)
void CYSFTX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t outBuffer[YSF_RADIO_SYMBOL_LENGTH * 4U];
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
+4 -4
View File
@@ -33,7 +33,7 @@ DSTAR PB6 output
DMR PB5 output
YSF PB7 output
POCSAG PC10 output
FM PC11 output
FM PB14 output
RX PB0 analog input
RSSI PB1 analog input
@@ -83,9 +83,9 @@ EXT_CLK PA15 input
#define PORT_POCSAG GPIOC
#define RCC_Per_POCSAG RCC_AHB1Periph_GPIOC
#define PIN_FM GPIO_Pin_11
#define PORT_FM GPIOC
#define RCC_Per_FM RCC_AHB1Periph_GPIOC
#define PIN_FM GPIO_Pin_14
#define PORT_FM GPIOB
#define RCC_Per_FM RCC_AHB1Periph_GPIOB
#define PIN_EXT_CLK GPIO_Pin_15
#define SRC_EXT_CLK GPIO_PinSource15
+2 -2
View File
@@ -20,7 +20,7 @@
#define _PINS_F7_STM32DVM_V5_H
/*
Pin definitions for STM32F4 STM32-DVM rev 5 Board:
Pin definitions for STM32F7 STM32-DVM rev 5 Board:
COS PB13 input
PTT PB12 output
@@ -33,6 +33,7 @@ DSTAR PB6 output
DMR PB5 output
YSF PB7 output
POCSAG PC10 output (Not Valid)
FM PB14 output
RX PB0 analog input
RSSI PB1 analog input
@@ -45,7 +46,6 @@ EXT_CLK PA15 input
#define PORT_COS GPIOB
#define RCC_Per_COS RCC_AHB1Periph_GPIOB
#define PIN_PTT GPIO_Pin_12
#define PORT_PTT GPIOB
#define RCC_Per_PTT RCC_AHB1Periph_GPIOB
-187
View File
@@ -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")
}
-427
View File
@@ -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
-227
View File
@@ -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>&copy; 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****/