Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions include/ADC.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// ADC Class Header
#ifndef ADC_H
#define ADC_H

#include <kinetis.h>
#include "PDB.h"

#define ADC_MAX_12B (1 << 12)
#define ADC_REF 3.3

class ADC
{
private:
PDB m_pdb;

public:
ADC (uint16_t sample_rate);

uint8_t calibrate (void);
void start (void);
uint16_t get_latest_sample (void);
};

#endif // ADC_H
15 changes: 15 additions & 0 deletions include/PDB.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// PDB (Programmable Delay Block) Class Header
#ifndef PDB_H
#define PDB_H

#include <kinetis.h>

class PDB
{
public:
PDB (uint16_t timer_freq);

void start (void);
};

#endif // PDB_H
82 changes: 82 additions & 0 deletions src/ADC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <core_pins.h>
#include "ADC.h"

#define NUM_ADC_MODULES 2
#define MAX_NUM_ADC_CHANNELS 24

#define PDB_TRIG 0x0 // SIM_SOPT7 PDB Trigger
#define PIT_TRIG0 0x4 // SIM_SOPT7 PIT Trigger

static uint16_t s_adc_0_sample = 0;

// ADC ISR
void adc0_isr(void)
{
// Only update sample value if Conversion Complete flag is set
if (ADC0_SC1A & ADC_SC1_COCO)
{
s_adc_0_sample = ADC0_RA;
}
}

ADC::ADC (uint16_t sample_rate)
: m_pdb (sample_rate)
{
SIM_SCGC6 |= SIM_SCGC6_ADC0; // Enable CLK to ADC0

ADC0_CFG1 = ADC_CFG1_ADLSMP // Long Sample Time
| ADC_CFG1_ADIV(0) // Clock div = 1
| ADC_CFG1_MODE(1) // 12-bit mode
| ADC_CFG1_ADICLK(0); // Select bus clock

ADC0_CFG2 = ADC_CFG2_ADLSTS(1); // Set sample time to 12 samples
// MUX_SEL = 0; Channel A selected

ADC0_SC2 = ADC_SC2_ADTRG // Hardware trigger
| ADC_SC2_REFSEL(0); // Select reference = VREFH, VREFL

ADC0_SC3 = ADC_SC3_AVGE // Hardware average enable
| ADC_SC3_AVGS(0); // Averages 4 samples

ADC0_SC1A = ADC_SC1_AIEN // Conversion complete interrupt enable
| ADC_SC1_ADCH(0x0F); // Input PC1 (A8 on Teensy 3.2)

SIM_SOPT7 &= ~(SIM_SOPT7_ADC0ALTTRGEN // ADC0 trigger
| SIM_SOPT7_ADC0TRGSEL(PDB_TRIG)); // Set PDB to trigger ADC0

// Enable ADC ISR
NVIC_ENABLE_IRQ(IRQ_ADC0);
}

// Perform ADC calibration
uint8_t ADC::calibrate (void)
{
uint8_t err;

ADC0_SC3 |= ADC_SC3_CAL; // Begin ADC Calibration

while (ADC0_SC3 & ADC_SC3_CAL)
; // Wait for calibration to complete

// Check for calibration error
err = ((ADC0_SC3 & ADC_SC3_CALF) != 0) ? 1 : 0;
return err;
}

void ADC::start (void)
{
m_pdb.start();
}

// Returns the latest computed ADC sample
uint16_t ADC::get_latest_sample (void)
{
// static uint16_t sample = 0;

// // Only update sample value if Conversion Complete flag is set
// if (ADC0_SC1A & ADC_SC1_COCO)
// {
// sample = ADC0_RA;
// }
return s_adc_0_sample;
}
41 changes: 41 additions & 0 deletions src/PDB.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "PDB.h"

#define PDB_CHxCx_TOS(n) (1 << (n + 8))
#define PDB_CHxCx_EN(n) (1 << (n))

// PDB ISR
void pdb_isr (void)
{
PDB0_SC &= ~PDB_SC_PDBIF; // Clear PDB Int flag
}

