teensy3056
Active member
I am trying to take in an signal via the ADC0 and send it out via TPM1. The ADC works, the TPM1, specifically the selected clock, OSCERCLK, does not.
In the following code, 3 files, the configuration is in Definitions.cpp. The rest is included for completeness. The pdf. page numbers refer to the MK66FX1M0 Manual
The problems:
1. I want the OSCERCLK to be connected to Teensy 3.6 pin 9, and expect to see a frequency of 2 MHz. Instead I am measuring 30 Hz (not kHz, not MHz, Hz) with an oscilloscope.
2. The TPM1 output is connected to Teensy pin 16 and has the correct duty cycle for the analog voltage input. However, the frequency of the PWM signal is 1 Hz (not kHz, not MHz, Hz).
Teensy_Sound_Processing_B.ino:
Definitions.h
Definitions.cpp
The output from this project is:
I am using a potentiometer wired as a voltage divider to divide the 3.3 VDC Teensy voltage as an input to the ADC. This is working.
TPM1 is supposed to be using OSCERCLK divided by 8 from 16 MHz to 2 MHz.
Again, the problems:
1. I want the OSCERCLK to be connected to Teensy 3.6 pin 9, and expect to see a frequency of 2 MHz. Instead I am measuring 30 Hz (not kHz, not MHz, Hz) with an oscilloscope.
2. The TPM1 output is connected to Teensy pin 16 and has the correct duty cycle for the analog voltage input. However, the frequency of the PWM signal is 1 Hz (not kHz, not MHz, Hz).
My relevant configuration code is in Definitions.cpp and begins after the "// TPM1 function declarations" comment.
Any help would be appreciated.
Thanks.
In the following code, 3 files, the configuration is in Definitions.cpp. The rest is included for completeness. The pdf. page numbers refer to the MK66FX1M0 Manual
The problems:
1. I want the OSCERCLK to be connected to Teensy 3.6 pin 9, and expect to see a frequency of 2 MHz. Instead I am measuring 30 Hz (not kHz, not MHz, Hz) with an oscilloscope.
2. The TPM1 output is connected to Teensy pin 16 and has the correct duty cycle for the analog voltage input. However, the frequency of the PWM signal is 1 Hz (not kHz, not MHz, Hz).
Teensy_Sound_Processing_B.ino:
Code:
/*
Name: Teensy_Sound_Processing_B_09.ino
*/
//*****************************************************************************
#include "Definitions.h"
//*****************************************************************************
void setup() {
Serial.begin(115200);
Serial.printf("\n1. Serial print ready.\n");
Serial.printf("2. Serial print ready.\n");
// LED pin
pinMode(13, OUTPUT);
Configure_ADC();
Configure_TPM1();
//Serial.printf("ADC0_SC2 = 0x%X\n", ADC0_SC2);
attachInterruptVector(IRQ_ADC0, ISR_ADC0);
NVIC_ENABLE_IRQ(IRQ_ADC0);
//*********************************
Serial.printf("End of setup().\n");
startTime = micros();
}
//*****************************************************************************
void loop() {
currentTime = micros();
deltaTime = currentTime - lastTime;
if (((ADC0_SC2 & (1 << 7)) == 0) && startConversion) {
startConversion = false;
currentTime = lastTime = micros();
// ADC Status and Control Registers 1 (ADC0_SC1A), pdf. 959
// Writing to this register initiates a conversion.
// SC1A is used for both software and hardware trigger modes of operation.
// Disable interrupt
// Single-ended conversions
// Input channel AD18.
ADC0_SC1A = 0x12;
}
if (((ADC0_SC2 & (1 << 7)) == 0) && !startConversion) {
ISR_ADC0();
if (++printCount > 99) {
printCount = 0;
//Serial.printf("Input voltage = %6.3f\n", digitizedScaledInput);
}
startConversion = true;
}
if (digitizedScaledInput > 1.655) {
digitalWrite(13, HIGH);
}
else {
digitalWrite(13, LOW);
}
if (/*(digitizedScaledInput < 1.600) &&*/ (conversionCount > 50'000)) {
conversionCount = 0;
endTime = micros();
//Serial.printf("Conversion count = %d in %d (us) \n", conversionCount, (endTime - startTime));
Serial.printf("Input ADC value = %d\n", digitizedInput);
Serial.printf("Input voltage = %6.3f\n", digitizedScaledInput);
Serial.printf("TPM1_C0V = %d\n", TPM1_C0V);
}
}
Definitions.h
Code:
// Definitions_09.h
#ifndef _DEFINITIONS_h
#define _DEFINITIONS_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
//*****************************************************************************
// Global variables
extern volatile bool startConversion;
extern volatile uint16_t digitizedInput;
extern volatile float digitizedScaledInput;
extern volatile uint32_t deltaTime;
extern volatile uint32_t currentTime;
extern volatile uint32_t lastTime;
extern volatile uint32_t printCount;
extern volatile uint32_t startTime;
extern volatile uint32_t endTime;
extern volatile uint32_t conversionCount;
//*****************************************************************************
// ADC function declarations
void Configure_ADC();
void ISR_ADC0();
//*****************************************************************************
// TPM1 function declarations
void Configure_TPM1();
#endif
Definitions.cpp
Code:
// Definitions_09.cpp
#include "Definitions.h"
//*****************************************************************************
volatile bool startConversion = true;
volatile uint16_t digitizedInput = 0;
volatile float digitizedScaledInput = 0.0f;
volatile uint32_t deltaTime = 0;
volatile uint32_t currentTime = 0;
volatile uint32_t lastTime = 0;
volatile uint32_t printCount = 0;
volatile uint32_t startTime = 0;
volatile uint32_t endTime = 0;
volatile uint32_t conversionCount = 0;
//*****************************************************************************
// ADC configuration
void Configure_ADC() {
// pdf. 960.
// Bit 7 is the conversion complete flag.
// ADC interrupt disabled.
// Single-ended conversions.
// Input channel, AD18, default pin 34.
// Writing to ADC0_SC1A starts conversion.
//ADC0_SC1A |= 0x12;
// pdf. 962
// Clock divide by 8
// Long sample time
// 10-bit conversion
// ADC clock is 30 / 2 MHz.
// Default, ADC0_CFG1 = 0x39
ADC0_CFG1 |= 0x12;
// pdf. 963
// ADxxa channels
// Asynchronous clock and clock output is enabled regardless of the state of the ADC.
// Normal conversion sequence selected.
// 2 extra ADCK cycles; 6 ADCK cycles total sample time.
ADC0_CFG2 |= 0x03;
// pdf. 964
// ADC0_RA & 0x3FF is the 10-bit conversion result.
// pdf. 966
// Compare value
// pdf. 967
// Will want to enable compare value function.
ADC0_SC2 |= 0x00;
}
//*********************************
void ISR_ADC0() {
currentTime = micros();
deltaTime = currentTime - lastTime;
digitizedInput = ADC0_RA;
// pdf.1066
// Check TPM1 overflow flag.
// Write new value if an overflow has occurred.
if ((TPM1_SC & 0x80) != 0) {
// Clear TPM1 overflow flag, w1c.
TPM1_SC |= 0x80;
TPM1_C0V = (digitizedInput << 6);
}
//TPM1_C0V = (digitizedInput << 5);
digitizedScaledInput = ((float)digitizedInput / (float)1023) * 3.3f;
conversionCount++;
}
//*****************************************************************************
// TPM1 function declarations
void Configure_TPM1() {
// pdf.1066
// Disable TPM1 for subsequent setting.
TPM1_SC &= 0x80;
while (TPM1_SC != 0x0) {
TPM1_SC &= 0x80;
}
Serial.printf("TPM1 is disable. Should equal 0x0, = 0x%X\n", TPM1_SC);
// pdf.1066
// Overflow flag cleared.
// Set for upcounting.
// TPM counter increments on every TPM counter clock, CMOD = 0b01.
// Prescaler = 32, 2 MHz / 32 = 62.5 kHz.
TPM1_SC |= 0x08D;
while ((TPM1_SC & 0xD) != 0xD) {
TPM1_SC |= 0x08D;
}
Serial.printf("TPM1_SC should equal 0xD, = 0x%X\n", TPM1_SC);
// pdf. 1067
// Initialize the TPM1 counting register
TPM1_CNT = 0x0000;
Serial.printf("TPM1_CNT reset, should equal 0x0, = 0x%X\n", TPM1_CNT);
// pdf. 1068
// Overflow value, set to max.
TPM1_MOD |= 0xFFFF;
while ((TPM1_MOD & 0xFFFF) != 0xFFFF) {
TPM1_MOD |= 0xFFFF;
}
Serial.printf("Check value should equal 0xFFFF, = 0x%X\n", (TPM1_MOD & 0xFFFF));
// pdf. 1069
// MS0B:MS0A = 0b10, ELS0B:ELS0A = 0b10 - Edge-aligned PWM, High-true pulses
// (clear Output on match, set Output on reload).
// Disable the channel.
while ((TPM1_C0SC & 0x3C) != 0) {
TPM1_C0SC &= 80;
}
Serial.printf("(TPM1_C0SC & 0x3C) should be disabled and = 0x0, = 0x%X\n", (TPM1_C0SC & 0x3C));
TPM1_C0SC |= 0xA8;
Serial.printf("TPM1_C0SC should be = 0xA8, = 0x%X\n", TPM1_C0SC);
// pdf. 1071
// Will be updated as received from the ADC input.
//TPM1_C0V = digitizedInput, set in ISR_ADC0(). This is a 50% duty cycle starting setting.
TPM1_C0V |= 32'768;
//************************************
// TPM1 clock
// pdf. 631
// Very high frequency range selected for the crystal oscillator.
// Oscillator requested.
// Fast internal reference clock selected.
MCG_C2 |= 0x1;
Serial.printf("MCG_C2 should be 0x25 = 0x%X\n", MCG_C2);
// pdf. 239
// Check that TPM1 clock source is OSCERCLK.
Serial.printf("((SIM_SOPT2 & (0b10 << 24)) >> 24) should be 0x2 = 0x%X\n", ((SIM_SOPT2 & (0b10 << 24)) >> 24));
// pdf. 667
// Disable OSCERCLOCK.
// OSC_CR = 0x8A
OSC0_CR &= ~0x80;
while ((OSC0_CR & 0x80) != 0) {
OSC0_CR &= ~0x80;
}
Serial.printf("((OSC0_CR & 0x80) >> 7) is disabled, should be = 0x0, = 0x%X\n", ((OSC0_CR & 0x80) >> 7));
// pdf. 669
// Divsor is 8. Output frequency should be 16 MHz / 8 = 2 MHz.
OSC0_OSC_DIV |= (0b11 << 6);
Serial.printf("OSC0_OSC_DIV should be = 0xC0, = 0x%X\n", OSC0_OSC_DIV);
// pdf. 667
// Set by default to the OSCERCLOCK.
// Enable OSCERCLOCK.
// External reference clock stays enabled in Stop mode
// OSC_CR = 0x8A
OSC0_CR |= 0xAA;
Serial.printf("OSC0_CR should be = 0xAA, = 0x%X\n", OSC0_CR);
// pdf. 255
// Enable the TPM1 clock.
SIM_SCGC2 |= (1 << 9);
Serial.printf("(SIM_SCGC2 & (1 << 9)) should be = 0x200, = 0x%X\n", (SIM_SCGC2 & (1 << 9)));
//************************************
// Check that clock for ports B and C are enabled.
// pdf. 261
Serial.printf("((SIM_SCGC5 & (3 << 10)) >> 10) should be 0x3, = 0x%X\n", ((SIM_SCGC5 & (3 << 10)) >> 10));
// pdf. 220
// Divided OSCERCLOCK output connected to pin 9.
// pdf. 188
// PTC3, ALT5, CLKOUT
PORTC_PCR3 |= (5 << 8);
Serial.printf("(PORTC_PCR3 & (7 << 8)) should be = 0x500, = 0x%X\n", (PORTC_PCR3 & (7 << 8)));
// pdf. 220
// TPM1 output connected to pin 16.
// pdf. 188
// PTB0, ALT6
PORTB_PCR0 |= (6 << 8);
Serial.printf("(PORTB_PCR0 & (7 << 8)) should be = 0x600, = 0x%X\n", (PORTB_PCR0 & (7 << 8)));
}
The output from this project is:
Code:
1. Serial print ready.
2. Serial print ready.
TPM1 is disable. Should equal 0x0, = 0x0
TPM1_SC should equal 0xD, = 0xD
TPM1_CNT reset, should equal 0x0, = 0x3E84
Check value should equal 0xFFFF, = 0xFFFF
(TPM1_C0SC & 0x3C) should be disabled and = 0x0, = 0x0
TPM1_C0SC should be = 0xA8, = 0xA8
MCG_C2 should be 0x25 = 0x25
((SIM_SOPT2 & (0b10 << 24)) >> 24) should be 0x2 = 0x2
((OSC0_CR & 0x80) >> 7) is disabled, should be = 0x0, = 0x0
OSC0_OSC_DIV should be = 0xC0, = 0xC0
OSC0_CR should be = 0xAA, = 0xAA
(SIM_SCGC2 & (1 << 9)) should be = 0x200, = 0x200
((SIM_SCGC5 & (3 << 10)) >> 10) should be 0x3, = 0x3
(PORTC_PCR3 & (7 << 8)) should be = 0x500, = 0x500
(PORTB_PCR0 & (7 << 8)) should be = 0x600, = 0x600
End of setup().
Input ADC value = 608
Input voltage = 1.961
TPM1_C0V = 38912
I am using a potentiometer wired as a voltage divider to divide the 3.3 VDC Teensy voltage as an input to the ADC. This is working.
TPM1 is supposed to be using OSCERCLK divided by 8 from 16 MHz to 2 MHz.
Again, the problems:
1. I want the OSCERCLK to be connected to Teensy 3.6 pin 9, and expect to see a frequency of 2 MHz. Instead I am measuring 30 Hz (not kHz, not MHz, Hz) with an oscilloscope.
2. The TPM1 output is connected to Teensy pin 16 and has the correct duty cycle for the analog voltage input. However, the frequency of the PWM signal is 1 Hz (not kHz, not MHz, Hz).
My relevant configuration code is in Definitions.cpp and begins after the "// TPM1 function declarations" comment.
Any help would be appreciated.
Thanks.