Jump to content
PTB

Stellaris fast analog reads

Recommended Posts

@@PTB

 

Almost one microsecond per read is really gootd. Consider that 1usec is the limit of the hardware! The 3usec may be do to the overhead of the call to micros! Energia has a bain-damaged micros/and millis method anyhow.

Try sample1=micros(); sampe2=micros(); Serail.prntln(sample2-sample1;

This will give you an idea of the overhead.

 

I am sorry I will not be able to help as I am leaving on a business trip tomorrow morning. :(  I will be back thursday. :wub:

 

If anyone is inerested here is my replacement for wiring.c to make timing more accurate. The old version had warp problems that limit the max value of millis to 65000 or so. I also only used 80mhz for the colck. I have enhanced it to used whatever frequency is defined by F_CPU.

 

changes are also needed to main and lm4fcpp.ld.

 

in main.c: Chare to call to timer_init:

int main(void){    // change timer_init to use requested clock frequency    // this means we may be able to change it on the fly if needed    timerInit(F_CPU);

Lm4fcpp.ld needs to be changed so the long long functions don't produce an error!

/** * * lm4fcpp.ld - Linker configuration file for Energia c++ programs. * */ MEMORY {    flash (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000     ram  (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 }REGION_ALIAS("REGION_TEXT", flash);REGION_ALIAS("REGION_RAM", ram);SECTIONS {    .text :    {        _text = .;        KEEP(*(.isr_vector))        *(.text .text* .gnu.linkonce.t.*)    } > REGION_TEXT        .preinit_array : {        . = ALIGN(4);        __preinit_array_start = .;        KEEP (*(SORT(.preinit_array*)))        KEEP (*(.preinit_array))        __preinit_array_end = .;    } > REGION_TEXT        .init_array :    {        . = ALIGN(4);        __init_array_start = .;        KEEP (*(SORT(.init_array.*)))        KEEP (*(.init_array))        __init_array_end = .;    } > REGION_TEXT        .rodata :    {        . = ALIGN(4);        *(.rodata .rodata* .gnu.linkonce.r.*)        . = ALIGN(4);    } > REGION_TEXT    .ARM.exidx : {        __exidx_start = .;        *(.ARM.exidx* .gnu.linkonce.armexidx.*)        __exidx_end = .;    } >REGION_TEXT    _etext = .;    .data :     {        . = ALIGN(4);        _data = .;        *(vtable)        *(.data .data* .gnu.linkonce.d.*)        _edata = .;    } > REGION_RAM AT > REGION_TEXT    .bss :    {        . = ALIGN(4);        _bss = .;         *(.bss .bss*)         *(COMMON)        . = ALIGN(4);         _ebss = .;         . = ALIGN(8);        _end = .;    } > REGION_RAM     _jkend = .;}/* end of allocated ram is start of heap, heap grows up towards stack*/PROVIDE(end = _end);/* top of stack starts at end of ram, stack grows down towards heap */PROVIDE (_estack = ORIGIN(ram) + LENGTH(ram));

 

 

Wiring.c

/* ************************************************************************ *  wiring.c * *  Arduino core files for MSP430 *      Copyright (c) 2012 Robert Wessels. All right reserved. * * ***********************************************************************  Derived from:  wiring.c - Partial implementation of the Wiring API for the ATmega8.  Part of Arduino - http://www.arduino.cc/  Copyright (c) 2005-2006 David A. Mellis  This library is free software; you can redistribute it and/or  modify it under the terms of the GNU Lesser General Public  License as published by the Free Software Foundation; either  version 2.1 of the License, or (at your option) any later version.  This library is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General  Public License along with this library; if not, write to the  Free Software Foundation, Inc., 59 Temple Place, Suite 330,  Boston, MA  02111-1307  USA */#include "Energia.h"#include <limits.h>#include "driverlib/rom_map.h"#include "driverlib/sysctl.h"#include "driverlib/timer.h"//// I have removed any frequency that is not an even number of MHZ// as this makes micros inaccurate//uint32_t freq_table[][2] ={    80000000,   SYSCTL_SYSDIV_2_5   | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  80,000,000      80    50000000,   SYSCTL_SYSDIV_4     | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  50,000,000      50    40000000,   SYSCTL_SYSDIV_5     | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  40,000,000      40    25000000,   SYSCTL_SYSDIV_8     | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  25,000,000      25    20000000,   SYSCTL_SYSDIV_10    | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  20,000,000      20    16000000,   SYSCTL_SYSDIV_1  | SYSCTL_RCC_BYPASS | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  16,000,000      16   raw osc    10000000,   SYSCTL_SYSDIV_20    | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  10,000,000      10     8000000,   SYSCTL_SYSDIV_2  | SYSCTL_RCC_BYPASS | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  8,000,000       8     5000000,   SYSCTL_SYSDIV_40    | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  5,000,000       5     4000000,   SYSCTL_SYSDIV_4  | SYSCTL_RCC_BYPASS | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ, //  4,000,000       4    0,          SYSCTL_SYSDIV_2_5   | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ  // if not in table default to 80mhz};// these// no need to call SysCtlClockGetuint32_t System_Frequency;uint32_t System_Frequency_Mhz;          // in Mhzvoid timerInit(uint32_t desiredFrequency){    uint16_t i;    // search for the frequency wanted    for (i=0;freq_table[i][0]!=0;i++)    {        if (desiredFrequency == freq_table[i][0] )        {            break;        }    }    // ok - got it (or the default)    // set it    SysCtlClockSet(freq_table[i][1]);    System_Frequency = SysCtlClockGet();    System_Frequency_Mhz = System_Frequency / 1000000;    // clocks per 1 us    // we are not using this anymore but keep it around.    // I may us it to give a time interrupt in my private OS/Supervisor if I need it    // set periodic to 1 ms    SysTickPeriodSet(System_Frequency / 10);    //100ms 1/10 second    SysTickEnable();    //    //Initialize WTimer4 to be used as time-tracker since beginning of time    //    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER4);    //not tied to launchpad pin    TimerConfigure(WTIMER4_BASE, TIMER_CFG_PERIODIC);    TimerLoadSet64(WTIMER4_BASE, 0xFFFFFFFFFFFFFFFFl);    //start at -1 and count down    TimerEnable(WTIMER4_BASE, TIMER_A);}inline unsigned long micros(void){    // get the time value ond convert to positive    unsigned long long cycles = ~ROM_TimerValueGet64(WTIMER4_BASE);    // divide by clock in mhz - give micro seconds    cycles /= System_Frequency_Mhz;    return (cycles);}unsigned long millis(void){    unsigned  long long cycles = ~ROM_TimerValueGet64(WTIMER4_BASE);    cycles /= (System_Frequency / 1000ll); // note: that is LL at the end not 11!     return (cycles);}/* Delay for the given number of microseconds.  */void delayMicroseconds(unsigned int us){    unsigned long currTime;    unsigned long endTime;    endTime = micros() + us;    do    {        currTime = micros();    }    while (currTime <= endTime);}void delay(uint32_t milliseconds){    unsigned long i;    for (i = 0; i < milliseconds; i++)    {        delayMicroseconds(1000);    }}

Share this post


Link to post
Share on other sites

Well, here is my 2 cents.

 

Im working on a kind of DSO using the stellaris launchpad, and visual basic 2010.

 

Right now, the stellaris can sample in 1 channel (pin PA7) at different speeds, selectable via serial port commands. Right now, it can sample at 1Msps (890Ksps real), 500Ksps, 250Ksps, 125Ksps using ADC interrupt, and 64ksps, 32ksps, 16ksps, 8ksps, and 2 ksps using timer interrupt.

 

My code samples a 4096 samples buffer, and when receives the "c" command, it sends the values stored in the buffer in ASCII over the serial port, and the its plotted on the VB app. pretty simple, but for me resulted very useful.

 

Here is my code

// stelarisDSO v1.0
// 2013-07-20
// buffer de 4096 muestras
// 

#include "Energia.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/timer.h"

#define numDatos 4095

int i=0;
int j=1;
int adc[numDatos];
unsigned char dataReady=0;
unsigned long ulADC0Value[1];
int datosListos=0;
int datoActual=0;




void setup() {
  int i;
  Serial.begin(115200);
  pinMode(RED_LED, OUTPUT);
  pinMode(BLUE_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
 
  
  for (i=0;i<=4;i++) {
    digitalWrite(GREEN_LED,1);
    digitalWrite(RED_LED,1);
    digitalWrite(BLUE_LED,1);
    delay(100);
    digitalWrite(GREEN_LED,0);
    digitalWrite(RED_LED,0);
    digitalWrite(BLUE_LED,0);
    delay(100);
  }
  
   
  
  Serial.println("Stellaris DSO");
  Serial.println("(c) 2013 www.patolin.com");
  Serial.println("Inicio OK. ");
  Serial.print(SysCtlClockGet());
  Serial.println(" hz");
  
  initADC(0,0);  
  ADCIntDisable(ADC0_BASE, 3);
  initTimer(500);
  
}






void loop() {
  int valor;
  unsigned timerADC=500;
  unsigned velADC=0;
  unsigned char serialIn;
  char tipoSampling=1;   // 0=ADC int, 1=TIMER int
  
  // esperamos comando para la velocidad de muestreo
  while (1) {
    if (Serial.available()==1) {
        serialIn=Serial.read();
        
        switch (serialIn) {
           case 's':
               // status
               Serial.println("Ok."); 
               break;
           case 'c':
               // devuelve los datos del buffer
               
               
                // esperamos a los datos
               while (!datosListos) {}
               // paramos las interrupciones
               TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
               ADCIntDisable(ADC0_BASE, 3);
                 datosListos=0;
                 datoActual=0;
                 //enviamos los datos por el puerto serie
                 Serial.println(numDatos);
                 for (i=0;i<=(numDatos-1);i++) {
                     Serial.println(adc[i]);
                 }
               // reiniciamos las interrupciones
               if (tipoSampling==1) {
                 TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
               } else {
                 ADCIntEnable(ADC0_BASE, 3);
               }
               break;
           case '1':
               // 1ksps
               timerADC=500;
               tipoSampling=1;
               break;
           case '2':
               // 2ksps
               timerADC=1000;
               tipoSampling=1;
               break;
           case '3':
               // 4ksps
               timerADC=2000;
               tipoSampling=1;
               break;
           case '4':
               // 8ksps
               timerADC=4000;
               tipoSampling=1;
               break;    
           case '5':
               // 16ksps
               timerADC=8000;
               tipoSampling=1;
               break;
           case '6':
               // 32ksps
               timerADC=16000;
               tipoSampling=1;
               break;
           case '7':
               // 64ksps
               timerADC=32000;
               tipoSampling=1;
               break;
           case '8':
               // 125ksps
               timerADC=0000;
               velADC=0;
               tipoSampling=0;
               break;
           case '9':
               // 250ksps
               timerADC=0000;
               velADC=1;
               tipoSampling=0;
               break;
           case 'A':
               // 500ksps
               timerADC=0000;
               velADC=2;
               tipoSampling=0;
               break;
           case 'B':
               // 1Msps
               timerADC=0000;
               velADC=3;
               tipoSampling=0;
               break;
           
        }
        // inicializamos el timer o el ADC segun el caso
        datosListos=0;
        datoActual=0;
        if (tipoSampling==0) {
            // ADC por interrupcion
            TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
            initADC(velADC,1);
            digitalWrite(RED_LED, 0x00);  
            digitalWrite(BLUE_LED, 0x01);
        } else {
            ADCIntDisable(ADC0_BASE, 3);
            initTimer(timerADC);
            digitalWrite(RED_LED, 0x00);  
            digitalWrite(BLUE_LED, 0x00);
        }
      }  
  }
  
}


int capturaADC() {
    ADCIntClear(ADC0_BASE, 3);
    ADCProcessorTrigger(ADC0_BASE, 3);
    while(!ADCIntStatus(ADC0_BASE, 3, false)) { }	
    ADCSequenceDataGet(ADC0_BASE, 3, ulADC0Value);
    return (int)ulADC0Value[0];
}



void Timer0IntHandler()
{
  TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  digitalWrite(RED_LED, j&0x01);  
  j++;
  adc[datoActual]=capturaADC();
  datoActual++;
  
  if (datoActual>numDatos) {
     datosListos=1; 
     datoActual=0;
  }
}

void ADC0IntHandler() {
   ADCIntClear(ADC0_BASE,3);
   ADCSequenceDataGet(ADC0_BASE, 3, ulADC0Value);
   adc[datoActual]=(int)ulADC0Value[0];  
   datoActual++;
   if (datoActual>numDatos) { datoActual=0;  datosListos=1; ADCIntDisable(ADC0_BASE, 3);}
}

void initTimer(unsigned Hz)
{
  SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
  TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
  unsigned long ulPeriod = (SysCtlClockGet() / Hz) / 2;
  TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod -1);
  IntEnable(INT_TIMER0A);
  TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0IntHandler);
  TimerEnable(TIMER0_BASE, TIMER_A);
  
}

void initADC(int velocidad, int trigger) {
        /* 
          Velocidad: 0=1msps,1=500ksps,2=250ksps,3=125ksps
          trigger: 0=processor, 1=always
        */
          
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        switch(velocidad) {
           case 3:
               SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
               break;
           case 2:
               SysCtlADCSpeedSet(SYSCTL_ADCSPEED_500KSPS);
               break;
           case 1:
               SysCtlADCSpeedSet(SYSCTL_ADCSPEED_250KSPS);
               break;
           case 0:
               SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS);
               break;
           default:
               SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
               break;
        }
	
        ADCSequenceDisable(ADC0_BASE, 3);
        if (trigger==0) {
          ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
          
        } else {
          ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 0);  
          
          
        }
	ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); 
	//ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE | ADC_CTL_END); //Secuencia de ejemplo para el medidor de temperatura interno
        ADCIntRegister(ADC0_BASE, 3, ADC0IntHandler);
        ADCIntEnable(ADC0_BASE, 3);
	ADCSequenceEnable(ADC0_BASE, 3);
        ADCProcessorTrigger(ADC0_BASE, 3);
        
}

Im writing a detailed post for my blog, so I hope it can be useful for you guys. You can check a preview (in spanish) in http://patolin.com/blog/2013/07/07/osciloscopio-con-stellaris-launchpad-actualizacion/

 

Here is a capture image, of a RC transmitter PPM frame, at 125Ksps, 10 bits, using a 4096 sample buffer

 

dso1.png

Share this post


Link to post
Share on other sites

Ok I thought I would see if I had learned something.... it appears not. :huh:

 

I tried to make a fast digital read and write.... they are terrible. Slower than the standard command.

///**************************************************************************
///
///                         Fast Digital Read Routine
///
///**************************************************************************
uint16_t fast_digitalRead(uint8_t pin) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    uint32_t value;
    GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_IN);
