Impedance Fast Circuitry Software

Dependencies:   mbed-dsp mbed

Fork of DSP_200kHz by Mazzeo Research Group

main.cpp

Committer:
timmey9
Date:
2015-01-28
Revision:
38:ec3b16c130d7
Parent:
37:8bdc71f3e874
Child:
39:82dc3daecf32

File content as of revision 38:ec3b16c130d7:

// Server code
#include "mbed.h"
#include <stdio.h>

// Analog sampling
#include "PeripheralNames.h"
#include "PeripheralPins.h"
#include "fsl_adc_hal.h"
#include "fsl_clock_manager.h"
#include "fsl_dspi_hal.h"
#include "AngleEncoder.h"

#include "dma.h"

// Analog sampling
#define MAX_FADC 6000000
#define SAMPLING_RATE       10 // In microseconds, so 10 us will be a sampling rate of 100 kHz
#define TOTAL_SAMPLES       3 // originally 30000 for 0.3 ms of sampling.

#define LAST_SAMPLE_INDEX   (TOTAL_SAMPLES-1) // If sampling time is 25 us, then 2000 corresponds to 50 ms
#define FIRST_SAMPLE_INDEX  0
#define BEGIN_SAMPLING      0xFFFFFFFF
#define WAITING_TO_BEGIN    (BEGIN_SAMPLING-1)


// for debug purposes
Serial pc(USBTX, USBRX);
DigitalOut led_red(LED_RED);
DigitalOut led_green(LED_GREEN);
DigitalOut led_blue(LED_BLUE);

AngleEncoder angle_encoder(PTD2, PTD3, PTD1, PTD0, 8, 0, 1000000); // mosi, miso, sclk, cs, bit_width, mode, hz
DigitalIn AMT20_A(PTC0); // input for quadrature encoding from angle encoder
DigitalIn AMT20_B(PTC1); // input for quadrature encoding from angle encoder

// Analog sampling
AnalogIn A0_pin(A0);
AnalogIn A2_pin(A2);
Ticker Sampler;

uint32_t current_sample_index = WAITING_TO_BEGIN;
uint16_t sample_array1[TOTAL_SAMPLES];
uint16_t sample_array2[TOTAL_SAMPLES];
uint16_t angle_array[TOTAL_SAMPLES];
float currA0 = 0;
float currA2 = 0;

// Declaration of functions
void analog_initialization(PinName pin);
void timed_sampling();

// Important globabl variables necessary for the sampling every interval
int rotary_count = 0;
uint32_t last_AMT20_AB_read = 0;

using namespace std;
 
int main() {
    led_blue = 1;
    led_green = 1;
    led_red = 1;
    
    pc.baud(230400);
    pc.printf("Starting\r\n");
    
    
// Turn on the ADC0 and ADC1 clocks as well as the PDB clocks to test ADC triggered by PDB
SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;
SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
SIM_SCGC6 |= SIM_SCGC6_PDB_MASK;

    
    
    analog_initialization(A0);
    //analog_initialization(A2);
    
    ADC0->CFG1 |= ADC_CFG1_ADLPC_MASK; // high power mode for faster frequencies                   
    //ADC0->SC2 |= ADC_SC2_ADTRG_MASK; // enable hardware trigger
    SIM_SOPT7 |= 0;
    
    // put in continuous conversion mode
    //pc.printf("ADC0_SC3: %08x\r\n", ADC0->SC3);
    
    // enable the DMA
    ADC0->SC2 |= ADC_SC2_DMAEN_MASK;
    //ADC1->SC2 |= ADC_SC2_DMAEN_MASK;
    ADC0->SC3 = 0; // Reset SC3
    //ADC1->SC3 = 0; // Reset SC3
    
    dma_init(sample_array1, sample_array2, angle_array, TOTAL_SAMPLES);
    
    // initialize the Programmable Delay Block
    SIM->SCGC6 |= SIM_SCGC6_PDB_MASK; // turn on the clock to the PDB
    
    
// Configure System Integration Module for defaults as far as ADC
SIM_SOPT7 &= ~(SIM_SOPT7_ADC1ALTTRGEN_MASK  | // selects PDB not ALT trigger
            SIM_SOPT7_ADC1PRETRGSEL_MASK |
            SIM_SOPT7_ADC0ALTTRGEN_MASK  | // selects PDB not ALT trigger
            SIM_SOPT7_ADC0ALTTRGEN_MASK) ;
SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0);       // applies only in case of ALT trigger, in which case PDB external pin input trigger for ADC
SIM_SOPT7 = SIM_SOPT7_ADC1TRGSEL(0);       // same for both ADCs
    
    

