
jkabat
-
Content Count
59 -
Joined
-
Last visited
-
Days Won
1
Reputation Activity
-
jkabat got a reaction from CorB in Anaren Air Boosterpack on Stellaris
@@CorB
That actually should be OK.
You might want to try:
#pragma pack(1)
... define your structure here
#pragma pack()
You might be having problems with word alignment. The compiler may force uint16_t to be aligned on a word boundry.
The pack(1) forces aligment to 1 byte. the pack() restores it to whatever the compiler is using.
I have to do this all the time on my x86 stuff.
regards
John
-
jkabat got a reaction from CorB in Anaren Air Boosterpack on Stellaris
@@CorB,
Here is a useful function;
uint16_t swap16(uint16_t val) {
return ((val & 0xFF) << 8)
| ((val >> 8) & 0xFF);
}
data2=swap(data1);
I make my own include files that conditionally compile based on the endian type of the host. All external items should be little endian.
#ifdef WE_ARE_BIGENDIAN
#define swap16_external(val) (((val & 0xFF) << 8) | ((val >> 8) & 0xFF)))
#else
#define swap16_external(val) (val)
#endif
-
jkabat got a reaction from spirilis in Programming Micro-USB connector failure
Well,
Last night I managed to solder wires to the DM- and DM+ on the back of the board. Due to the fact that the traces are thin and fragile I covered them with a laer of Gorrilla Glue to pot them. I then glued a old style USB Type B connector to the bottom of the board. I then connected DM- to pin 2, DM+ to pin3, Vin to pin 1 and Gnd to Pin 4 of the USB Type-B connector.
I then tested it and everything worked!
I then potted the back of the USB connector for insulation and strength.
Here is a picture while working on it:
-
jkabat got a reaction from bluehash in Programming Micro-USB connector failure
grahamf72See this thread: http://forum.stellarisiti.com/topic/495-programming-lm4f-when-idc-usb-connector-destroyed/
This is from when I 1st had problems.
-
jkabat got a reaction from grahamf72 in Programming Micro-USB connector failure
grahamf72See this thread: http://forum.stellarisiti.com/topic/495-programming-lm4f-when-idc-usb-connector-destroyed/
This is from when I 1st had problems.
-
jkabat got a reaction from grahamf72 in Programming Micro-USB connector failure
Well,
Last night I managed to solder wires to the DM- and DM+ on the back of the board. Due to the fact that the traces are thin and fragile I covered them with a laer of Gorrilla Glue to pot them. I then glued a old style USB Type B connector to the bottom of the board. I then connected DM- to pin 2, DM+ to pin3, Vin to pin 1 and Gnd to Pin 4 of the USB Type-B connector.
I then tested it and everything worked!
I then potted the back of the USB connector for insulation and strength.
Here is a picture while working on it:
-
jkabat got a reaction from PTB in Stellaris fast analog reads
@@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
-
jkabat reacted to patolin_01 in Stellaris fast analog reads
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
-
jkabat got a reaction from PTB in Stellaris fast analog reads
@@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.
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); }} -
jkabat reacted to PTB in Stellaris fast analog reads
@JKabat @Rei Vilo @reaper7
I dunno John... Its still 3 microseconds too slow.
Sensational ! You definitely appear to know your stuff.
Number of Samples : 255 Sample Starttime : 11000011 Sample Endtime : 11000269 Sample Array Set Duration time in microseconds : 258 I also tried your "Late Edit" (Complete with disclaimer) but that slowed it down so I took it back out.
Number of Samples : 255 Sample Starttime : 27725011 Sample Endtime : 27727786 Sample Array Set Duration time in microseconds : 2775 I did a little more housekeeping taking out some comments and unused defines and faMask as it appears to not be used.
Latest Code Here.....
// // 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; unsigned long SampleEndTime; unsigned long SampleDuration; unsigned long 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: }//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: fast_analogInit(PE_3); 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) { uint32_t value[8]; unsigned long *pulBuffer = &value[0]; unsigned long ulCount; unsigned long ulBase = faBase; HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; HWREG(ADC0_BASE + ADC_O_PSSI) |= ((SEQUENCER & 0xffff0000) | (1 << (SEQUENCER & 0xf))); while (!(HWREG(ADC0_BASE + ADC_O_RIS) & (0x10000 | (1 << SEQUENCER)))) {} HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; ulBase = ADC0_BASE + (ADC_SEQ + (ADC_SEQ_STEP * SEQUENCER)); ulCount = 0; while(!(HWREG(ulBase + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) && (ulCount < 8)) { value[ulCount] = HWREG(ulBase + ADC_SSFIFO); 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); } I was hoping for one sample per microsecond.... I don't think you could get much closer than this.
Cheers
PTB
-
jkabat got a reaction from PTB in Stellaris fast analog reads
@@reaper7,
That is what I was going to suggest. Just overloaded here a work today.
@@PTB
one thing you may want to do after applying @@reaper7s fix is to place the code for fastAnalogRead in place of the call. Anlternativly you should move the read and init routines up befor loop and place the __inline__ attribute on them. Sorry I am at work preparing for a trip and am not sure of the exact format. If you copy the code in place of fast... assign the result to sample[i++]= HWREG(ulBase + ADC_SSFIFO); in place of value[ulcount].
If you switch to another sequencer (o has an 8 deep fifo) this will handle the results automatically. You may have to modify some setting in fastAdcInit(pin) to get multiple reads.
update:
Use sequencer 0.
I am not sure if all 8 steps need to be configured but you may need to add the following to init:
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);
(late edit: You may (or may not) neet to remove the" | ACD_CTL_IE" from all but the last entry. Only use this for SEQUENCER 0)
Use at your own risk as I am unable to test this.
-
jkabat reacted to PTB in Stellaris fast analog reads
And Here's the Code
// // LM4F_ADC // // Description of the project // Developed with [embedXcode](http://embedXcode.weebly.com) // // Author Rei VILO // Rei Vilo // // Date 21/07/13 09:42 // Version <#version#> // // Copyright (c) Rei VILO, 2013 // Licence CC = BY NC SA // // See ReadMe.txt for references // // Core library for code-sense #if defined(WIRING) // Wiring specific #include "Wiring.h" #elif defined(MAPLE_IDE) // Maple specific #include "WProgram.h" #elif defined(MPIDE) // chipKIT specific #include "WProgram.h" #elif defined(DIGISPARK) // Digispark specific #include "Arduino.h" #elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific #include "Energia.h" #elif defined(CORE_TEENSY) // Teensy specific #include "WProgram.h" #elif defined(ARDUINO) && (ARDUINO >= 100) // Arduino 1.0 and 1.5 specific #include "Arduino.h" #elif defined(ARDUINO) && (ARDUINO < 100) // Arduino 23 specific #include "WProgram.h" #else // error #error Platform not defined #endif // 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_SSMUX (ADC_O_SSMUX0 - ADC_O_SSMUX0) #define ADC_SSEMUX (ADC_O_SSEMUX0 - ADC_O_SSMUX0) #define ADC_SSCTL (ADC_O_SSCTL0 - ADC_O_SSMUX0) #define ADC_SSFIFO (ADC_O_SSFIFO0 - ADC_O_SSMUX0) #define ADC_SSFSTAT (ADC_O_SSFSTAT0 - ADC_O_SSMUX0) #define ADC_SSOP (ADC_O_SSOP0 - ADC_O_SSMUX0) #define ADC_SSDC (ADC_O_SSDC0 - ADC_O_SSMUX0) #define SEQUENCER 3 // // 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; unsigned long SampleEndTime; unsigned long SampleDuration; unsigned long faBase; uint16_t faMask; // // 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: }//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: fast_analogInit(PE_3); // JKabat SampleStartTime = micros(); digitalWrite(TriggerPin, HIGH); // Start the Analog Signal for (uint16_t i=0;i<SampleQty;i++) { // Sample[i]=analogRead(PE_3); // Original Analog Read Sample[i] = fast_analogRead(); // JKabat } 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) { uint32_t value[8]; unsigned long *pulBuffer = &value[0]; unsigned long ulCount; unsigned long ulBase = faBase; HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; HWREG(ADC0_BASE + ADC_O_PSSI) |= ((SEQUENCER & 0xffff0000) | (1 << (SEQUENCER & 0xf))); while (!(HWREG(ADC0_BASE + ADC_O_RIS) & (0x10000 | (1 << SEQUENCER)))) {} HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; ulBase = ADC0_BASE + (ADC_SEQ + (ADC_SEQ_STEP * SEQUENCER)); ulCount = 0; while(!(HWREG(ulBase + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) && (ulCount < 8)) { value[ulCount] = HWREG(ulBase + ADC_SSFIFO); 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); faMask = digitalPinToBitMask(pin); 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 | ADC_CTL_END); ROM_ADCSequenceEnable(ADC0_BASE, SEQUENCER); return(1); } Cheers
PTB
-
jkabat reacted to reaper7 in Stellaris fast analog reads
This is my results:
Number of Samples : 255 Sample Starttime : 378625230 Sample Endtime : 378625913 Sample Array Set Duration time in microseconds : 683 1 Sample every ~2.68 microseconds
driverlib/sysctl.h - have function for ADC SPEED:
SysCtlADCSpeedSet(unsigned long ulSpeed)
available value:
#define SYSCTL_ADCSPEED_1MSPS 0x00000F00 // 1,000,000 samples per second #define SYSCTL_ADCSPEED_500KSPS 0x00000A00 // 500,000 samples per second #define SYSCTL_ADCSPEED_250KSPS 0x00000500 // 250,000 samples per second #define SYSCTL_ADCSPEED_125KSPS 0x00000000 // 125,000 samples per second Default is: SYSCTL_ADCSPEED_125KSPS 0x00000000 // 125,000 samples per second
so...You must add a one line:
ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);
before return(1);
in fast_analogInit(uint8_t pin):
... ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 0, channel | ADC_CTL_IE | ADC_CTL_END); ROM_ADCSequenceEnable(ADC0_BASE, SEQUENCER); ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS); return(1); } -
jkabat reacted to Rei Vilo in Stellaris fast analog reads
Let's do a library and request a pull at Energia GitHub repository!
-
jkabat got a reaction from PTB in Stellaris fast analog reads
@@PTB,
I begin to see where I erred! I forgot to include the sequencer in the read of the fifo. The clue to this was the ucount was 8 not 1. this indicates the we were reading an 8 deep FIFO not a single one. (Sequencer 0) Also since value is only one entry were were overwriting something following it. That is why it never returned!
So one more fix:
change value to:
uint16_t value[8]; just to be safe.
change the end as follows:
// // Get the offset of the sequence to be read. // ulBase = ADC0_BASE + (ADC_SEQ + (ADC_SEQ_STEP * SEQUENCER)); // // Read samples from the FIFO until it is empty. // ulCount = 0; while(!(HWREG(ulBase + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) && (ulCount < 8)) { // // Read the FIFO and copy it to the destination. // value[ulcount] = HWREG(ulBase + ADC_SSFIFO); // // Increment the count of samples read. // ulCount++; } return(value[0]; -
jkabat got a reaction from PTB in Stellaris fast analog reads
@@PTB @@Rei Vilo
Possible fix for fast_analog read:
Replace:
while (!(HWREG(ADC0_BASE + ADC_O_ISC) & (0x10001 << SEQUENCER))) {}
with:
while (!(HWREG(ADC0_BASE + ADC_O_RIS) & (0x10000 | (1 << SEQUENCE))) {}
This MAY fix the problem! Regards
John
-
jkabat reacted to Rei Vilo in Stellaris fast analog reads
In France, we use the same logic but from Le Discours de la méthode (1637) by Descartes, more precisely the second rule:
or in English
One can't imagine how modern and well suited for programming Descartes precepts are
-
jkabat got a reaction from PTB in Stellaris fast analog reads
@@PTB,
I probably extracted it wrong. See the original in driverlib/adc.c. Also I should have had you include driverlib/adc.h which would have taken care of those pesky defines
john
-
jkabat got a reaction from PTB in Stellaris fast analog reads
PTB,
Your problem intrigued me so i did some thinking. (In my day job optimization and speed is a way of life!)
I have split out into some semi-optimized routines below. This is more or less a direct translation of analogRead in wiring.c. IT HAS NOT BEEN TESTED but should work. (I think so)
your routine should be:
fast_analogInit(PE_3);
for (uint16_t i=0;i<SampleQty;i++)
{
// Sample=analogRead(PE_3);
//Sample[i] = GPIOPinRead(SENSOR_INT_BASE, SENSOR_INT_PIN);
Sample = fast_analogRead();
}
for further optimization you could have the sequencer run continuously and/or place the result directly in your table. Be careful Sequencer 3 has a FIFO depth of only one entry . Change to sequencer 0 to get a deptf of 16.
Here is the my code:
unsigned long faBase;uint16_t faMask;#define SEQUENCER 3uint16_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); faMask = digitalPinToBitMask(pin); 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 | ADC_CTL_END); ROM_ADCSequenceEnable(ADC0_BASE, SEQUENCER); return(1);}uint16_t fast_analogRead(void) { uint16_t value[1]; unsigned long *pulBuffer = &value[0]; unsigned long ulCount; unsigned long ulBase = faBase;// ROM_ADCIntClear(ADC0_BASE, 3);//// Clear the interrupt.// HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER; // ROM_ADCProcessorTrigger(ADC0_BASE, 3);//// Generate a processor trigger for this sample sequence.// HWREG(ADC0_BASE + ADC_O_PSSI) |= ((SEQUENCER & 0xffff0000) | (1 << (SEQUENCER & 0xf))); // while (!ROM_ADCIntStatus(ADC0_BASE, 3, false)) {} while (!(HWREG(ADC0_BASE + ADC_O_ISC) & (0x10001 << SEQUENCER))) {}// ROM_ADCIntClear(ADC0_BASE, 3);//// Clear the interrupt.// HWREG(ADC0_BASE + ADC_O_ISC) = 1 << SEQUENCER;// ROM_ADCSequenceDataGet(ADC0_BASE, 3, (unsigned long *)value); // // Get the offset of the sequence to be read. // ulBase += ADC_SEQ + (ADC_SEQ_STEP * SEQUENCER); // // Read samples from the FIFO until it is empty. // ulCount = 0; while (!(HWREG(ulBase + ADC_SSFSTAT) & ADC_SSFSTAT0_EMPTY) && (ulCount < 8)) { // // Read the FIFO and copy it to the destination. // *pulBuffer++ = HWREG(ulBase + ADC_SSFIFO); // // Increment the count of samples read. // ulCount++; } return value[0];} -
jkabat got a reaction from PTB in Stellaris fast analog reads
@Rei Vilo
You need to look at the source for wiring_analog.c and driverlib\adc.c./ There is a lot of overhead that can be removed. Most routines in adc.c boild down to 1 line that can be inserted into a copy of analogRead. this will run faster and eliminate the ROM_ calls.
If you are really ambitious you can move the ADC code to use sequencer 0 rather than 3. Sequencer 0 has a 16 entry fifo for readings. you can interrupt at half full to read the values.
As the next step use DMA instead of interrupts to directly place the values in memory.
This is all off the top of my head after a quick peek at the source for the analog stuff.
Have fun!
John
-
jkabat got a reaction from Rei Vilo in Stellaris fast analog reads
@Rei Vilo
You need to look at the source for wiring_analog.c and driverlib\adc.c./ There is a lot of overhead that can be removed. Most routines in adc.c boild down to 1 line that can be inserted into a copy of analogRead. this will run faster and eliminate the ROM_ calls.
If you are really ambitious you can move the ADC code to use sequencer 0 rather than 3. Sequencer 0 has a 16 entry fifo for readings. you can interrupt at half full to read the values.
As the next step use DMA instead of interrupts to directly place the values in memory.
This is all off the top of my head after a quick peek at the source for the analog stuff.
Have fun!
John
-
jkabat got a reaction from Rei Vilo in SOLVED - 4-Wire Resistive Touch-Screen Reading with Energia
Rei Vilo,
Thanks, this may explain the jitter on my touch screens! T never though a processor could be too fast!
Looks like I help you and you help me. That is the way things are supposed to be in this forum!!!!!!!!!!!!!!!!!!
The fun thing is that a work I do low level development on Muilti-Giga Hz processors where I am used to waiting, at home I deal with 8-100Mhz and forgot about waits! My focus has always to get things to run faster! Lve and learn!
Thanks
John
-
jkabat reacted to Rei Vilo in SOLVED - 4-Wire Resistive Touch-Screen Reading with Energia
@@igor
Thank you very much for pointing on the right direction.
The Stellaris is too fast! The touch needs more time!
Here is the modified code:
// for x axis do { delay(1); a = analogRead(TOUCH_YP); delay(1); b = analogRead(TOUCH_YP); } while (absDiff(a, > 8); x0 = 4095 - a; with
inline uint16_t absDiff(uint16_t a, uint16_t { return (a > ? a-b : b-a; } Stability is reached after a couple of iterations.
Problem solved
-
jkabat got a reaction from bluehash in Programming Micro-USB connector failure
Well,
Last night I managed to solder wires to the DM- and DM+ on the back of the board. Due to the fact that the traces are thin and fragile I covered them with a laer of Gorrilla Glue to pot them. I then glued a old style USB Type B connector to the bottom of the board. I then connected DM- to pin 2, DM+ to pin3, Vin to pin 1 and Gnd to Pin 4 of the USB Type-B connector.
I then tested it and everything worked!
I then potted the back of the USB connector for insulation and strength.
Here is a picture while working on it:
-
jkabat got a reaction from Rei Vilo in SOLVED - Writing and Reading the Values of an 8-bit Port with Energia
@Mention,
Here is what I use for my LCD driver. Note the last line. Remember HWREG is your friend. A good way to do fast digital I/O.
//========================================// Port and bitmask used for 8-bit data bus#define LCD_DATA_PERIPH SYSCTL_PERIPH_GPIOB#define LCD_DATA_BASE GPIO_PORTB_BASE#define LCD_DATA_PINS 0xFF// Ports and pins used for control#define LCD_CS_PERIPH SYSCTL_PERIPH_GPIOA#define LCD_CS_BASE GPIO_PORTA_BASE#define LCD_CS_PIN GPIO_PIN_7#define LCD_CD_PERIPH SYSCTL_PERIPH_GPIOA#define LCD_CD_BASE GPIO_PORTA_BASE#define LCD_CD_PIN GPIO_PIN_6#define LCD_WR_PERIPH SYSCTL_PERIPH_GPIOA#define LCD_WR_BASE GPIO_PORTA_BASE#define LCD_WR_PIN GPIO_PIN_5#define LCD_RD_PERIPH SYSCTL_PERIPH_GPIOA#define LCD_RD_BASE GPIO_PORTA_BASE#define LCD_RD_PIN GPIO_PIN_4#define LCD_RST_PERIPH SYSCTL_PERIPH_GPIOC#define LCD_RST_BASE GPIO_PORTC_BASE#define LCD_RST_PIN GPIO_PIN_7#define LCD_BKLT_PERIPH SYSCTL_PERIPH_GPIOD#define LCD_BKLT_BASE GPIO_PORTD_BASE#define LCD_BKLT_PIN GPIO_PIN_6#define LCD_CS_IDLE HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = LCD_CS_PIN;#define LCD_CS_ACTIVE HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = 0;#define LCD_CD_DATA HWREG(LCD_CD_BASE + GPIO_O_DATA + (LCD_CD_PIN << 2)) = LCD_CD_PIN;#define LCD_CD_COMMAND HWREG(LCD_CD_BASE + GPIO_O_DATA + (LCD_CD_PIN << 2)) = 0;#define LCD_WR_IDLE HWREG(LCD_WR_BASE + GPIO_O_DATA + (LCD_WR_PIN << 2)) = LCD_WR_PIN;#define LCD_WR_ACTIVE HWREG(LCD_WR_BASE + GPIO_O_DATA + (LCD_WR_PIN << 2)) = 0;#define LCD_RD_IDLE HWREG(LCD_RD_BASE + GPIO_O_DATA + (LCD_RD_PIN << 2)) = LCD_RD_PIN;#define LCD_RD_ACTIVE HWREG(LCD_RD_BASE + GPIO_O_DATA + (LCD_RD_PIN << 2)) = 0;#define LCD_RST_IDLE HWREG(LCD_RST_BASE + GPIO_O_DATA + (LCD_RST_PIN << 2)) = LCD_RST_PIN;#define LCD_RST_ACTIVE HWREG(LCD_RST_BASE + GPIO_O_DATA + (LCD_RST_PIN << 2)) = 0;#define LCD_BKLT_ON HWREG(LCD_BKLT_BASE + GPIO_O_DATA + (LCD_BKLT_PIN << 2)) = LCD_BKLT_PIN;#define LCD_BKLT_OFF HWREG(LCD_BKLT_BASE + GPIO_O_DATA + (LCD_BKLT_PIN << 2)) = 0;#define LCD_DATA_WRITE(ucByte) { HWREG(LCD_DATA_BASE + GPIO_O_DATA + (LCD_DATA_PINS << 2)) = (ucByte); }