//    value = GPIOPinRead(ulPort, ucPins);
    value = (HWREG( ulPort  + (GPIO_O_DATA + (ucPins << 2))));
    return value;
}    
///**************************************************************************
///
///                         Fast Digital Write Init Routine
///
///**************************************************************************
uint16_t fast_digitalWriteInit(uint8_t pin) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_OUT);
    return 1;
}    

///**************************************************************************
///
///                         Fast Digital Write Routine
///
///**************************************************************************
uint16_t fast_digitalWrite(uint8_t pin, unsigned char ucVal) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    uint32_t value;
//    GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_OUT);
//    GPIOPinWrite(ulPort, ucPins, ucVal);
    (HWREG( ulPort  + (GPIO_O_DATA + (ucPins << 2)))) = ucVal;
    return 1;
}    

Is there a better way ? If the fastanalogread is so fast... surely a digital read and write could be equivalent in speed?

 

Cheers

 

PTB

Share this post


Link to post
Share on other sites

@@PTB,

 

in fast digital read:

Move GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_IN); to ant init routine. Ony dnnest to be done before the read.

 

use constants if possble in fast digial read:

 

For port a pin 2 PA2

 

#define PORT_A GPIOA_BASE

#define PIN2 ( (1<<2)<<2)

 

 

value = (HWREG( PORT_A + (GPIO_O_DATA +PIN2));

 

The you can build somthing like the following:

 

#define PORT_A GPIOA_BASE

#define PIN2 ((1<<2)

#define NUMBER_VALUES 4096

uint32_t pa2 _values[NUMBER_VALUES+1];

void fast_read_PA2(void)

{

    int i;

   uint32_t *pValues=&VALUES[0]

  GPIODirModeSet(PORT_A,,PIN2, GPIO_DIR_MODE_OUT);

 

 FOR =0;I<number_values;i++,pValues++)

{

   

   *Pvalues = HWREG( PORT_A + (GPIO_O_DATA +PIN2));

}

 

Untested. Use at your ownrisk.

 

I am still traveling.

 

 

Johnk

Share this post


Link to post
Share on other sites

@@jkabat

 

Ok, I'm not sure what the intention of the "number_values" is but your post has given me more experimentation ideas.

 

I tried a multitude of setups all reading or writing 1000 samples.

 

Here are the results and the code portions used to generate them.

My favourites are the Fast digital read/write separated routines which give results of 451 and 401 microseconds for 1000 samples and are still flexible codewise. That's 2 operations every microsecond.

 

This one is just a learning exercise as the standard digital read and write commands are fast enough for what I want.

 

Cheers

 

PTB

Standard digital write 
==============
Number of Samples : 1000

Sample Starttime : 5000001

Sample Endtime : 5000802

Sample Array Set Duration time in microseconds  : 801




********************************************************************************************
Standard digital read 
==============

Number of Samples : 1000

Sample Starttime : 22129001

Sample Endtime : 22129777

Sample Array Set Duration time in microseconds  : 776


********************************************************************************************
Fast digital read 
===========

Number of Samples : 1000

Sample Starttime : 19131001

Sample Endtime : 19132102

Sample Array Set Duration time in microseconds  : 1101



Code
===

uint16_t fast_digitalRead(uint8_t pin) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    uint32_t value;
    GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_IN);
    value = (HWREG( ulPort  + (GPIO_O_DATA + (ucPins << 2))));
    return value;
}    