// Configure the Peripheral Delay Block (PDB):
// enable PDB, pdb counter clock = busclock / 20 , continous triggers, sw trigger , and use prescaler too
PDB0_SC =  PDB_SC_CONT_MASK       // Contintuous, rather than one-shot, mode
     | PDB_SC_PDBEN_MASK      // PDB enabled
     //| PDB_SC_PDBIE_MASK      // PDB Interrupt Enable
     | PDB_SC_PRESCALER(0x5)  // Slow down the period of the PDB for testing
     | PDB_SC_TRGSEL(0xf)     // Trigger source is Software Trigger to be invoked in this file
     | PDB_SC_MULT(2);        // Multiplication factor 20 for the prescale divider for the counter clock
                              // the software trigger, PDB_SC_SWTRIG_MASK is not triggered at this time.

PDB0_IDLY = 0x0000;   // need to trigger interrupt every counter reset which happens when modulus reached

PDB0_MOD = 0xffff;    // largest period possible with the slections above, so slow you can see each conversion.

// channel 0 pretrigger 0 and 1 enabled and delayed
PDB0_CH0C1 = PDB_C1_EN(0x01)
       | PDB_C1_TOS(0x01)
       | PDB_C1_EN(0x02)
       | PDB_C1_TOS(0x02) ;

PDB0_CH0DLY0 = 100 ;
PDB0_CH0DLY1 = 300 ;

// channel 1 pretrigger 0 and 1 enabled and delayed
PDB0_CH1C1 = PDB_C1_EN(0x01)
       | PDB_C1_TOS(0x01)
       | PDB_C1_EN(0x02)
       | PDB_C1_TOS(0x02) ;

PDB0_CH1DLY0 = 200 ;
PDB0_CH1DLY1 = 400 ;

PDB0_SC =  PDB_SC_CONT_MASK        // Contintuous, rather than one-shot, mode
     | PDB_SC_PDBEN_MASK       // PDB enabled
     | PDB_SC_PDBIE_MASK       // PDB Interrupt Enable
     | PDB_SC_PRESCALER(0x5)   // Slow down the period of the PDB for testing
     | PDB_SC_TRGSEL(0xf)      // Trigger source is Software Trigger to be invoked in this file
     | PDB_SC_MULT(2)          // Multiplication factor 20 for the prescale divider for the counter clock
     | PDB_SC_LDOK_MASK;       // Need to ok the loading or it will not load certain regsiters!
                               // the software trigger, PDB_SC_SWTRIG_MASK is not triggered at this time.