PDB::PDB (uint16_t timer_freq)
{
SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable CLK to PDB

PDB0_SC = PDB_SC_PDBEN // PDB Enable
| PDB_SC_PDBIE // PDB Int Enable
| PDB_SC_MULT(0) // MULT = 1x
| PDB_SC_PRESCALER(0) // Prescaler = 2^0
| PDB_SC_CONT // Continuous Mode
| PDB_SC_TRGSEL(0xF); // Select Software Trigger
// Config other PDB Registers
PDB0_IDLY = 0; // Trigger Int every counter reset

PDB0_CH0C1 |= PDB_CHxCx_TOS(0) // PDB0 Pre-Trigger Output
| PDB_CHxCx_EN(0); // PDB0 Pre-Trigger Enable

//PDB0_CH0DLY0 = 0x0000;

PDB0_MOD = (F_BUS / timer_freq) - 1; // Set Timer value to trigger @ timer_freq

PDB0_SC |= PDB_SC_LDOK; // Load new config to PDB registers

// Enable PDB ISR
NVIC_ENABLE_IRQ (IRQ_PDB);
}

void PDB::start (void)
{
PDB0_SC |= PDB_SC_SWTRIG; // Starts the PDB and its trigger
}
137 changes: 97 additions & 40 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,31 @@
#include "GPIO.h"
#include "Encoder.h"
#include "SoftwareTimer.h"
#include "ADC.h"

#define NUM_LEDS 5
#define NUM_BTNS 3
#define LOOP_PERIOD_MS 100
// #define NUM_BTNS 3
#define LOOP_PERIOD_MS 10
#define LED_FREQ_HZ 4
#define PRINT_LOOP_CNT 5
#define PRINT_LOOP_CNT 50
#define BPM_DIV 30

#define ADC_SAMPLE_RATE 1000
#define SERIAL_SPEED 9600
#define PRINT_BUF_SIZE 64

void led_timer_cb (void);
static void handle_switch_input (void);
static void handle_button_input (void);
static void handle_encoder_input (uint16_t * encoder_count);

enum btn_id_t
{
BTN_ID_LEFT,
BTN_ID_CENTER,
BTN_ID_RIGHT,
NUM_BTN_IDS
};

GPIO leds [NUM_LEDS] =
{
Expand All @@ -25,17 +38,18 @@ GPIO leds [NUM_LEDS] =
GPIO (DIR_OUTPUT, GPIO_PIN_13),
};

GPIO btns [NUM_BTNS] =
GPIO btns [NUM_BTN_IDS] =
{
GPIO (DIR_INPUT, GPIO_PIN_4),
GPIO (DIR_INPUT, GPIO_PIN_5),
GPIO (DIR_INPUT, GPIO_PIN_6),
};

GPIO enable_sw = GPIO (DIR_INPUT, GPIO_PIN_11);
GPIO debug_gpio = GPIO (DIR_OUTPUT, DEBUG_GPIO_PIN_NUM);
Encoder encoder = Encoder (GPIO_PIN_15, GPIO_PIN_14);
SoftwareTimer * led_tmr = NULL;
GPIO enable_sw = GPIO (DIR_INPUT, GPIO_PIN_11);
GPIO debug_gpio = GPIO (DIR_OUTPUT, DEBUG_GPIO_PIN_NUM);
Encoder encoder = Encoder (GPIO_PIN_15, GPIO_PIN_14);
ADC adc = ADC (ADC_SAMPLE_RATE);
SoftwareTimer * led_tmr = NULL;

void led_timer_cb (void)
{
Expand All @@ -47,7 +61,7 @@ void led_timer_cb (void)
led_state ^= 0x01;
}

void handle_switch_input (void)
static void handle_switch_input (void)
{
static uint8_t prev_sw_state = 0;
uint8_t sw_state = enable_sw.read();
Expand All @@ -68,6 +82,68 @@ void handle_switch_input (void)
prev_sw_state = sw_state;
}