********************************************************************************************
Fast digital read separated routines
=======================

Number of Samples : 1000

Sample Starttime : 26000002

Sample Endtime : 26000453

Sample Array Set Duration time in microseconds  : 451

Code
===

uint16_t fast_digitalReadInit(uint8_t pin) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_IN);
    return 1;
}    


uint16_t fast_digitalRead(uint8_t pin) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    uint32_t value;
    value = (HWREG( ulPort  + (GPIO_O_DATA + (ucPins << 2))));
    return value;
}    

********************************************************************************************
Fast digital write separated routines 
=======================

Number of Samples : 1000

Sample Starttime : 26129002

Sample Endtime : 26129403

Sample Array Set Duration time in microseconds  : 401


Code
===

uint16_t fast_digitalWriteInit(uint8_t pin) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_OUT);
    return 1;
}

uint16_t fast_digitalWrite(uint8_t pin, unsigned char ucVal) {
    uint8_t ulPort = digitalPinToPort(pin);
    uint32_t ucPins = digitalPinToBitMask(pin);
    uint32_t value;
    (HWREG( ulPort  + (GPIO_O_DATA + (ucPins << 2)))) = ucVal;
    return 1;
}
********************************************************************************************
Fast digital write separated routines - Hard coded Port PD3 
======================================

Number of Samples : 1000

Sample Starttime : 45000002

Sample Endtime : 45000103

Sample Array Set Duration time in microseconds  : 101


Code
===

uint16_t fast_digitalWriteInit_PD3() {
    GPIODirModeSet(GPIO_PORTD_BASE, GPIO_PIN_3, GPIO_DIR_MODE_OUT);
    return 1;
}

uint16_t fast_digitalWrite_PD3(unsigned char ucVal) {
    uint32_t value;
    (HWREG( GPIO_PORTD_BASE  + (GPIO_O_DATA + (GPIO_PIN_3 << 2)))) = ucVal;
    return 1;
}    
********************************************************************************************
Fast digital read separated routines - Hard coded Port PD3 
======================================

Number of Samples : 1000

Sample Starttime : 7000002

Sample Endtime : 7000128

Sample Array Set Duration time in microseconds  : 126

Code
===

uint16_t fast_digitalReadInit_PD3() {
    GPIODirModeSet(GPIO_PORTD_BASE, GPIO_PIN_3, GPIO_DIR_MODE_IN);
    return 1;
}

uint16_t fast_digitalRead_PD3() {
    uint32_t value;
    value = (HWREG( GPIO_PORTD_BASE  + (GPIO_O_DATA + (GPIO_PIN_3 << 2))));
    return value;
}    



Share this post


Link to post
Share on other sites

Hi,

 

I worked on with the DSO of Patolin Posted 30 July 2013.

 

Here is my code.

 

// stelarisDSO v1.2
// 2014-04-24
// 1 channel differencial @ 2 Msps or 2 channel diff. @ 1 Msps max.

#include "Energia.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/lm4f120h5qr.h"    // for register access ii faster ADCinterupt handling
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/timer.h"

#define buffersize 2048

unsigned long size = 2047;  // 63, 127, 255, 511, 1023 or 2047.   * use only 2^n -1
unsigned long aux0;
unsigned long aux1;
unsigned long aux2;
unsigned long  adc0[buffersize ] = { 0} ; // unsigned int wil do, but u-long takes up the same RAMspace
unsigned long  adc1[buffersize ] = { 0}; // and saves time in the int-serviceroutine (no convertion required)
byte oversample = 1;
/* hardware average factor,
 0, 1, 2, 4, 8, 16, 32 or 64
 0 = (sum of) ADC0 and ADC1 for single channel 2MSPS,
 */