//PDB configured above
/////////////////////////////////////////////////////////////////////////////////////////
//ADC configured below
/*
// setup the initial ADC default configuration
Master_Adc_Config.CONFIG1  = ADLPC_NORMAL
                        | ADC_CFG1_ADIV(ADIV_4)
                        | ADLSMP_LONG
                        | ADC_CFG1_MODE(MODE_16)
                        | ADC_CFG1_ADICLK(ADICLK_BUS);
Master_Adc_Config.CONFIG2  = MUXSEL_ADCA
                        | ADACKEN_DISABLED
                        | ADHSC_HISPEED
                        | ADC_CFG2_ADLSTS(ADLSTS_20) ;
Master_Adc_Config.COMPARE1 = 0x1234u ;                 // can be anything
Master_Adc_Config.COMPARE2 = 0x5678u ;                 // can be anything
                                                    // since not using
                                                    // compare feature
Master_Adc_Config.STATUS2  = ADTRG_HW
                        | ACFE_DISABLED
                        | ACFGT_GREATER
                        | ACREN_ENABLED
                        | DMAEN_DISABLED
                        | ADC_SC2_REFSEL(REFSEL_EXT);

Master_Adc_Config.STATUS3  = CAL_OFF
                        | ADCO_SINGLE
                        | AVGE_ENABLED
                        | ADC_SC3_AVGS(AVGS_32);

Master_Adc_Config.PGA      = PGAEN_DISABLED
                        | PGACHP_NOCHOP
                        | PGALP_NORMAL
                        | ADC_PGA_PGAG(PGAG_64);
Master_Adc_Config.STATUS1A = AIEN_OFF | DIFF_SINGLE | ADC_SC1_ADCH(31);
Master_Adc_Config.STATUS1B = AIEN_OFF | DIFF_SINGLE | ADC_SC1_ADCH(31);


// Configure ADC as it will be used, but becuase ADC_SC1_ADCH is 31,
// the ADC will be inactive.  Channel 31 is just disable function.
// There really is no channel 31.

ADC_Config_Alt(ADC0_BASE_PTR, &Master_Adc_Config);  // config ADC

// Calibrate the ADC in the configuration in which it will be used:
ADC_Cal(ADC0_BASE_PTR);                    // do the calibration

// The structure still has the desired configuration.  So restore it.
// Why restore it?  The calibration makes some adjustments to the
// configuration of the ADC.  The are now undone:

// config the ADC again to desired conditions
ADC_Config_Alt(ADC0_BASE_PTR, &Master_Adc_Config);

// REPEAT for BOTH ADC's.  However we will only 'use' the results from
// the ADC wired to the Potentiometer on the Kinetis Tower Card.

// Repeating for ADC1:
ADC_Config_Alt(ADC1_BASE_PTR, &Master_Adc_Config);  // config ADC
ADC_Cal(ADC1_BASE_PTR);                    // do the calibration
//  ADC_Read_Cal(ADC1_BASE_PTR,&CalibrationStore[0]);   // store the cal


// config the ADC again to default conditions
ADC_Config_Alt(ADC1_BASE_PTR, &Master_Adc_Config);

// *****************************************************************************
//      ADC0 and ADC1 using the PDB trigger in ping pong
// *****************************************************************************

// use interrupts, single ended mode, and real channel numbers now:

Master_Adc_Config.STATUS1A = AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(ADC0_CHANA);
Master_Adc_Config.STATUS1B = AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(ADC0_CHANB);
ADC_Config_Alt(ADC0_BASE_PTR, &Master_Adc_Config);  // config ADC0

Master_Adc_Config.STATUS1A = AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(ADC1_CHANA);
Master_Adc_Config.STATUS1B = AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(ADC1_CHANB);
ADC_Config_Alt(ADC1_BASE_PTR, &Master_Adc_Config);  // config ADC1
*/
    
    
    
    
    
    /*
    PDB0->SC = 0x0100; // DMA enable and Load OK
    PDB0->MOD = 1000;// the period of the PDB
    // AOS
    PDB0->SC |= PDB_SC_CONT_MASK; // run PDB in continuous mode
    PDB0->SC |= PDB_SC_TRGSEL(7); // set trigger selection to 7
    PDB0->SC |= PDB_SC_LDOK_MASK; // load values into the register
    PDB0->SC |= PDB_SC_PDBEN_MASK; // enables the PDB
    PDB0->SC |= PDB_SC_SWTRIG_MASK; // enable software trigger (start the PDB)
    */
    PDB0->SC |= PDB_SC_SWTRIG_MASK; // enable software trigger (start the PDB)
    
    //pc.printf("SampleArr: %08x\r\n", &sample_array1);
    //uint16_t* dma_csr = (uint16_t*) 0x4000901C;
    //uint32_t* dma_daddr = (uint32_t*) 0x40009010;
    //*dma_csr |= 1;
    
    // Start the sampling loop
    current_sample_index = WAITING_TO_BEGIN;
    Sampler.attach_us(&timed_sampling, SAMPLING_RATE);
    
    pc.printf("\r\n\r\n\r\n");
    
    while(1) {
        rotary_count++;
        if(pc.readable() > 0) {
            char temp = pc.getc();
            
            switch(temp) {
                case 's':
                    for(int i = 0; i < TOTAL_SAMPLES; i++) pc.printf("%i: %f\t",i,sample_array1[i]*3.3/65535);
                    
                    pc.printf("\r\n");
                    break;
                case 'f':
                    for(int i = 0; i < TOTAL_SAMPLES; i++) sample_array1[i] = 0;
                    break;
                    
            }
        }
        for(int i = 0; i < TOTAL_SAMPLES; i++) pc.printf("A%i: %f  ",i,sample_array1[i]*3.3/65535);
        for(int i = 0; i < TOTAL_SAMPLES; i++) pc.printf("B%i: %f  ",i,sample_array2[i]*3.3/65535);
        for(int i = 0; i < TOTAL_SAMPLES; i++) pc.printf("C%i: %i  ",i,angle_array[i]);
        pc.printf("\r");
        //pc.printf("DMA_DADDR: %08x                  \r", *dma_daddr);
        //pc.printf("A1: %f\tA2: %f\r\n", currA0, currA2);
        wait(1);
    }
}

