Make h/w SPI still better and some cosmetic fixes

pull/18/head^2
Thierry Frenkel 5 years ago
parent 7197da8055
commit 07e09fcfaf
  1. 6
      Open_Theremin_V3/Open_Theremin_V3.ino
  2. 16
      Open_Theremin_V3/SPImcpDAC.h
  3. 23
      Open_Theremin_V3/ihandlers.cpp

@ -1,7 +1,7 @@
/* /*
* Open.Theremin control software for Arduino UNO * Open.Theremin control software for Arduino UNO
* Version 3.0 * Version 3.1
* Copyright (C) 2010-2016 by Urs Gaudenz * Copyright (C) 2010-2020 by Urs Gaudenz
* *
* Open.Theremin control software is free software: you can redistribute it and/or * Open.Theremin control software is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
@ -19,6 +19,7 @@
* With important contributions by * With important contributions by
* David Harvey * David Harvey
* Michael Margolis * Michael Margolis
* "Theremingenieur" Thierry Frenkel
*/ */
/** /**
@ -76,4 +77,3 @@ void setup() {
void loop() { void loop() {
app.loop(); app.loop();
} }

@ -45,18 +45,20 @@ static inline void SPImcpDACinit()
HW_SPI_DDR |= _BV(HW_SPI_MOSI_BIT); HW_SPI_DDR |= _BV(HW_SPI_MOSI_BIT);
// initialize the hardware SPI registers // initialize the hardware SPI registers
SPCR = _BV(SPE) | _BV(MSTR); // no interrupt, SPI enable, MSB first, SPI master, SPI mode 0, clock = f_osc/4 (maximum) SPCR = _BV(SPE) | _BV(MSTR); // no interrupt, SPI enable, MSB first, SPI master, SPI mode 0, clock = f_osc/4 (maximum)
SPSR |= SPI2X; // double the SPI clock, ideally we get 8 MHz, so that a 16bit word goes out in 2us plus only a small overhead SPSR = _BV(SPI2X); // double the SPI clock, ideally we get 8 MHz, so that a 16bit word goes out in 3.5us (5.6us when called from an interrupt) including CS asserting/deasserting
} }
static inline void SPImcpDACtransmit(uint16_t data) static inline void SPImcpDACtransmit(uint16_t data)
{ {
// Send highbyte and wait for complete // Send highbyte and wait for complete
SPDR = highByte(data); SPDR = highByte(data);
while (!(SPSR && _BV(SPIF))) asm("nop");
while (!(SPSR & _BV(SPIF)))
; ;
// Send lowbyte and wait for complete // Send lowbyte and wait for complete
SPDR = lowByte(data); SPDR = lowByte(data);
while (!(SPSR && _BV(SPIF))) asm("nop");
while (!(SPSR & _BV(SPIF)))
; ;
} }
@ -69,12 +71,12 @@ static inline void SPImcpDAClatch()
static inline void SPImcpDACsend(uint16_t data) static inline void SPImcpDACsend(uint16_t data)
{ {
MCP_DAC_CS_PORT &= ~_BV(MCP_DAC_CS_BIT); MCP_DAC_CS_PORT &= ~_BV(MCP_DAC_CS_BIT);
// Sanitize input data and add DAC config MSBs // Sanitize input data and add DAC config MSBs
data &= 0x0FFF; data &= 0x0FFF;
data |= 0x7000; data |= 0x7000;
SPImcpDACtransmit(data); SPImcpDACtransmit(data);
MCP_DAC_CS_PORT |= _BV(MCP_DAC_CS_BIT); MCP_DAC_CS_PORT |= _BV(MCP_DAC_CS_BIT);
// Do not latch immpediately, let's do it at the beginning of the next interrupt to get consistent timing // Do not latch immpediately, let's do it at the very beginning of the next interrupt to get consistent timing
} }
static inline void SPImcpDAC2Asend(uint16_t data) static inline void SPImcpDAC2Asend(uint16_t data)

@ -106,14 +106,15 @@ void ihInitialiseVolumeMeasurement() //Measurement of variable frequency oscilla
/* Externaly generated 31250 Hz Interrupt for WAVE generator (32us) */ /* Externaly generated 31250 Hz Interrupt for WAVE generator (32us) */
ISR (INT1_vect) { ISR (INT1_vect) {
// Interrupt takes up a total of 16us plus overhead when interrupted itself. // Interrupt takes up normally 14us but can take up to 22us when interrupted by another interrupt.
// Added by ThF 20200419
#ifdef TH_DEBUG // Added by ThF 20200419
HW_LED2_ON; #ifdef TH_DEBUG
#endif HW_LED2_ON;
#endif
// Latch previously written DAC value: // Latch previously written DAC value:
SPImcpDAClatch(); SPImcpDAClatch();
disableInt1(); // Disable External Interrupt INT1 to avoid recursive interrupts disableInt1(); // Disable External Interrupt INT1 to avoid recursive interrupts
// Enable Interrupts to allow counter 1 interrupts // Enable Interrupts to allow counter 1 interrupts
@ -126,18 +127,18 @@ ISR (INT1_vect) {
#if CV_ENABLED // Generator for CV output #if CV_ENABLED // Generator for CV output
vPointerIncrement = min(vPointerIncrement, 4095); vPointerIncrement = min(vPointerIncrement, 4095);
mcpDacSend(vPointerIncrement); //Send result to Digital to Analogue Converter (audio out) (9.6 us) mcpDacSend(vPointerIncrement); //Send result to Digital to Analogue Converter (audio out) (5.5 us)
#else //Play sound #else //Play sound
// Read next wave table value // Read next wave table value
waveSample = (int16_t)pgm_read_word_near(wavetables[vWavetableSelector] + offset); waveSample = (int16_t)pgm_read_word_near(wavetables[vWavetableSelector] + offset);
scaledSample = ((int32_t)waveSample * (uint32_t)vScaledVolume) >> 16; scaledSample = ((int32_t)waveSample * (uint32_t)vScaledVolume) >> 16; // The compiler optimizes this better than any assembly written by hand !!!
SPImcpDACsend(scaledSample + MCP_DAC_BASE); //Send result to Digital to Analogue Converter (audio out) (6 us) SPImcpDACsend(scaledSample + MCP_DAC_BASE); //Send result to Digital to Analogue Converter (audio out) (5.5 us)
pointer += vPointerIncrement; // increment table pointer (ca. 2us) pointer += vPointerIncrement; // increment table pointer
#endif //CV play sound #endif //CV play sound
incrementTimer(); // update 32us timer incrementTimer(); // update 32us timer

Loading…
Cancel
Save