byte oversample5 = 0;
/*    0= soft-average ADC0 and ADC1 for single channel 2MSPS,
 1= no soft-average
 5 = 5 sampels soft-average in 1 interupt,  
 25 = 25  sampels soft-average
 */
byte pass = 1;
byte mult = 5; // results are 5 * ADC-values = 0 - 20480  (12 to 14¼ bits ).
unsigned long adc0sum; // for soft-average
unsigned long adc1sum;
unsigned int dataReady=0;
unsigned int pointer=0;

void setup() {
  int count;
  Serial.begin(115200);
  pinMode(RED_LED, OUTPUT);
  pinMode(BLUE_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);

  for (count=0;count<4;count++) {
    digitalWrite(GREEN_LED,1);
    delay(100);
    digitalWrite(RED_LED,1);
    delay(100);
    digitalWrite(BLUE_LED,1);
    delay(100);
    digitalWrite(GREEN_LED,0);
    delay(100);
    digitalWrite(RED_LED,0);
    delay(100);
    digitalWrite(BLUE_LED,0);
    delay(100);
  }
  Serial.println("Stellaris 2 channel DSO");
  Serial.println("Based on work from 2013 www.patolin.com");
  Serial.println("and http://forum.stellarisiti.com/topic/684 ");
  Serial.print(SysCtlClockGet());
  Serial.println(" hz systemclock ");
  Serial.println("   ");
  Serial.println(" c to start  ? for keys ");
  initADC();
  // tone(GREEN_LED,10000); testsignal, not tested yet
}


void loop() {
  int count;
  String text("  ?                   ");
  unsigned char serialin;
  while (1) {
    if (Serial.available()>0) {
      serialin=Serial.read();
      switch (serialin) {
      case 'a':
        size = 63;
        break;
      case 's':
        size = 126;
        break;
      case 'd':
        size = 255;
        break;
      case 'f':
        size = 511;
        break;
      case 'g':
        size = 1023;
        break;
      case 'h':
        size = 2047;
        break;

      case 'c':     // convert and output the results
        while (!dataReady) {   // wait for full databuffer
        }
        // disable interupts == stop aquisition
        ADCIntDisable(ADC0_BASE, 0);
        ADCIntDisable(ADC0_BASE, 3);
        delay(2); // be shure last interupt is done
        //Serial.println(size + 1); number of datapoints
        // Data is output in a format for "SerialChart" (www.Starlino.com)

        for (count=0 ; count < size+1 ; count++) {
          //Serial.print(pointer); // start print where ADC stopped
          Serial.print(",");
          if (!oversample) {           // single channel
            aux0 = (adc0[pointer]);
            aux1 = (adc1[pointer]);
            aux2 = (adc0[(++pointer &= size) ]);
            Serial.println((aux0 + aux1) * mult / 2  );
            Serial.print(",");
            Serial.println((aux0 + aux2) * mult / 2 );     
          }
          else {   // 2 channels
            Serial.print((adc0[pointer]) * mult);  // start print where ADC stopped
            Serial.print(",");
            Serial.println((adc1[pointer]) * mult);
            ++pointer &= size;
          }
        }
        break;
      case 'q':
        text = String("  500 sps 2 channels ");
        oversample=16;
        oversample5=25;
        mult = 1;
        break;
      case '1':
        text = String("    1 ksps 2 channels ");
        oversample=8;
        oversample5=25; // 8 * 5 * 5 * 5 =  / 1000
        mult = 1;
        break;
      case '2':
        text = String("    2 ksps 2 channels ");
        oversample=4;
        oversample5=25;  // 4 * 5 * 5 * 5 =  / 500
        mult = 1;
        break;
      case '3':
        text = String("    5 ksps 2 channels ");
        oversample=8;
        oversample5=5;
        mult = 1;
        break;    
      case '4':
        text = String("   10 ksps 2 channels ");
        oversample=4;
        oversample5=5; // 4 * 5 * 5 = / 100
        mult = 1;
        break;
      case '5':
        text = String("   25 ksps 2 channels ");
        oversample=8;
        oversample5=1;
        mult = 1;
        break;
      case '6':
        text = String("   50 ksps 2 channels ");
        oversample=4;
        oversample5=1;
        mult = 1;
        break;
      case '7':
        text = String("  100 ksps 2 channels ");
        oversample=2;
        oversample5=1; // 2 * 5 = / 10
        mult = 1;
        break;
      case '8':
        text = String("  250 ksps 2 channels ");
        oversample=4;
        oversample5=0;
        mult = 5;
        break;
      case '9':
        text = String("  500 ksps 2 channels ");
        oversample=2;
        oversample5=0;
        mult = 5;
        break;
      case '0':
        text = String("    1 Msps 2 channels ");
        oversample=1;
        oversample5=0;
        mult = 5;
        break;
      case '-':
        text = String("    2 Msps single channel ");
        oversample=0;
        oversample5=0;
        mult = 5;
        break;
      default:
        text = String("???? ");
        Serial.println(" .  ");
        Serial.println("For samplerate hit  :");
        Serial.println(" q,  1,  2,  3,  4,   5,   6,   7,    8,    9,    0 or  -    ");
        Serial.println("500, 1k, 2k, 5k, 10k, 25k, 50k, 100k, 200k, 500k, 1M or 2M ");
        Serial.println("   ");
        Serial.println("For bufferssize : hit");
        Serial.println(" a,  s,    d,   f,   g  or h      ");
        Serial.println(" 64, 128, 256, 512, 1024, 2048  bufferssize");
        Serial.println(" .  ");
        Serial.println(" c to start  ");
      }
      Serial.print(text);
      Serial.print("  oversample: ");
      Serial.print(oversample);
      Serial.print("  oversample5: ");
      Serial.print(oversample5);
      Serial.print("  buffersize: ");
      Serial.println(size + 1 );

      initADC(); // restart conversions
      digitalWrite(RED_LED, 0x00);  
      digitalWrite(BLUE_LED, 0x01);
    }  
  }
}   // end of loop


void ADC0IntHandler_0Fast() {
  ADCIntClear(ADC0_BASE,0);   // sequencer 0

    adc0[pointer] = ADC0_SSFIFO0_R ;  //step0
  adc1[pointer] = ADC1_SSFIFO0_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO0_R ;  //step1
  adc1[pointer] = ADC1_SSFIFO0_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO0_R ;  //step2
  adc1[pointer] = ADC1_SSFIFO0_R;

  if (!(++pointer  &= size)) dataReady=1;


  adc0[pointer] = ADC0_SSFIFO0_R ;  //step3
  adc1[pointer] = ADC1_SSFIFO0_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO0_R ;  //step4
  adc1[pointer] = ADC1_SSFIFO0_R;

  if (!(++pointer  &= size)) dataReady=1;

}

void ADC0IntHandler_3Fast() {
  ADCIntClear(ADC0_BASE,3);   // sequencer 1 and 3

    adc0[pointer] = ADC0_SSFIFO1_R ;  //step0
  adc1[pointer] = ADC1_SSFIFO1_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO1_R ;  //step1
  adc1[pointer] = ADC1_SSFIFO1_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO1_R ;  //step2
  adc1[pointer] = ADC1_SSFIFO1_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO1_R ;  //step3
  adc1[pointer] = ADC1_SSFIFO1_R;

  if (!(++pointer  &= size)) dataReady=1;

  adc0[pointer] = ADC0_SSFIFO3_R ;  //step0
  adc1[pointer] = ADC1_SSFIFO3_R;

  if (!(++pointer  &= size)) dataReady=1;

}