void timed_sampling() {
    
    // Write to SC1A to start conversion with channel 12 PTB2
    //ADC0_SC1A = (ADC_SC1_ADCH(ADC_CHANNEL) | (ADC0_SC1A & (ADC_SC1_AIEN_MASK | ADC_SC1_DIFF_MASK))); 
    
    //__disable_irq();    // Disable Interrupts
    
    
    // The following performs analog-to-digital conversions - first reading the last conversion - then initiating another
    //uint32_t A0_value = adc_hal_get_conversion_value(0, 0); // ADC0_RA
    //uint32_t A2_value = adc_hal_get_conversion_value(1, 0);
    
    
    BW_ADC_SC1n_ADCH(0, 0, kAdcChannel12);      // This corresponds to starting an ADC conversion on channel 12 of ADC 0 - which is A0 (PTB2)
    BW_ADC_SC1n_ADCH(1, 0, kAdcChannel14);      // This corresponds to starting an ADC conversion on channel 14 of ADC 1 - which is A2 (PTB10)
    
    /*
    currA0 = (float) A0_value*3.3/65535;
    currA2 = (float) A2_value*3.3/65535;
    */
    
    // The following updates the rotary counter for the AMT20 sensor
    // Put A on PTC0
    // Put B on PTC1
    uint32_t AMT20_AB = HW_GPIO_PDIR_RD(HW_PORTC) & 0x03;
    if (AMT20_AB != last_AMT20_AB_read)
    {
        // change "INVERT_ANGLE" to change whether relative angle counts up or down.
        if ((AMT20_AB >> 1)^(last_AMT20_AB_read) & 1U)
        #if INVERT_ANGLE == 1
            {rotary_count--;}
        else
            {rotary_count++;}
        #else
            {rotary_count++;}
        else
            {rotary_count--;}
        #endif
        
        last_AMT20_AB_read = AMT20_AB;        
    }
    /*
    //current_sample_index = BEGIN_SAMPLING; // Used to force extra time.
    if (current_sample_index == WAITING_TO_BEGIN) {}
    else
    { 
        if (current_sample_index == BEGIN_SAMPLING) {
            current_sample_index = FIRST_SAMPLE_INDEX;
            }
            
        sample_array1[current_sample_index] = A0_value;
        sample_array2[current_sample_index] = A2_value;
        angle_array[current_sample_index] = rotary_count;
        
        if (current_sample_index == LAST_SAMPLE_INDEX) {
            current_sample_index = WAITING_TO_BEGIN;
            }
        else { current_sample_index++; }
    }
    */
    //__enable_irq();     // Enable Interrupts
}

