From 762482f6f58c1fba5761882c72833fc692b4e8ed Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 14 Nov 2016 11:41:58 +0000 Subject: [PATCH 1/6] Include the Teensy 3.5 as a supported platform. --- IOTeensy.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/IOTeensy.cpp b/IOTeensy.cpp index 1cd90f9..b59e3a4 100644 --- a/IOTeensy.cpp +++ b/IOTeensy.cpp @@ -20,10 +20,8 @@ #include "Globals.h" #include "IO.h" -#if defined(__MK20DX256__) || defined(__MK66FX1M0__) +#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) -// A Teensy 3.1/3.2 -#if defined(__MK20DX256__) #define PIN_LED 13 #define PIN_COS 52 #define PIN_PTT 23 @@ -35,20 +33,6 @@ #define PIN_ADC 5 // A0 #define PIN_RSSI 8 // A2 -// A Teensy 3.6 -#elif defined(__MK66FX1M0__) -#define PIN_LED 13 -#define PIN_COS 52 -#define PIN_PTT 23 -#define PIN_COSLED 22 -#define PIN_DSTAR 9 -#define PIN_DMR 8 -#define PIN_YSF 7 -#define PIN_P25 6 -#define PIN_ADC 5 // A0 -#define PIN_RSSI 8 // A2 -#endif - #define PDB_CH0C1_TOS 0x0100 #define PDB_CH0C1_EN 0x01 @@ -231,4 +215,3 @@ void CIO::setP25Int(bool on) } #endif - From f946824639adbd04eb006be2c9255484bdcc15dc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 14 Nov 2016 11:44:38 +0000 Subject: [PATCH 2/6] Add more info about the new platforms. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3bfea68..030f94c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion and P25. -It runs on the Arduino Due, and the STM32F4xx platforms. Support for the Teensy (3.1/3.2 and 3.6) is being added. +It runs on the Arduino Due and the ST-Micro STM32F4xx platforms. Support for the Teensy (3.1/3.2 and 3.5/3.6) is being added. -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. +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 Coocox IDE with ARM GCC. The Teensy support is via the latest beta of 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. From de289c125826164a0b9818d3d7524d5bac804c91 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 14 Nov 2016 21:47:38 +0000 Subject: [PATCH 3/6] Further refinement of the Teensy IO. --- IOTeensy.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/IOTeensy.cpp b/IOTeensy.cpp index b59e3a4..55c56df 100644 --- a/IOTeensy.cpp +++ b/IOTeensy.cpp @@ -33,8 +33,8 @@ #define PIN_ADC 5 // A0 #define PIN_RSSI 8 // A2 -#define PDB_CH0C1_TOS 0x0100 -#define PDB_CH0C1_EN 0x01 +#define PDB_CHnC1_TOS 0x0100 +#define PDB_CHnC1_EN 0x0001 const uint16_t DC_OFFSET = 2048U; @@ -84,9 +84,8 @@ void CIO::startInt() ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb ADC0_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger - ADC0_SC3 = ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples + ADC0_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples - ADC0_SC3 = ADC_SC3_CAL; // Begin calibration while ((ADC0_SC3 & ADC_SC3_CAL) == ADC_SC3_CAL) // Wait for calibration ; @@ -103,9 +102,8 @@ void CIO::startInt() ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time ADC1_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb ADC1_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger - ADC1_SC3 = ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples + ADC1_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples - ADC1_SC3 = ADC_SC3_CAL; // Begin calibration while ((ADC1_SC3 & ADC_SC3_CAL) == ADC_SC3_CAL) // Wait for calibration ; @@ -117,20 +115,16 @@ void CIO::startInt() NVIC_ENABLE_IRQ(IRQ_ADC1); #endif - // Setup PDB for ADC0 at 24 kHz + // Setup PDB for ADC0 (and ADC1) at 24 kHz SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock -#if F_BUS == 60000000 - // 60 MHz for the Teensy 3.5/3.6 - PDB0_MOD = 2500 - 1; // Timer period for 60 MHz bus -#else - // 48 MHz for the Teensy 3.1/3.2 - PDB0_MOD = 2000 - 1; // Timer period for 48 MHz bus -#endif + PDB0_MOD = F_BUS / 24000; // Timer period PDB0_IDLY = 0; // Interrupt delay - PDB0_CH0C1 = PDB_CH0C1_TOS | PDB_CH0C1_EN; // Enable pre-trigger - PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE | - PDB_SC_CONT | PDB_SC_PRESCALER(7) | PDB_SC_MULT(1) | - PDB_SC_LDOK; + PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0 +#if defined(SEND_RSSI_DATA) + PDB0_CH1C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-t9rigger for ADC1 +#endif + PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode + PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_LDOK; // No prescaling PDB0_SC |= PDB_SC_SWTRIG; // Software trigger (reset and restart counter) NVIC_ENABLE_IRQ(IRQ_PDB); From cc051152809fe06c6643d1121891f95b3f08fe8c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 14 Nov 2016 22:39:14 +0000 Subject: [PATCH 4/6] Enable the ADC clocks. --- IOTeensy.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/IOTeensy.cpp b/IOTeensy.cpp index 55c56df..385b7e2 100644 --- a/IOTeensy.cpp +++ b/IOTeensy.cpp @@ -80,38 +80,40 @@ void CIO::startInt() #endif // Initialise ADC0 - ADC0_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | ADC_CFG1_MODE(1) | - ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time - ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb - ADC0_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger - ADC0_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples + SIM_SCGC6 |= SIM_SCGC6_ADC0; + ADC0_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | ADC_CFG1_MODE(1) | + ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time + ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb + ADC0_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger + ADC0_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples while ((ADC0_SC3 & ADC_SC3_CAL) == ADC_SC3_CAL) // Wait for calibration ; uint16_t sum0 = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0; // Plus side gain sum0 = (sum0 / 2U) | 0x8000U; - ADC0_PG = sum0; + ADC0_PG = sum0; ADC0_SC1A = ADC_SC1_AIEN | PIN_ADC; // Enable ADC interrupt, use A0 NVIC_ENABLE_IRQ(IRQ_ADC0); #if defined(SEND_RSSI_DATA) // Initialise ADC1 - ADC1_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | ADC_CFG1_MODE(1) | - ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time - ADC1_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb - ADC1_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger - ADC1_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples + SIM_SCGC3 |= SIM_SCGC3_ADC1; + ADC1_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | ADC_CFG1_MODE(1) | + ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time + ADC1_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb + ADC1_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger + ADC1_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples while ((ADC1_SC3 & ADC_SC3_CAL) == ADC_SC3_CAL) // Wait for calibration ; uint16_t sum1 = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; // Plus side gain sum1 = (sum1 / 2U) | 0x8000U; - ADC1_PG = sum1; + ADC1_PG = sum1; - ADC1_SC1A = ADC_SC1_AIEN | PIN_RSSI; // Enable ADC interrupt, use A2 + ADC1_SC1A = ADC_SC1_AIEN | PIN_RSSI; // Enable ADC interrupt, use A2 NVIC_ENABLE_IRQ(IRQ_ADC1); #endif From dd5940fe2e042760f14eeeb1dad3002694ba3610 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 15 Nov 2016 06:27:46 +0000 Subject: [PATCH 5/6] Add the Teensy 3.5 as a supported platform. --- Globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Globals.h b/Globals.h index 807417e..9e18082 100644 --- a/Globals.h +++ b/Globals.h @@ -36,7 +36,7 @@ #if defined(__SAM3X8E__) #define ARM_MATH_CM3 -#elif defined(STM32F4XX) || defined(STM32F4) || defined(__MK20DX256__) || defined(__MK66FX1M0__) +#elif defined(STM32F4XX) || defined(STM32F4) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) #define ARM_MATH_CM4 #else #error "Unknown processor type" From 59d93b5a6f61fb5a1e6445aeb5753d1e69bdacec Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 15 Nov 2016 08:07:24 +0000 Subject: [PATCH 6/6] First attempt at using external clock for Teensy ADC. --- IOTeensy.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/IOTeensy.cpp b/IOTeensy.cpp index 385b7e2..a7d1806 100644 --- a/IOTeensy.cpp +++ b/IOTeensy.cpp @@ -50,6 +50,21 @@ extern "C" { io.interrupt(1U); } #endif + +#if defined(EXTERNAL_OSC) + void ftm0_isr() + { + FTM0_CNT = 0; // Reset count value + if ((FTM0_SC & FTM_SC_TOF) == FTM_SC_TOF) // Read the timer overflow flag (TOF in FTM0_SC) + FTM0_SC &= ~FTM_SC_TOF; // If set, clear overflow flag + + // Kick off the ADCs with interrupt at the end of conversion + ADC0_SC1A = ADC_SC1_AIEN | PIN_ADC; +#if defined(SEND_RSSI_DATA) + ADC1_SC1A = ADC_SC1_AIEN | PIN_RSSI; +#endif + } +#endif } void CIO::initInt() @@ -84,7 +99,11 @@ void CIO::startInt() ADC0_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | ADC_CFG1_MODE(1) | ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb +#if defined(EXTERNAL_OSC) + ADC0_SC2 = ADC_SC2_REFSEL(1); // Voltage ref internal, software trigger +#else ADC0_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger +#endif ADC0_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples while ((ADC0_SC3 & ADC_SC3_CAL) == ADC_SC3_CAL) // Wait for calibration @@ -94,7 +113,10 @@ void CIO::startInt() sum0 = (sum0 / 2U) | 0x8000U; ADC0_PG = sum0; - ADC0_SC1A = ADC_SC1_AIEN | PIN_ADC; // Enable ADC interrupt, use A0 +#if !defined(EXTERNAL_OSC) + ADC0_SC1A = ADC_SC1_AIEN | PIN_ADC; // Enable ADC interrupt, use A0 +#endif + NVIC_ENABLE_IRQ(IRQ_ADC0); #if defined(SEND_RSSI_DATA) @@ -103,7 +125,11 @@ void CIO::startInt() ADC1_CFG1 = ADC_CFG1_ADIV(1) | ADC_CFG1_ADICLK(1) | ADC_CFG1_MODE(1) | ADC_CFG1_ADLSMP; // Single-ended 12 bits, long sample time ADC1_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(2); // Select channels ADxxxb +#if defined(EXTERNAL_OSC) + ADC1_SC2 = ADC_SC2_REFSEL(1); // Voltage ref internal, software trigger +#else ADC1_SC2 = ADC_SC2_REFSEL(1) | ADC_SC2_ADTRG; // Voltage ref internal, hardware trigger +#endif ADC1_SC3 = ADC_SC3_CAL | ADC_SC3_AVGE | ADC_SC3_AVGS(0); // Enable averaging, 4 samples while ((ADC1_SC3 & ADC_SC3_CAL) == ADC_SC3_CAL) // Wait for calibration @@ -113,22 +139,34 @@ void CIO::startInt() sum1 = (sum1 / 2U) | 0x8000U; ADC1_PG = sum1; - ADC1_SC1A = ADC_SC1_AIEN | PIN_RSSI; // Enable ADC interrupt, use A2 +#if !defined(EXTERNAL_OSC) + ADC1_SC1A = ADC_SC1_AIEN | PIN_RSSI; // Enable ADC interrupt, use A2 +#endif + NVIC_ENABLE_IRQ(IRQ_ADC1); #endif +#if defined(EXTERNAL_OSC) + // Set up for an external oscillator input + SIM_SCGC6 |= SIM_SCGC6_FTM0; + FTM0_MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN; + FTM0_MOD = EXTERNAL_OSC / 24000; + FTM0_CNTIN = 0; + FTM0_SC = FTM_SC_TOIE | FTM_SC_CLKS(3); // External clock, overflow interrupts, no prescaling + NVIC_ENABLE_IRQ(IRQ_FTM0); +#else // Setup PDB for ADC0 (and ADC1) at 24 kHz - SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock - PDB0_MOD = F_BUS / 24000; // Timer period - PDB0_IDLY = 0; // Interrupt delay - PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0 + SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock + PDB0_MOD = F_BUS / 24000; // Timer period + PDB0_IDLY = 0; // Interrupt delay + PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0 #if defined(SEND_RSSI_DATA) - PDB0_CH1C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-t9rigger for ADC1 + PDB0_CH1C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-t9rigger for ADC1 +#endif + PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode + PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_LDOK; // No prescaling + PDB0_SC |= PDB_SC_SWTRIG; // Software trigger (reset and restart counter) #endif - PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode - PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_LDOK; // No prescaling - PDB0_SC |= PDB_SC_SWTRIG; // Software trigger (reset and restart counter) - NVIC_ENABLE_IRQ(IRQ_PDB); // Initialise the DAC SIM_SCGC2 |= SIM_SCGC2_DAC0;