void ADC0IntHandler_0Av() {
  ADCIntClear(ADC0_BASE,0);

  adc0sum += (ADC0_SSFIFO0_R + ADC0_SSFIFO0_R + ADC0_SSFIFO0_R + ADC0_SSFIFO0_R + ADC0_SSFIFO0_R)  ;  //sum step 0,1,2,3,4  sequ 0
  adc1sum += (ADC1_SSFIFO0_R + ADC1_SSFIFO0_R + ADC1_SSFIFO0_R + ADC1_SSFIFO0_R + ADC1_SSFIFO0_R)  ;

  if (!--pass ) {
    pass = oversample5;
    adc0[pointer] = adc0sum /oversample5;
    adc1[pointer] = adc1sum /oversample5;
    adc0sum = 0;
    adc1sum = 0;
    ++pointer &= size;
  }
  if (!pointer) dataReady=1;
}


void ADC0IntHandler_3Av() {
  ADCIntClear(ADC0_BASE,3);

  adc0sum += (ADC0_SSFIFO1_R + ADC0_SSFIFO1_R + ADC0_SSFIFO1_R + ADC0_SSFIFO1_R + ADC0_SSFIFO3_R) ;  //sum step 0, 1, 2,3 sequ.1 +
  adc1sum += (ADC1_SSFIFO1_R + ADC1_SSFIFO1_R + ADC1_SSFIFO1_R + ADC1_SSFIFO1_R + ADC1_SSFIFO3_R)  ;  // step 0 sequ.3

  if (!--pass ) {
    pass = oversample5;
    adc0[pointer] = adc0sum / oversample5 ;
    adc1[pointer] = adc1sum /oversample5 ;
    adc0sum = 0;
    adc1sum = 0;
    ++pointer &= size;
  }
  if (!pointer) dataReady=1;
}


void initADC() {
  SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); // first ADCspeed then Enable
  SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);

  ADCSequenceDisable(ADC0_BASE, 0);            // use sequencer 0 (5 of 8 steps) first
  ADCSequenceDisable(ADC1_BASE, 0);            // and sequencer 1+3 (4+1=5 steps) in ping-pong*
  ADCSequenceDisable(ADC0_BASE, 1);            
  ADCSequenceDisable(ADC1_BASE, 1);
  ADCSequenceDisable(ADC0_BASE, 3);            
  ADCSequenceDisable(ADC1_BASE, 3);

  /*
ping-pong in this case is:
   ping: first take autonome 5 samples, raise interupt and end sequence 0.
   Interup-routine handles these 5 samples WHILE   
   pong: sequencer 1 takes the next 4 samples and sequencer 3 the 5st
   sequencer 3 raise interupt and end sequence.
   Interup-routine handles these 5 samples WHILE  
   ping; sequencer 3's "end sequence" starts the ping (sequence 0) again.
   */
  ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);  // priority 0
  ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
  ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_ALWAYS, 1);  // priority 1
  ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_ALWAYS, 1);
  ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_ALWAYS, 2);  // priority 2
  ADCSequenceConfigure(ADC1_BASE, 3, ADC_TRIGGER_ALWAYS, 2);

  if (!oversample )   { // 2Msps on chan.0
    ADCPhaseDelaySet(ADC0_BASE,  ADC_PHASE_270);
    ADCPhaseDelaySet(ADC1_BASE,  ADC_PHASE_90);

    //ping
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 |ADC_CTL_D );  // sequencer 0, step 0, chan 0, Differential
    ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH0 |ADC_CTL_D );   // ADC1 same as ADC0
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH0 |ADC_CTL_D); // sequencer 0, step 1
    ADCSequenceStepConfigure(ADC1_BASE, 0, 1, ADC_CTL_CH0 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0 |ADC_CTL_D); //  step 2
    ADCSequenceStepConfigure(ADC1_BASE, 0, 2, ADC_CTL_CH0 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH0 |ADC_CTL_D); //  step 3
    ADCSequenceStepConfigure(ADC1_BASE, 0, 3, ADC_CTL_CH0 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH0 |ADC_CTL_D | ADC_CTL_IE | ADC_CTL_END); //  step 4
    ADCSequenceStepConfigure(ADC1_BASE, 0, 4, ADC_CTL_CH0 |ADC_CTL_D | ADC_CTL_END); // 1 interupt serves both ADC's

    //pong
    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH0 |ADC_CTL_D ); // sequencer 1, step 0
    ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH0 |ADC_CTL_D );   
    ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH0 |ADC_CTL_D); // step 1
    ADCSequenceStepConfigure(ADC1_BASE, 1, 1, ADC_CTL_CH0 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH0 |ADC_CTL_D); // step 2
    ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_CH0 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH0 |ADC_CTL_D| ADC_CTL_END); //  step 3 end sequencer 1 and
    ADCSequenceStepConfigure(ADC1_BASE, 1, 3, ADC_CTL_CH0 |ADC_CTL_D| ADC_CTL_END); // continue with sequencer 3
    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 |ADC_CTL_D | ADC_CTL_IE | ADC_CTL_END ); //  sequencer 3, step 0
    ADCSequenceStepConfigure(ADC1_BASE, 3, 0, ADC_CTL_CH0 |ADC_CTL_D | ADC_CTL_END ); // only ADC_0 with interupt, it serves both
  }
  else{
    ADCPhaseDelaySet(ADC0_BASE,  ADC_PHASE_90);
    ADCPhaseDelaySet(ADC1_BASE,  ADC_PHASE_90);

    //ping
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 |ADC_CTL_D ); // sequencer 0, step 0
    ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH1 |ADC_CTL_D );   // ADC1 same as ADC0
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH0 |ADC_CTL_D); // sequencer 0, step 1
    ADCSequenceStepConfigure(ADC1_BASE, 0, 1, ADC_CTL_CH1 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH0 |ADC_CTL_D); //  step 2
    ADCSequenceStepConfigure(ADC1_BASE, 0, 2, ADC_CTL_CH1 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH0 |ADC_CTL_D); //  step 3
    ADCSequenceStepConfigure(ADC1_BASE, 0, 3, ADC_CTL_CH1 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH0 |ADC_CTL_D | ADC_CTL_IE | ADC_CTL_END); //  step 4
    ADCSequenceStepConfigure(ADC1_BASE, 0, 4, ADC_CTL_CH1 |ADC_CTL_D | ADC_CTL_END); // 1 interupt serves both ADC's

    //pong
    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH0 |ADC_CTL_D ); // sequencer 1, step 0
    ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH1 |ADC_CTL_D );   
    ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH0 |ADC_CTL_D); // step 1
    ADCSequenceStepConfigure(ADC1_BASE, 1, 1, ADC_CTL_CH1 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH0 |ADC_CTL_D); // step 2
    ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_CH1 |ADC_CTL_D);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH0 |ADC_CTL_D| ADC_CTL_END); //  step 3
    ADCSequenceStepConfigure(ADC1_BASE, 1, 3, ADC_CTL_CH1 |ADC_CTL_D| ADC_CTL_END); // continue with sequencer 3
    ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 |ADC_CTL_D | ADC_CTL_IE | ADC_CTL_END ); //  sequencer 3, step 0
    ADCSequenceStepConfigure(ADC1_BASE, 3, 0, ADC_CTL_CH1 |ADC_CTL_D | ADC_CTL_END ); // only ADC_0 with interupt, it serves both
  }
  ADCIntRegister(ADC0_BASE, 0, ADC0IntHandler_0Fast);   // set interupt-handler adress
  ADCIntRegister(ADC0_BASE, 3, ADC0IntHandler_3Fast);

  if (oversample5) {
    ADCIntRegister(ADC0_BASE, 0,  ADC0IntHandler_0Av );  // overwrite interupt-handler adress
    ADCIntRegister(ADC0_BASE, 3,  ADC0IntHandler_3Av );  
  }
  ADCHardwareOversampleConfigure(ADC0_BASE, oversample);  
  ADCHardwareOversampleConfigure(ADC1_BASE, oversample);

  dataReady=0;
  pointer=0;
  adc0sum = 0;
  adc1sum = 0;
  pass = oversample5;

  ADCSequenceEnable(ADC0_BASE, 0);
  ADCSequenceEnable(ADC1_BASE, 0);

  ADCSequenceEnable(ADC0_BASE, 1);
  ADCSequenceEnable(ADC1_BASE, 1);

  ADCSequenceEnable(ADC0_BASE, 3);
  ADCSequenceEnable(ADC1_BASE, 3);

  ADCIntEnable(ADC0_BASE, 0);
  ADCIntEnable(ADC0_BASE, 3);  // and enable interupt
}






























 

