Archived
1
0
This repo is archived. You can view files and clone it, but cannot push or open issues or pull requests.
controller/Scan/ADCTest/scan_loop.c
Rowan Decker 1392571bd7 Fix whitespace
Use a consistent standard - Tabs in front for indenting, spaces after for anything else. This way everything stays nice and lined up while also letting users change there prefered indent level. Most of the new files from Haata where already in this format.
2015-03-08 18:40:01 -07:00

376 lines
9.9 KiB
C

/* Copyright (C) 2014 by Jacob Alexander
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// ----- Includes -----
// Compiler Includes
#include <Lib/ScanLib.h>
// Project Includes
#include <cli.h>
#include <led.h>
#include <print.h>
// Local Includes
#include "scan_loop.h"
// ----- Defines -----
// ADC Clock divisor settings (F_BUS == 48000000)
#define ADC_CFG1_6MHZ ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1)
#define ADC_CFG1_12MHZ ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1)
#define ADC_CFG1_24MHZ ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1)
// ----- Macros -----
// ----- Function Declarations -----
void cliFunc_adc ( char* args );
void cliFunc_adcInit( char* args );
void cliFunc_dac ( char* args );
void cliFunc_dacVref( char* args );
void cliFunc_echo ( char* args );
// ----- Variables -----
// Buffer used to inform the macro processing module which keys have been detected as pressed
volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER];
volatile uint8_t KeyIndex_BufferUsed;
// Scan Module command dictionary
char scanCLIDictName[] = "ADC Test Module Commands";
const CLIDictItem scanCLIDict[] = {
#if defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
{ "adc", "Read the specified number of values from the ADC at the given pin: <pin> [# of reads]"
NL "\t\t See \033[35mLib/pin_map.teensy3\033[0m for ADC0 channel number.", cliFunc_adc },
{ "adcInit", "Intialize/calibrate ADC: <ADC Resolution> <Vref> <Hardware averaging samples>"
NL "\t\tADC Resolution -> 8, 10, 12, 16 (bit)"
NL "\t\t Vref -> 0 (1.2 V), 1 (External)"
NL "\t\tHw Avg Samples -> 0 (disabled), 4, 8, 16, 32", cliFunc_adcInit },
#endif
#if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
{ "dac", "Set DAC output value, from 0 to 4095 (1/4096 Vref to Vref).", cliFunc_dac },
{ "dacVref", "Set DAC Vref. 0 is 1.2V. 1 is 3.3V.", cliFunc_dacVref },
#endif
{ "echo", "Example command, echos the arguments.", cliFunc_echo },
{ 0, 0, 0 } // Null entry for dictionary end
};
// ----- Functions -----
// Setup
inline void Scan_setup()
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR
{
// Register Scan CLI dictionary
CLI_registerDictionary( scanCLIDict, scanCLIDictName );
}
#elif defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
{
// Register Scan CLI dictionary
CLI_registerDictionary( scanCLIDict, scanCLIDictName );
// ADC Setup
VREF_TRM = 0x60;
VREF_SC = 0xE1; // Enable 1.2V Vref
#if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
// DAC Setup
SIM_SCGC2 |= SIM_SCGC2_DAC0;
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
#endif
}
#endif
// Main Detection Loop
inline uint8_t Scan_loop()
{
return 0;
}
// Signal KeyIndex_Buffer that it has been properly read
void Scan_finishedWithBuffer( uint8_t sentKeys )
{
}
// Signal that the keys have been properly sent over USB
void Scan_finishedWithUSBBuffer( uint8_t sentKeys )
{
}
// Reset Keyboard
void Scan_resetKeyboard()
{
}
// ----- CLI Command Functions -----
// XXX Just an example command showing how to parse arguments (more complex than generally needed)
void cliFunc_echo( char* args )
{
char* curArgs;
char* arg1Ptr;
char* arg2Ptr = args;
// Parse args until a \0 is found
while ( 1 )
{
print( NL ); // No \r\n by default after the command is entered
curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
// Stop processing args if no more are found
if ( *arg1Ptr == '\0' )
break;
// Print out the arg
dPrint( arg1Ptr );
}
}
void cliFunc_adc( char* args )
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR
{
}
#elif defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
{
// Parse code from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
// Set the ADC Channel
uint8_t channel = numToInt( arg1Ptr );
__disable_irq();
ADC0_SC1A = channel;
__enable_irq();
// Number of ADC samples to display
CLI_argumentIsolation( arg2Ptr, &arg1Ptr, &arg2Ptr );
int displayedADC = 1; // Default to 1 read
if ( arg1Ptr ) // If there is an argument, use that instead
{
displayedADC = numToInt( arg1Ptr );
}
// Poll ADC until it gets a value, making sure to serve interrupts on each attempt
while ( displayedADC > 0 )
{
__disable_irq();
// ADC Sample is ready
if ( (ADC0_SC1A & ADC_SC1_COCO) )
{
int result = ADC0_RA;
print( NL );
printInt32( result );
displayedADC--;
// Prepare for another read
if ( displayedADC > 0 )
{
ADC0_SC1A = channel;
}
}
__enable_irq();
yield(); // Make sure interrupts actually get serviced
}
}
#endif
void cliFunc_adcInit( char* args )
#if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR
{
}
#elif defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
{
// Parse code from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
// Make sure calibration has stopped
ADC0_SC3 = 0;
// Select bit resolution
int bitResolution = numToInt( arg1Ptr );
switch ( bitResolution )
{
case 8: // 8-bit
ADC0_CFG1 = ADC_CFG1_24MHZ + ADC_CFG1_MODE(0);
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
break;
case 10: // 10-bit
ADC0_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
break;
case 12: // 12-bit
ADC0_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
break;
case 16: // 16-bit
ADC0_CFG1 = ADC_CFG1_12MHZ + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP;
ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
break;
default: return; // Do nothing, invalid arg
}
// Select Vref
CLI_argumentIsolation( arg2Ptr, &arg1Ptr, &arg2Ptr );
int vRef = numToInt( arg1Ptr );
switch ( vRef )
{
case 0: // 1.2V internal Vref
ADC0_SC2 = ADC_SC2_REFSEL(1);
break;
case 1: // Vcc/Ext Vref
ADC0_SC2 = ADC_SC2_REFSEL(0);
break;
default: return; // Do nothing, invalid arg
}
// Hardware averaging (and start calibration)
CLI_argumentIsolation( arg2Ptr, &arg1Ptr, &arg2Ptr );
int hardwareAvg = numToInt( arg1Ptr );
switch ( hardwareAvg )
{
case 0: // No hardware averaging
ADC0_SC3 = ADC_SC3_CAL; // Just start calibration
break;
case 4: // 4 sample averaging
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0);
break;
case 8: // 8 sample averaging
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1);
break;
case 16: // 16 sample averaging
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2);
break;
case 32: // 32 sample averaging
ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3);
break;
default: return; // Do nothing, invalid arg
}
// Wait for calibration
while ( ADC0_SC3 & ADC_SC3_CAL );
// Set calibration
uint16_t sum;
// XXX Why is PJRC doing this? Is the self-calibration not good enough? -HaaTa
// ADC Plus-Side Gain Register
__disable_irq(); // Disable interrupts
sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
sum = (sum / 2) | 0x8000;
ADC0_PG = sum;
print( NL );
info_msg("Calibration ADC0_PG (Plus-Side Gain Register) set to: ");
printInt16( sum );
// ADC Minus-Side Gain Register
// XXX I don't think this is necessary when doing single-ended (as opposed to differential) -HaaTa
// K20P64M72SF1RM.pdf 31.3.10 pg. 666
sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0;
sum = (sum / 2) | 0x8000;
ADC0_MG = sum;
print( NL );
info_msg("Calibration ADC0_MG (Minus-Side Gain Register) set to: ");
printInt16( sum );
__enable_irq(); // Re-enable interrupts
}
#endif
void cliFunc_dac( char* args )
{
#if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
// Parse code from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
int dacOut = numToInt( arg1Ptr );
// Make sure the value is between 0 and 4096, otherwise ignore
if ( dacOut >= 0 && dacOut <= 4095 )
{
*(int16_t *) &(DAC0_DAT0L) = dacOut;
}
#endif
}
void cliFunc_dacVref( char* args )
{
#if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
// Parse code from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
switch ( numToInt( arg1Ptr ) )
{
case 0:
DAC0_C0 = DAC_C0_DACEN; // 1.2V Vref is DACREF_1
break;
case 1:
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
break;
}
#endif
}