From 07e09fcfaf98ec702528261a9d5b5feb92b88b18 Mon Sep 17 00:00:00 2001 From: Thierry Frenkel Date: Mon, 20 Apr 2020 14:38:26 +0200 Subject: [PATCH] Make h/w SPI still better and some cosmetic fixes --- Open_Theremin_V3/Open_Theremin_V3.ino | 6 +++--- Open_Theremin_V3/SPImcpDAC.h | 18 ++++++++++-------- Open_Theremin_V3/ihandlers.cpp | 23 ++++++++++++----------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Open_Theremin_V3/Open_Theremin_V3.ino b/Open_Theremin_V3/Open_Theremin_V3.ino index 94bedb5..49255a4 100644 --- a/Open_Theremin_V3/Open_Theremin_V3.ino +++ b/Open_Theremin_V3/Open_Theremin_V3.ino @@ -1,7 +1,7 @@ /* * Open.Theremin control software for Arduino UNO - * Version 3.0 - * Copyright (C) 2010-2016 by Urs Gaudenz + * Version 3.1 + * Copyright (C) 2010-2020 by Urs Gaudenz * * 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 @@ -19,6 +19,7 @@ * With important contributions by * David Harvey * Michael Margolis + * "Theremingenieur" Thierry Frenkel */ /** @@ -76,4 +77,3 @@ void setup() { void loop() { app.loop(); } - diff --git a/Open_Theremin_V3/SPImcpDAC.h b/Open_Theremin_V3/SPImcpDAC.h index 9ead1f5..e87f9e8 100644 --- a/Open_Theremin_V3/SPImcpDAC.h +++ b/Open_Theremin_V3/SPImcpDAC.h @@ -45,18 +45,20 @@ static inline void SPImcpDACinit() HW_SPI_DDR |= _BV(HW_SPI_MOSI_BIT); // 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) - 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) { // Send highbyte and wait for complete SPDR = highByte(data); - while (!(SPSR && _BV(SPIF))) + asm("nop"); + while (!(SPSR & _BV(SPIF))) ; // Send lowbyte and wait for complete 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) { MCP_DAC_CS_PORT &= ~_BV(MCP_DAC_CS_BIT); - // Sanitize input data and add DAC config MSBs - data &= 0x0FFF; - data |= 0x7000; + // Sanitize input data and add DAC config MSBs + data &= 0x0FFF; + data |= 0x7000; SPImcpDACtransmit(data); 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) @@ -99,4 +101,4 @@ static inline void SPImcpDAC2Bsend(uint16_t data) SPImcpDAClatch(); } -#endif \ No newline at end of file +#endif diff --git a/Open_Theremin_V3/ihandlers.cpp b/Open_Theremin_V3/ihandlers.cpp index 9b29087..894e037 100644 --- a/Open_Theremin_V3/ihandlers.cpp +++ b/Open_Theremin_V3/ihandlers.cpp @@ -106,14 +106,15 @@ void ihInitialiseVolumeMeasurement() //Measurement of variable frequency oscilla /* Externaly generated 31250 Hz Interrupt for WAVE generator (32us) */ ISR (INT1_vect) { - // Interrupt takes up a total of 16us plus overhead when interrupted itself. -// Added by ThF 20200419 -#ifdef TH_DEBUG - HW_LED2_ON; -#endif + // Interrupt takes up normally 14us but can take up to 22us when interrupted by another interrupt. + + // Added by ThF 20200419 + #ifdef TH_DEBUG + HW_LED2_ON; + #endif - // Latch previously written DAC value: - SPImcpDAClatch(); + // Latch previously written DAC value: + SPImcpDAClatch(); disableInt1(); // Disable External Interrupt INT1 to avoid recursive interrupts // Enable Interrupts to allow counter 1 interrupts @@ -126,18 +127,18 @@ ISR (INT1_vect) { #if CV_ENABLED // Generator for CV output 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 // Read next wave table value 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 incrementTimer(); // update 32us timer