Share this post


Link to post
Share on other sites

This last entry of me (tonrei) is not working the way I discribed.

The ping-pong trick does not work, all the samples come from the same sample-sequencer.

That is because the Trigger "ALWAYS"  instruction for the hiest priority sequencer blocks the other sample-sequencers.

 

I'm now using the connected launchpad for a further development of the DSO.

 

If I caused someone a headache ........... apollagies

Share this post


Link to post
Share on other sites

Ok,

I'm going to try and make time for finishing off my project. http://forum.43oh.com/topic/7346-stellaris-launchpad-camera-flash-timer-and-measurement-tool/?p=59708

I have many questions.... but I am just going to post and solve 1 by 1

When I started it.... the Tiva didnt exist and its all been stellaris. I have tried to run it on Tiva but it wouldnt work for some reason.
That doesnt bother me as I have a few Stellari (Is that a word ?)

The big thing is I have decided to move it forward from Energia 9 to Energia 15. (and stay up to date from there) The reason I havent to date is because I had dramas getting it to run on later versions of energia..... I dont know why.
I ended up coding in 9 and watching all the releases slip by.

Anyway, Most of the code appears to be working including I2C eeprom's, RobG's touchscreen and the SD card. Which is great.

What isnt so great is the Fast Analog Read (which was a crucial element) no longer runs. It hangs the program.
There was a lot of black magic in that subroutine and my simple mind and I cant get it going.
I've compared the energia files and I can see changes in there regarding variable types and other stuff, but I dont know what has upset my program.

I went back to the original simple testing sketches for fast analog read and they dont work either under Energia 15.

The test code below has been tested and runs under
Energia 9
Energia 10

It does NOT run under
Energia 11
Energia 12
Energia 15

I never installed 13 or 14

So it appears something change between 10 and 11 which I need to account for. Trouble is.... I cant find it.

JKabat had pretty much created that routine for me plus there was help from some other forum members. Unfortunately I havent seen JKabat here for quite some time.

That routine was in this thread at post No. 30
http://forum.43oh.com/topic/7153-stellaris-fast-analog-reads/?p=58681

I changed the unsigned long to uint32_t throughout the routine, but that seems to have made no difference.

I know the exact line it hangs on and it is marked in this updated version of the code

HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER;

// 
// LM4F_ADC 
// A Stellarisiti Collaborative effort 
// JKabat, Rei Vilo, reaper7, PTB.
//

// Include application, user and local libraries

// Define variables and constants
///
/// @file	Fast_Analog_Read.ino
/// @brief	Main sketch
///
/// @details	Fast Analog Read Investigations for Stellaris LM4F
///

//
// Stellaris Pin Assignments
// =========================
//PE_3    //Sensor Analog Read
//PA_5    //Trigger Analog Signal Pulse
//PF_4    //Push Button to Start

//
// Libraries
// =========
#include "Energia.h"
#include "SPI.h"
#include "inc/lm4f120h5qr.h"


#include "inc/hw_adc.h"
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"

#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"


//
// Constants from adc.c
// ====================
#define ADC_SEQ                 (ADC_O_SSMUX0)
#define ADC_SEQ_STEP            (ADC_O_SSMUX1 - ADC_O_SSMUX0)
#define ADC_SSFIFO              (ADC_O_SSFIFO0 - ADC_O_SSMUX0)
#define ADC_SSFSTAT             (ADC_O_SSFSTAT0 - ADC_O_SSMUX0)

#define SEQUENCER   0


//
// Global Constants
// ================
const byte SampleQty = 255;               // number of samples  
const uint16_t buttonPin = PUSH1;         // the number of the pushbutton pin
const uint16_t ledPin =  GREEN_LED;       // the number of the LED pin
const uint16_t TriggerPin = PA_5;         // Analog Signal Trigger connected to digital pin PA_5


//
// Global Variables
// ================

uint16_t SampleTest;
uint16_t buttonState = 0;         // variable for reading the pushbutton status
uint16_t Sample[SampleQty];       // Array variable to store the value coming from the sensor
//unsigned long SampleStartTime;
uint32_t SampleStartTime;
//unsigned long SampleEndTime;
uint32_t SampleEndTime;
//unsigned long SampleDuration;
uint32_t SampleDuration;

//unsigned long faBase;
uint32_t faBase;

//
// Prototypes
// ==========
  uint16_t fast_analogInit(uint8_t pin);
  uint16_t fast_analogRead(void);


///**************************************************************************
///
///                                   Setup code
///
///**************************************************************************
void setup() {
Serial.begin(9600) ;               //Debugging initialize the serial communication:
pinMode(ledPin, OUTPUT);           // initialize the LED pin as an output:    
pinMode(buttonPin, INPUT_PULLUP);  // initialize the pushbutton pin as an input:
pinMode(TriggerPin, OUTPUT);       // initialize the Trigger pin as an output: 
Serial.println("Stellaris Fast Analog Read");
Serial.println("==========================");
Serial.println("");
Serial.println("Press SW1 to commence test");
}//end setup

///**************************************************************************
///
///                                   Loop code
///
///**************************************************************************
void loop() {
buttonState = digitalRead(buttonPin);  // read the state of the pushbutton value:
if (buttonState == LOW) {     
digitalWrite(ledPin, HIGH);            // turn LED on:
Serial.println("Initialising Stellaris Fast Analog Read");
fast_analogInit(PE_3);
Serial.println("Stellaris Fast Analog Read Initialised");
SampleStartTime = micros();
digitalWrite(TriggerPin, HIGH);        // Start the Analog Signal 
for (uint16_t i=0;i<SampleQty;i++)
 {
Sample[i] = fast_analogRead();                                  
 } 
SampleEndTime = micros();
//Dump results to serial monitor
for (uint16_t i=0;i<SampleQty;i++)
{
  Serial.println(Sample[i]);
} 
Serial.print("Number of Samples : ");
Serial.println(SampleQty);
Serial.print("Sample Starttime : ");
Serial.println(SampleStartTime);
Serial.print("Sample Endtime : ");
Serial.println(SampleEndTime);
SampleDuration = SampleEndTime - SampleStartTime;
Serial.print("Sample Array Set Duration time in microseconds  : ");
Serial.println(SampleDuration);
}// end if 
delay(1000);
digitalWrite(ledPin, LOW);  // turn LED off:
}//end loop