void analog_initialization(PinName pin)
{
    ADCName adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
//    MBED_ASSERT(adc != (ADCName)NC);

    uint32_t instance = adc >> ADC_INSTANCE_SHIFT;

    clock_manager_set_gate(kClockModuleADC, instance, true);

    uint32_t bus_clock;
    clock_manager_get_frequency(kBusClock, &bus_clock);
    uint32_t clkdiv;
    for (clkdiv = 0; clkdiv < 4; clkdiv++) {
        if ((bus_clock >> clkdiv) <= MAX_FADC)
            break;
    }
    if (clkdiv == 4) {
        clkdiv = 0x7; //Set max div
    }
    // adc is enabled/triggered when reading.
    adc_hal_set_clock_source_mode(instance, (adc_clock_source_mode_t)(clkdiv >> 2));
    adc_hal_set_clock_divider_mode(instance, (adc_clock_divider_mode_t)(clkdiv & 0x3));
    adc_hal_set_reference_voltage_mode(instance, kAdcVoltageVref);
    adc_hal_set_resolution_mode(instance, kAdcSingleDiff16);
    adc_hal_configure_continuous_conversion(instance, false); // true=continuous conversion mode, false = single conversion mode
    adc_hal_configure_hw_trigger(instance, false); // true=hw trigger, false=sw trigger
    adc_hal_configure_hw_average(instance, false);
    adc_hal_set_hw_average_mode(instance, kAdcHwAverageCount4);
    adc_hal_set_group_mux(instance, kAdcChannelMuxB); // only B channels are avail 

    pinmap_pinout(pin, PinMap_ADC);
}



/*
    // read some registers for some info.
    uint32_t* dma_cr = (uint32_t*) 0x40008000;
    pc.printf("DMA_CR: %08x\r\n", *dma_cr);
    
    uint32_t* dma_eei = (uint32_t*) 0x40008014;
    pc.printf("DMA_EEI: %08x\r\n", *dma_eei);
    
    uint32_t* dma_erq = (uint32_t*) 0x4000800C;
    pc.printf("DMA_ERQ: %08x\r\n", *dma_erq);
    
    uint16_t* dma_csr = (uint16_t*) 0x4000901C;
    pc.printf("DMA_TD0_CSR: %04x\r\n\n", *dma_csr);
    
    uint32_t* dma_saddr = (uint32_t*) 0x40009000;
    pc.printf("DMA_SAADR: %08x\r\n", *dma_saddr);
    
    uint16_t* dma_soff = (uint16_t*) 0x40009004;
    pc.printf("DMA_SOFF: %04x\r\n", *dma_soff);
    
    uint16_t* dma_attr = (uint16_t*) 0x40009006;
    pc.printf("DMA_ATTR: %04x\r\n", *dma_attr);
    
    uint32_t* dma_minor = (uint32_t*) 0x40009008;
    pc.printf("DMA_MINOR: %08x\r\n", *dma_minor);
    
    uint32_t* dma_daddr = (uint32_t*) 0x40009010;
    pc.printf("DMA_DADDR: %08x\r\n", *dma_daddr);


    // read some registers for some info.
    pc.printf("DMA_CR: %08x\r\n", *dma_cr);
    pc.printf("DMA_EEI: %08x\r\n", *dma_eei);
    pc.printf("DMA_ERQ: %08x\r\n", *dma_erq);
    pc.printf("DMA_TD0_CSR: %04x\r\n\n", *dma_csr);
    pc.printf("DMA_SAADR: %08x\r\n", *dma_saddr);
    pc.printf("DMA_SOFF: %04x\r\n", *dma_soff);
    pc.printf("DMA_ATTR: %04x\r\n", *dma_attr);
    pc.printf("DMA_MINOR: %08x\r\n", *dma_minor);
    pc.printf("DMA_DADDR: %08x\r\n", *dma_daddr);
    pc.printf("SampleArr: %08x\r\n",&sample_array1);
*/