static void handle_button_input (void)
{
uint8_t btn_num = 0;
uint8_t temp_btn_state = LOW;
int8_t temp_led_num = 0;
uint8_t min_led_num = 1;
uint8_t prev_active_led = min_led_num;
static uint8_t active_led_num = min_led_num;
static uint8_t led_state = HIGH;
static uint8_t btn_state [NUM_BTN_IDS] = {LOW};

for (btn_num = 0; btn_num < NUM_BTN_IDS; btn_num++)
{
temp_btn_state = btns [btn_num].read();

if ((temp_btn_state == HIGH) && (btn_state [btn_num] == LOW))
{
prev_active_led = active_led_num;

if (btn_num == BTN_ID_LEFT && led_state)
{
// Decrement LED - handle negative modulo
temp_led_num = (active_led_num - min_led_num - 1);
temp_led_num = (temp_led_num < 0) ? (NUM_BTN_IDS - 1) : temp_led_num;
active_led_num = (temp_led_num + min_led_num);
}
else if (btn_num == BTN_ID_RIGHT && led_state)
{
// Increment LED
temp_led_num = (active_led_num - min_led_num + 1);
active_led_num = (temp_led_num % NUM_BTN_IDS) + min_led_num;
}
else if (btn_num == BTN_ID_CENTER)
{
// Toggle LED state
led_state ^= 0x01;
}

// Turn off previous LED
leds [prev_active_led].write(0);
// Turn on new LED
leds [active_led_num].write(led_state);
}
// Update button state
btn_state [btn_num] = temp_btn_state;
}
}

// Update the encoder count, change LED freq accordingly
static void handle_encoder_input (uint16_t * encoder_count)
{
static uint16_t prev_enc_count = *encoder_count;
*encoder_count = encoder.get_count();

if (*encoder_count != prev_enc_count)
{
prev_enc_count = *encoder_count;

led_tmr->set_freq(*encoder_count * 1.0 / BPM_DIV);
}
}

void setup()
{
// Put your setup code here, to run once:
Expand All @@ -77,52 +153,33 @@ void setup()
GPIO::init();

led_tmr = SoftwareTimer::getTimer (LED_FREQ_HZ, led_timer_cb, true);
adc.start();

Serial.begin(SERIAL_SPEED);
}

void loop()
{
// Put your main code here, to run repeatedly:
static uint8_t led_num = 0;
uint8_t btn_num = 0;
uint8_t temp_btn_state = LOW;
uint16_t adc_sample = 0;
float adc_reading = 0;
static uint16_t encoder_count = encoder.get_count();
static uint16_t prev_enc_count = encoder_count;
static uint8_t loop_cnt = 0;
static uint8_t led_state [NUM_LEDS] = {LOW};
static uint8_t btn_state [NUM_BTNS] = {LOW};

for (btn_num = 0; btn_num < NUM_BTNS; btn_num++)
{
temp_btn_state = btns [btn_num].read();

if ((temp_btn_state == HIGH) && (btn_state [btn_num] == LOW))
{
// Toggle the LED whenever its button is high
led_num = btn_num + 1;
led_state [led_num] ^= 0x01;
leds [led_num].write(led_state [led_num]);
}
// Update button state
btn_state [btn_num] = temp_btn_state;
}

handle_button_input();

handle_switch_input();

// Update the encoder count, change LED freq accordingly
encoder_count = encoder.get_count();

if (encoder_count != prev_enc_count)
{
prev_enc_count = encoder_count;

led_tmr->set_freq(encoder_count * 1.0 / BPM_DIV);
}
handle_encoder_input(&encoder_count);

if (loop_cnt == PRINT_LOOP_CNT)
{
loop_cnt = 0;

adc_sample = adc.get_latest_sample();
adc_reading = (adc_sample * ADC_REF) / ADC_MAX_12B;

Serial.printf ("Encoder: %u\n", encoder_count);
Serial.printf ("ADC Sample: %2.3fV\n", adc_reading);
}

loop_cnt++;
Expand Down