///**************************************************************************
///
///                                   Fast Analog Read Routine
///
///**************************************************************************
uint16_t fast_analogRead(void) {
  #define DEBUG        



  #ifdef DEBUG
  Serial.println("1");
  #endif
    uint32_t value[8];
    #ifdef DEBUG
    Serial.println("2");
    #endif
    //unsigned long *pulBuffer = &value[0];
    uint32_t *pulBuffer = &value[0];
    #ifdef DEBUG
    Serial.println("3");
    #endif
    //unsigned long ulCount;
    uint32_t ulCount;
    #ifdef DEBUG
    Serial.println("4");
    #endif
    //unsigned long ulBase = faBase;
     uint32_t ulBase = faBase;
    #ifdef DEBUG
    Serial.println("5");
    #endif
    HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; //<==== Hangs on this line here
    #ifdef DEBUG
    Serial.println("6");
    #endif
    HWREG(ADC0_BASE + ADC_O_PSSI) |= ((SEQUENCER & 0xffff0000) | (1 << (SEQUENCER & 0xf)));
    #ifdef DEBUG
    Serial.println("7");
    #endif
    while (!(HWREG(ADC0_BASE + ADC_O_RIS) & (0x10000 | (1 << SEQUENCER)))) {}
    #ifdef DEBUG
    Serial.println("8");
    #endif
    HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER;
    #ifdef DEBUG
    Serial.println("9");
    #endif
    ulBase = ADC0_BASE + (ADC_SEQ + (ADC_SEQ_STEP * SEQUENCER));
    #ifdef DEBUG
    Serial.println("10");
    #endif
    ulCount = 0;
    #ifdef DEBUG
    Serial.println("11");
    #endif
    while(!(HWREG(ulBase + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) && (ulCount < 8)) {
    #ifdef DEBUG
    Serial.println("12");
    #endif
    value[ulCount] = HWREG(ulBase + ADC_SSFIFO);
    #ifdef DEBUG
    Serial.println("13");
    #endif
    ulCount++;
    }
    return value[0];
}    

///**************************************************************************
///
///                                   Fast Analog Init Routine
///
///**************************************************************************
    uint16_t fast_analogInit(uint8_t pin) {
    uint8_t port = digitalPinToPort(pin);
    uint16_t value[1];
    uint32_t channel = digitalPinToADCIn(pin);
    if (pin == NOT_ON_ADC) {                    //invalid ADC pin
        return(0);
    }
    faBase = (uint32_t)portBASERegister(port);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    ROM_GPIOPinTypeADC((uint32_t)portBASERegister(port), digitalPinToBitMask(pin));
    ROM_ADCSequenceConfigure(ADC0_BASE, SEQUENCER, ADC_TRIGGER_PROCESSOR, 0);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 0, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 1, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 2, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 3, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 4, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 5, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 6, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 7, channel | ADC_CTL_IE | ADC_CTL_END);
    ROM_ADCSequenceEnable(ADC0_BASE, SEQUENCER);
    ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
    return(1);
}





 
Any help greatly apppreciated.


I'd love to get this project finished to both use it and also showoff the nice Lasercut panels @@Fred did for me ;)

Cheers

PTB

@@jkabat

Share this post


Link to post
Share on other sites

Hi PTB,

I actually find weird that the code doesn't stop before. After enabling the ADC peripheral clock with SysCtlPeripheralEnable() you should give it at least 5 cycles before configuring the ADC. You do have another line of code between it but it's cutting it a little to close. Just add SysCtlDelay(3) for good measure (it does a 9 cycle delay).

Btw, have you noticed how your code is in this post? It's a jumbled mess. Can you post it again?
 

Share this post


Link to post
Share on other sites

@L.R.A.

 

Hi L.R.A.

 

Thanks heaps for looking into this.

 

Goodness that code has gone to the dogs. It wasn't like that when I left it.... honest ;)

Just reposted and it looks alright at the moment. I must have wrecked it when I edited a typo the other day.

 

I'll give that suggestion a crack tomorrow after work and see what happens.

 

Thanks again for looking.

 

Cheers

 

PTB

Share this post


Link to post
Share on other sites

Hi PTB,

 

So I used your sketch on CCS to debug it.

 

When that line you referred was executed the code went into the Fault_ISR, consistent with the ADC peripheral not having the clock enabled. I checked the registers and it was indeed without a clock, weird right?

So I ran line by line the ADC init function. Found the culprit. For some reason this line of code disabled the ADC peripheral clock:
ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);

I actually can't find that function in the peripheral guide, though it's in the source files! I will have to check on that

Share this post


Link to post
Share on other sites

Went ahead and check my Tivaware version, the latest, and there isn't a SysCtlADCSpeedSet() function!



I really don't know what is the idea with the second register it changes:

    HWREG(SYSCTL_SCGC0) = ((HWREG(SYSCTL_SCGC0) & ~(SYSCTL_SCGC0_ADCSPD_M)) |
                           ui32Speed);

It's setting to 0 a reserved area, somehow it must be "leaking" into bits 16 and 17 of that register. Either way, avoid using that function. Instead use for ADC0:

    HWREG(SYSCTL_RCGC0) &= ~SYSCTL_RCGC0_ADC0SPD_M; // change if you want ADC1
    HWREG(SYSCTL_RCGC0) |= SYSCTL_RCGC0_ADC0SPD_1M; // change for the desired speed with the macros and the ADC module
 
 
 

Share this post


Link to post
Share on other sites

Hi L.R.A.

 

I may have misinterpreted what you were saying.

I disabled the line you mentioned in the init routine and replaced it with those last 2 lines. unfortunately it hangs at the same spot.

 

Was that what I was supposed to do ? This HWREG stuff is definitely outside my skillset.

 

Cheers

 

PTB

// 
// LM4F_ADC 
// A Stellarisiti Collaborative effort 
// JKabat, Rei Vilo, reaper7, PTB.
//

// Include application, user and local libraries

// Define variables and constants
///
/// @file	Fast_Analog_Read.ino
/// @brief	Main sketch
///
/// @details	Fast Analog Read Investigations for Stellaris LM4F
///

//
// Stellaris Pin Assignments
// =========================
//PE_3    //Sensor Analog Read
//PA_5    //Trigger Analog Signal Pulse
//PF_4    //Push Button to Start

//
// Libraries
// =========
#include "Energia.h"
#include "SPI.h"
#include "inc/lm4f120h5qr.h"


#include "inc/hw_adc.h"
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"

#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"


//
// Constants from adc.c
// ====================
#define ADC_SEQ                 (ADC_O_SSMUX0)
#define ADC_SEQ_STEP            (ADC_O_SSMUX1 - ADC_O_SSMUX0)
#define ADC_SSFIFO              (ADC_O_SSFIFO0 - ADC_O_SSMUX0)
#define ADC_SSFSTAT             (ADC_O_SSFSTAT0 - ADC_O_SSMUX0)

