2014-04-13 04:13:37 +00:00
/* 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 -----
2014-04-14 06:40:06 +00:00
// 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)
2014-04-13 04:13:37 +00:00
// ----- Macros -----
// ----- Function Declarations -----
2014-04-14 06:40:06 +00:00
void cliFunc_adc ( char * args ) ;
void cliFunc_adcInit ( char * args ) ;
2014-04-13 06:10:39 +00:00
void cliFunc_dac ( char * args ) ;
void cliFunc_dacVref ( char * args ) ;
void cliFunc_echo ( char * args ) ;
2014-04-13 04:13:37 +00:00
// ----- 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
2014-08-15 17:42:12 +00:00
char scanCLIDictName [ ] = " ADC Test Module Commands " ;
const CLIDictItem scanCLIDict [ ] = {
2015-01-01 01:13:44 +00:00
# if defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
2014-04-15 06:59:41 +00:00
{ " adc " , " Read the specified number of values from the ADC at the given pin: <pin> [# of reads] "
2015-03-09 01:40:01 +00:00
NL " \t \t See \033 [35mLib/pin_map.teensy3 \033 [0m for ADC0 channel number. " , cliFunc_adc } ,
2014-04-15 06:59:41 +00:00
{ " adcInit " , " Intialize/calibrate ADC: <ADC Resolution> <Vref> <Hardware averaging samples> "
2015-03-09 01:40:01 +00:00
NL " \t \t ADC Resolution -> 8, 10, 12, 16 (bit) "
NL " \t \t Vref -> 0 (1.2 V), 1 (External) "
NL " \t \t Hw Avg Samples -> 0 (disabled), 4, 8, 16, 32 " , cliFunc_adcInit } ,
2014-04-15 06:59:41 +00:00
# endif
2015-01-01 01:13:44 +00:00
# if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
2014-04-13 06:10:39 +00:00
{ " 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 } ,
2014-04-13 04:13:37 +00:00
{ 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 ) ;
}
2015-01-01 01:13:44 +00:00
# elif defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
2014-04-13 04:13:37 +00:00
{
// Register Scan CLI dictionary
CLI_registerDictionary ( scanCLIDict , scanCLIDictName ) ;
2014-04-13 06:10:39 +00:00
2014-04-14 06:40:06 +00:00
// ADC Setup
VREF_TRM = 0x60 ;
VREF_SC = 0xE1 ; // Enable 1.2V Vref
2015-01-01 01:13:44 +00:00
# if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
2014-04-13 06:10:39 +00:00
// DAC Setup
SIM_SCGC2 | = SIM_SCGC2_DAC0 ;
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS ; // 3.3V VDDA is DACREF_2
# endif
2014-04-13 04:13:37 +00:00
}
# 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 )
{
}
2014-04-14 06:40:06 +00:00
2014-04-13 04:13:37 +00:00
// 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 )
{
2014-04-15 06:59:41 +00:00
print ( NL ) ; // No \r\n by default after the command is entered
2014-04-13 04:13:37 +00:00
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 ) ;
}
}
2014-04-14 06:40:06 +00:00
void cliFunc_adc ( char * args )
# if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR
{
}
2015-01-01 01:13:44 +00:00
# elif defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
2014-04-14 06:40:06 +00:00
{
// Parse code from argument
// NOTE: Only first argument is used
char * arg1Ptr ;
char * arg2Ptr ;
CLI_argumentIsolation ( args , & arg1Ptr , & arg2Ptr ) ;
// Set the ADC Channel
2014-08-16 19:07:25 +00:00
uint8_t channel = numToInt ( arg1Ptr ) ;
2014-04-14 06:40:06 +00:00
__disable_irq ( ) ;
ADC0_SC1A = channel ;
__enable_irq ( ) ;
// Number of ADC samples to display
CLI_argumentIsolation ( arg2Ptr , & arg1Ptr , & arg2Ptr ) ;
2014-04-15 06:59:41 +00:00
int displayedADC = 1 ; // Default to 1 read
if ( arg1Ptr ) // If there is an argument, use that instead
{
2014-08-16 19:07:25 +00:00
displayedADC = numToInt ( arg1Ptr ) ;
2014-04-15 06:59:41 +00:00
}
2014-04-14 06:40:06 +00:00
// 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 ;
2014-04-15 06:59:41 +00:00
print ( NL ) ;
2014-04-14 06:40:06 +00:00
printInt32 ( result ) ;
displayedADC - - ;
2014-04-15 06:59:41 +00:00
// Prepare for another read
if ( displayedADC > 0 )
{
ADC0_SC1A = channel ;
}
2014-04-14 06:40:06 +00:00
}
__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
{
}
2015-01-01 01:13:44 +00:00
# elif defined(_mk20dx128_) || defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // ARM
2014-04-14 06:40:06 +00:00
{
// 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
2014-08-16 19:07:25 +00:00
int bitResolution = numToInt ( arg1Ptr ) ;
2014-04-14 06:40:06 +00:00
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 ) ;
2014-08-16 19:07:25 +00:00
int vRef = numToInt ( arg1Ptr ) ;
2014-04-14 06:40:06 +00:00
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 ) ;
2014-08-16 19:07:25 +00:00
int hardwareAvg = numToInt ( arg1Ptr ) ;
2014-04-14 06:40:06 +00:00
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 ) ;
2014-04-15 06:59:41 +00:00
info_msg ( " Calibration ADC0_PG (Plus-Side Gain Register) set to: " ) ;
printInt16 ( sum ) ;
2014-04-14 06:40:06 +00:00
// 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 ;
2014-04-15 06:59:41 +00:00
print ( NL ) ;
2014-04-14 06:40:06 +00:00
info_msg ( " Calibration ADC0_MG (Minus-Side Gain Register) set to: " ) ;
printInt16 ( sum ) ;
__enable_irq ( ) ; // Re-enable interrupts
}
# endif
2014-04-13 06:10:39 +00:00
void cliFunc_dac ( char * args )
{
2015-01-01 01:13:44 +00:00
# if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
2014-04-13 06:10:39 +00:00
// Parse code from argument
// NOTE: Only first argument is used
char * arg1Ptr ;
char * arg2Ptr ;
CLI_argumentIsolation ( args , & arg1Ptr , & arg2Ptr ) ;
2014-08-16 19:07:25 +00:00
int dacOut = numToInt ( arg1Ptr ) ;
2014-04-13 06:10:39 +00:00
// 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 )
{
2015-01-01 01:13:44 +00:00
# if defined(_mk20dx256_) || defined(_mk20dx256vlh7_) // DAC is only supported on Teensy 3.1
2014-04-13 06:10:39 +00:00
// Parse code from argument
// NOTE: Only first argument is used
char * arg1Ptr ;
char * arg2Ptr ;
CLI_argumentIsolation ( args , & arg1Ptr , & arg2Ptr ) ;
2014-08-16 19:07:25 +00:00
switch ( numToInt ( arg1Ptr ) )
2014-04-13 06:10:39 +00:00
{
case 0 :
2014-04-14 06:40:06 +00:00
DAC0_C0 = DAC_C0_DACEN ; // 1.2V Vref is DACREF_1
2014-04-13 06:10:39 +00:00
break ;
case 1 :
DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS ; // 3.3V VDDA is DACREF_2
break ;
}
# endif
}