#define SEQUENCER   0


//
// Global Constants
// ================
const byte SampleQty = 255;               // number of samples  
const uint16_t buttonPin = PUSH1;         // the number of the pushbutton pin
const uint16_t ledPin =  GREEN_LED;       // the number of the LED pin
const uint16_t TriggerPin = PA_5;         // Analog Signal Trigger connected to digital pin PA_5


//
// Global Variables
// ================

uint16_t SampleTest;
uint16_t buttonState = 0;         // variable for reading the pushbutton status
uint16_t Sample[SampleQty];       // Array variable to store the value coming from the sensor
//unsigned long SampleStartTime;
uint32_t SampleStartTime;
//unsigned long SampleEndTime;
uint32_t SampleEndTime;
//unsigned long SampleDuration;
uint32_t SampleDuration;

//unsigned long faBase;
uint32_t faBase;

//
// Prototypes
// ==========
  uint16_t fast_analogInit(uint8_t pin);
  uint16_t fast_analogRead(void);


///**************************************************************************
///
///                                   Setup code
///
///**************************************************************************
void setup() {
Serial.begin(9600) ;               //Debugging initialize the serial communication:
pinMode(ledPin, OUTPUT);           // initialize the LED pin as an output:    
pinMode(buttonPin, INPUT_PULLUP);  // initialize the pushbutton pin as an input:
pinMode(TriggerPin, OUTPUT);       // initialize the Trigger pin as an output: 
Serial.println("Stellaris Fast Analog Read");
Serial.println("==========================");
Serial.println("");
Serial.println("Press SW1 to commence test");
}//end setup

///**************************************************************************
///
///                                   Loop code
///
///**************************************************************************
void loop() {
buttonState = digitalRead(buttonPin);  // read the state of the pushbutton value:
if (buttonState == LOW) {     
digitalWrite(ledPin, HIGH);            // turn LED on:
Serial.println("Initialising Stellaris Fast Analog Read");
fast_analogInit(PE_3);
Serial.println("Stellaris Fast Analog Read Initialised");
SampleStartTime = micros();
digitalWrite(TriggerPin, HIGH);        // Start the Analog Signal 
for (uint16_t i=0;i<SampleQty;i++)
 {
Sample[i] = fast_analogRead();                                  
 } 
SampleEndTime = micros();
//Dump results to serial monitor
for (uint16_t i=0;i<SampleQty;i++)
{
  Serial.println(Sample[i]);
} 
Serial.print("Number of Samples : ");
Serial.println(SampleQty);
Serial.print("Sample Starttime : ");
Serial.println(SampleStartTime);
Serial.print("Sample Endtime : ");
Serial.println(SampleEndTime);
SampleDuration = SampleEndTime - SampleStartTime;
Serial.print("Sample Array Set Duration time in microseconds  : ");
Serial.println(SampleDuration);
}// end if 
delay(1000);
digitalWrite(ledPin, LOW);  // turn LED off:
}//end loop


///**************************************************************************
///
///                                   Fast Analog Read Routine
///
///**************************************************************************
uint16_t fast_analogRead(void) {
  #define DEBUG        



  #ifdef DEBUG
  Serial.println("1");
  #endif
    uint32_t value[8];
    #ifdef DEBUG
    Serial.println("2");
    #endif
    //unsigned long *pulBuffer = &value[0];
    uint32_t *pulBuffer = &value[0];
    #ifdef DEBUG
    Serial.println("3");
    #endif
    //unsigned long ulCount;
    uint32_t ulCount;
    #ifdef DEBUG
    Serial.println("4");
    #endif
    //unsigned long ulBase = faBase;
     uint32_t ulBase = faBase;
    #ifdef DEBUG
    Serial.println("5");
    #endif
    HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; //<==== Hangs on this line here
    #ifdef DEBUG
    Serial.println("6");
    #endif
    HWREG(ADC0_BASE + ADC_O_PSSI) |= ((SEQUENCER & 0xffff0000) | (1 << (SEQUENCER & 0xf)));
    #ifdef DEBUG
    Serial.println("7");
    #endif
    while (!(HWREG(ADC0_BASE + ADC_O_RIS) & (0x10000 | (1 << SEQUENCER)))) {}
    #ifdef DEBUG
    Serial.println("8");
    #endif
    HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER;
    #ifdef DEBUG
    Serial.println("9");
    #endif
    ulBase = ADC0_BASE + (ADC_SEQ + (ADC_SEQ_STEP * SEQUENCER));
    #ifdef DEBUG
    Serial.println("10");
    #endif
    ulCount = 0;
    #ifdef DEBUG
    Serial.println("11");
    #endif
    while(!(HWREG(ulBase + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) && (ulCount < 8)) {
    #ifdef DEBUG
    Serial.println("12");
    #endif
    value[ulCount] = HWREG(ulBase + ADC_SSFIFO);
    #ifdef DEBUG
    Serial.println("13");
    #endif
    ulCount++;
    }
    return value[0];
}    

///**************************************************************************
///
///                                   Fast Analog Init Routine
///
///**************************************************************************
    uint16_t fast_analogInit(uint8_t pin) {
    uint8_t port = digitalPinToPort(pin);
    uint16_t value[1];
    uint32_t channel = digitalPinToADCIn(pin);
    if (pin == NOT_ON_ADC) {                    //invalid ADC pin
        return(0);
    }
    faBase = (uint32_t)portBASERegister(port);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    ROM_GPIOPinTypeADC((uint32_t)portBASERegister(port), digitalPinToBitMask(pin));
    ROM_ADCSequenceConfigure(ADC0_BASE, SEQUENCER, ADC_TRIGGER_PROCESSOR, 0);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 0, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 1, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 2, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 3, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 4, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 5, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 6, channel | ADC_CTL_IE);
    ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 7, channel | ADC_CTL_IE | ADC_CTL_END);
    ROM_ADCSequenceEnable(ADC0_BASE, SEQUENCER);
    //ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);//<= Identified By L.R.A. as problem line
    HWREG(SYSCTL_RCGC0) &= ~SYSCTL_RCGC0_ADC0SPD_M; // change if you want ADC1
    HWREG(SYSCTL_RCGC0) |= SYSCTL_RCGC0_ADC0SPD_1M; // change for the desired speed with the macros and the ADC module
    return(1);
}

Share this post


Link to post
Share on other sites

Hum weird.

Basically you are directly changing the register values. I usually don't do register programming but sometimes it's needed.
 

 For some reason setting the ADC speed that way causes problems. If you remove that line I told you to add the code should run. The register I said to change is a legacy register, there's actually a better, new way to set the ADC rate.


I really can't find a Tivaware function to set the max sample rate :(. So I can't really give you a solution without using HWREG. Try what's bellow, right now I can't test it out.
It seems the right register to change, that isn't legacy, is: Register 55: ADC Peripheral Properties (ADCPP), offset 0xFC0


HWREG(ADC0_BASE+0xFC0) &= ~0xF;

HWREG(ADC0_BASE+0xFC0) |= 0x7;

 

Share this post


Link to post
Share on other sites

L.R.A.

 

I appreciate your help.

 

I'll keep having a play.

 

Its all kinda bizarro as it ran under energia 9 and 10.

 

Cheers

 

PTB

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×