This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

cc2530 znp using getvcc3 for analog input

Other Parts Discussed in Thread: MSP430F2274, CC2530

hello guys,

i have been working on the msp430f2274 zigbee kit for sometime now. I have downloaded the simple application from TI and have changed the getvcc3() as follows:

unsigned int getVcc3()
{
ADC10CTL0 = SREF_1 + REFON + REF2_5V + ADC10ON + ADC10SHT_3; // use internal ref, turn on 2.5V ref, set samp time = 64 cycles
ADC10CTL1 = INCH_4 ;
ADC10AE0 |= 0x10; // selecting channel A4
delayMs(1); // Allow internal reference to stabilize
ADC10CTL0 |= ENC + ADC10SC; // Enable conversions
while (!(ADC10CTL0 & ADC10IFG)); // Conversion done?
unsigned long temp = (ADC10MEM * 36000 ); // Convert raw ADC value to millivolts
return ((int) (temp / 10230));
}

with the above code i took the suggestion from this link: http://e2e.ti.com/support/low_power_rf/f/158/t/127604.aspx and used the math as per the link.

I was able to provide a square wave and obtained the output. but, the output was measuring 1.4v according to the adc converted results instead of 2v. I have connected to the pin no.7 on P2 of the target board.

what i do not understand is why is it 1.4 v instead of 2v.

here is the results obtained from the h-term.

0
0
0
0
1453
1449
1449
1449
1449
0
0
0
0
0
1449
1449
1449
1449
1449
0
0
0
0
0
1449
1449
1449
1449
1449
0
0
As you can see the square wave with 50 % duty cycle gives 5x 1449(since it is been converted to mV) and 5 times 0 per cycle.
I would greatly appreciate any help with regards to the value i am getting from the adc as to why it is different!!!
thanking you in advance
Nischal Venugopal
  • Hi Nischal,

    Based on the code fragment you posted above, it looks like you are configuring the ADC10 measuring range to be between VSS (Ground, 0V) and VREF+ (Internal reference, 2.5V configuration).  This means your ADC has a range of VSS to VSS+2.5V.

    Since this is a 10-bit ADC, the raw conversion result will be between zero and 1023.  That means that we are taking the 2.5V reference, with respect to VSS, and dividing that 2.5V up into 1024 steps.  

    This gives a step size of 2.44mV per conversion code.

    A conversion result of 0 correlates to 0V, a conversion result of 1 correlates to 2.44mV, and a conversion result of 10 correlates to 24.4mV, and so on.  If I back-trace the math in the function you show here, your function getVcc3 returning the raw conversion output multiplied by 3.519.  That relationship would make sense if you had a 3.6V reference, not a 2.5V reference.

    If I work the math backwards, that function giving you a result of 1449 should actually mean a conversion result of 1.006V.  This is still not the 2V you expect, however.  Are you outputting a 2V square wave peak to peak centered at zero, or centered at 1V?

    I've attached a spreadsheet that correlates output codes with voltages, as well as your fxn outputs for comparison.0488.ADC10_w2P5VRef.xlsx

    Regards,
    Walter

  • Hi Walter,

    I really appreciate your quick reply on this one, I am using a peak-peak square wave centered at zero.i.e the signal source is from a signal generator and i had no offset on the signal, nor did i re-adjust it such that the waveform would be above the zero line. One more thing i would like to ask you regarding this would be the strange behavior of the analog input itself, i.e if i do not rig up my target board to a signal source/generator; it is still sending a some amount of data which is fluctuating in the range of 400-700 mV. Right now i am really curious as to where or what this is. also, when I hook up the probes to the target board and keep the signal generator's output off, the output of the ADC drops to a range of 100-200mV. any insight on this one??

    I will change the reference voltage for the ADC by setting nothing on the ADC10CTL0 register such that it takes the Vcc by removing all the internal reference set bits from the code, as the reference with Vcc should be 3.6V.

     Actually I also tried some of the conversions based on: (Vin/Vref)*1023 = Nadc. but still couldn't figure out the resulting value. I also took a look at the excel sheet ,that is a great reference table; will be very helpful in the future thank you.

    looking forward for your reply. :) 

    thanking you in advance,

    Nischal Venugopal

  • Nischal,

    If you were outputting a 2Vpp square wave centered at zero, the output of the signal generator is going to be -1.0V to 1.0V.  The 1.00V pulses that your data indicates are in line with this, since the ADC is not going to measure negative voltages (they result in an output code of zero).

    If you remove the signal generator connection to the ADC input pin, the ADC pin becomes a floating conductor, also known as an antenna.  The same thing happens on any device pin if you leave it set as a High-Z input.  The few hundred mV that you are measuring is whatever noise is being coupled into the the pin from surrounding noise sources.  Remember, a floating pin that is not tied to a node still has a voltage with respect to your ground reference (VSS).

    Walter

  • Thank you walter for the reply,

    Could you briefly explain me how is it that the voltage output I am getting from the ADC is within range, I somewhow seem to be missing that. Shouldn't I get a 1v output with a square wave centered at zero ?? But instead I am getting 1.4 v. Won't the stray voltage before the switching on the output add on to the input signal ???Also, suppose I change the math and multiply the Nadc with 2500mV which is about 409 ADC value then, i should be getting 1V isn't that right?? If that is the case I shall do that first thing in the morning when I go to the lab amd shall let you know the outcome of it.

    Thanking you in advance, 

    Nischal

  • Hey Walter,

    Thanks for all your suggestions, I tried them out today at the lab and works just fine. I changed the conversion factor from 36000 to 2500l and i am getting appropriate output :)

    If possible, I would also like to know how to increase the rate of data sending..... Right now, I am getting each data set in 4 seconds interval; as in : it takes 4 second to get 1009 /r/n and the next data set 1009 will be after 4 seconds. I am using the simple application from TI.

    Regards,

    Nischal Venugopal.

  • Walter Schnoor said:
    dividing that 2.5V up into 1024 steps.  

    Actually 1023 steps. 0 is 0 and 1023 is Vrefc, so 1 is Vref*1/1023 and 1023 is Vref*1023/1023 (= Vref)
    However, the difference is minimal and way smaller than the reference tolerance. So I too always suggest using a >>10 instead of the (theoretically correct) /1023, for speed reasons.

    In the original code, why is the calculation multiplying with 36000 when 2.5V reference is used? This is why you get 1449 instead of 1000mV

  • hello Jens,

    I actually figured that out and now since i am dividing the Vin by 2500 to convert it into millivolts - it works just fine and i am getting the right results. However, I have a different question now, that is: I have a 4 sec interval before each data set. HOW DO I SHORTEN IT?? I am using the sample code from TI : simple applications IAR. I shall share the folder here, In case you need to take a look at the sample code.

    /**
    * @ingroup apps
    * @{
    *
    * @file example_basic_comms_router_afzdo.c
    *
    * @brief Resets Radio, configures this device to be a Zigbee Router, joins a network, then sends a message to the coordinator once per second.
    * Uses the AF/ZDO interface. Reads the ambient light sensor and supply voltage and sends these in the message.
    * Also sends a message upon a motion interrupt from the accelerometer. 
    *
    * @note This matches example_simple_application_coordinator.c
    * @note This example will not compile with the IAR Kickstart edition because CODE + CONST exceeds 4kB
    * @see http://processors.wiki.ti.com/index.php/Tutorial_on_the_Examples and http://e2e.ti.com/support/low_power_rf/default.aspx
    *
    * $Rev: 602 $
    * $Author: dsmith $
    * $Date: 2010-06-16 13:09:46 -0700 (Wed, 16 Jun 2010) $
    *
    * YOU ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED �AS IS� WITHOUT WARRANTY 
    * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, 
    * TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS 
    * OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, 
    * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
    * INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, 
    * LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY 
    * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
    */
    #include "../HAL/hal.h"
    #include "../HAL/hal_vti_cma3000_D01_accelerometer.h"
    #include "../ZNP/znp_interface.h"
    #include "../ZNP/application_configuration.h"
    #include "../ZNP/af_zdo.h"
    #include "znp_simple_app_utils.h" 
    #include "Messages/infoMessage.h"
    #include <string.h>  
    
    unsigned int sequenceNumber = 0;  //an application-level sequence number to track acknowledgements from server
    
    extern signed int znpResult;      //from znp_interface
    
    /** function pointer (in hal file) for the function that gets called when the timer generates an int*/
    extern void (*timerIsr)(void);
    
    /** This is the current state of the application. 
    * Gets changed by other states, or based on messages that arrive. */
    unsigned int state = STATE_ZNP_STARTUP;
    
    /** The main application state machine */
    void stateMachine();
    
    /** Various flags between states */
    unsigned int stateFlags = 0;
    #define STATE_FLAG_SEND_INFO_MESSAGE 0x01
    
    /** Handles timer interrupt */
    void handleTimer();
    
    /** This is the function pointer (in hal file) for the ISR called when the accelerometer generates an interrupt*/
    extern void (*accelerometerIsr)(void);
    
    /** Handles Accelerometer interrupt */
    void handleAccelerometer();
    
    /** Variable to track the cause of the Info Message; whether it be CAUSE_SCHEDULED or CAUSE_MOTION etc.*/
    unsigned char infoMessageCause = CAUSE_STARTUP;
    
    struct infoMessage im;
    struct header hdr;
                    
    /**Comment these out to only send a message on motion or timer respectively */
    #define SEND_MESSAGE_ON_MOTION
    #define SEND_MESSAGE_ON_TIMER
    
    int main( void )
    {
        halInit();
        HAL_DISABLE_INTERRUPTS();
        printf("\r\n****************************************************\r\n");    
        printf("Simple Application Example - END DEVICE - using AFZDO\r\n");
    #ifdef SEND_MESSAGE_ON_TIMER    
        unsigned int vlo = calibrateVlo();
        printf("VLO = %u Hz\r\n", vlo);   
        timerIsr = &handleTimer;  
        printf("Send message on timer enabled.\r\n");    
    #endif
        
    #ifdef SEND_MESSAGE_ON_MOTION
        printf("Send message on motion enabled.\r\n");    
        halSpiInitAccelerometer();  //note: this puts the SPI port in a non-ZNP configuration; must init it for ZNP afterwards
        writeAccelerometerRegister(ACCEL_CTRL, G_RANGE_2 | I2C_DIS | MODE_MD_10 | MDET_NO_EXIT);    // Configure Accelerometer
        delayUs(ACCELEROMETER_DELAY_BETWEEN_OPERATIONS_US);                                         // 11 bit-time delay required when using SPI
        readAccelerometerRegister(ACCEL_INT_STATUS);  // clear the interrupt
        accelerometerIsr = &handleAccelerometer;
        halEnableAccelerometerInterrupt(WAKEUP_AFTER_ACCELEROMETER);
    #endif    
        HAL_ENABLE_INTERRUPTS();
        
        //create the infoMessage. Most of these fields are the same, so we can create most of the message ahead of time. 
        hdr.sequence = 0;  //this will be incremented each message
        hdr.version = INFO_MESSAGE_VERSION;
        hdr.flags = INFO_MESSAGE_FLAGS_NONE;
        im.header = &hdr;  //Note, if you have multiple similar message types then you can use the same header for all
        im.deviceType = DEVICETYPE_SMITH_ELECTRONCS_ROUTER_DEMO;
        im.deviceSubType = DEVICESUBTYPE_SMITH_ELECTRONCS_ROUTER_DEMO;
        im.numParameters = 3;
                    
        //run the state machine
        stateMachine();
    }
    
    void stateMachine()
    {
        while (1)
        {
            switch (state)
            {
            case STATE_IDLE:
                {
                    if (stateFlags & STATE_FLAG_SEND_INFO_MESSAGE)  //if there is a pending info message to be sent
                    {
                        state = STATE_SEND_INFO_MESSAGE;            //then send the message and clear the flag
                        stateFlags &= ~STATE_FLAG_SEND_INFO_MESSAGE;
                    }
                    //note: other flags (for different messages or events) can be added here
                    break;
                }
                
            case STATE_ZNP_STARTUP:
                {
    #define ZNP_START_DELAY_IF_FAIL_MS 5000
                    /* Start the network; if fails then wait a second and try again. */
                    signed int startResult = startZnp(END_DEVICE);
                    while (startResult != ZNP_SUCCESS)
                    {
                        printf("FAILED. Error Code %i, ZNP Result %i. Retrying...\r\n", startResult, znpResult);
                        delayMs(ZNP_START_DELAY_IF_FAIL_MS);
                        startResult = startZnp(END_DEVICE);
                    }
                    printf("Success\r\n"); 
                    
                    //ZNP Initialized so store MAC Address
                    memcpy(hdr.mac, getMacAddress(), 8); 
    #ifdef SEND_MESSAGE_ON_TIMER
                    signed int timerResult = initTimer(4, WAKEUP_AFTER_TIMER);
                    if (timerResult != 0)
                    {
                        printf("timerResult Error %i, STOPPING\r\n", timerResult);
                        while (1);   
                    }
    #endif
                    state = STATE_DISPLAY_NETWORK_INFORMATION;
                    break;
                }
            case STATE_DISPLAY_NETWORK_INFORMATION:
                {
                    printf("~ni~");
                    /* On network, display info about this network */              
                    getNetworkConfigurationParameters();                
                    getDeviceInformation();    
                    state = STATE_SEND_INFO_MESSAGE;
                    break;   
                }
            case STATE_SEND_INFO_MESSAGE:
                {
                    printf("~im~");
                    setLed(1);
                    im.header->sequence = sequenceNumber++;                
                    im.cause = infoMessageCause;
                    unsigned char* panid = getDeviceInformationProperty(DIP_PANID);
                    im.parameters[0] = CONVERT_TO_INT(*panid, *(panid+1));      //PAN ID
                    im.parameters[1] = getVcc3();                               //VCC
                    im.parameters[2] = getLightSensor();                        //Light Sensor
                    printInfoMessage(&im);
    #define ZNP_RESTART_DELAY_IF_MESSAGE_FAIL_MS 5000
                    unsigned char msgBuf[100];
                    serializeInfoMessage(&im, msgBuf);
                    afSendData(DEFAULT_ENDPOINT,DEFAULT_ENDPOINT,0, INFO_MESSAGE_CLUSTER, msgBuf, getSizeOfInfoMessage(&im));
                    if (znpResult != ZNP_SUCCESS)
                    {
                        printf("afSendData error %i; restarting...\r\n", znpResult);
                        delayMs(ZNP_RESTART_DELAY_IF_MESSAGE_FAIL_MS);  //allow enough time for coordinator to fully restart, if that caused our problem
                        state = STATE_ZNP_STARTUP;
                    } else {      
                        state = STATE_IDLE;
                        clearLeds();        
                        HAL_SLEEP();                    
                    }
                    break;   
                }
            default:     //should never happen
                {
                    printf("UNKNOWN STATE\r\n");
                    state = STATE_ZNP_STARTUP;
                }
                break;
            }
        } 
    }
    
    #ifdef SEND_MESSAGE_ON_TIMER
    /** Handles timer interrupt */
    void handleTimer()
    {
        printf("$");   
        infoMessageCause = CAUSE_SCHEDULED;
        stateFlags |= STATE_FLAG_SEND_INFO_MESSAGE;
    }
    #endif
    
    #ifdef SEND_MESSAGE_ON_MOTION
    /** Handles Accelerometer interrupt */
    void handleAccelerometer()
    {
        printf("@");
        infoMessageCause = CAUSE_MOTION;
        stateFlags |= STATE_FLAG_SEND_INFO_MESSAGE;
        halSpiInitAccelerometer();
        readAccelerometerRegister(ACCEL_INT_STATUS);  //will clear the interrupt
        delayUs(ACCELEROMETER_DELAY_BETWEEN_OPERATIONS_US); //in case this interrupt is immediately followed by another one
        halSpiInitZnp();  //return SPI configuration to work with the ZNP
    }
    #endif
    
    /* @} */
     

    My second question would be: How is the return value of getVcc3() put into the radio buffer( I mean i know it is done by using spi, but i cannot find this in the code as in how are they writing it to the radio buffer of cc2530 is unknown to me) I really would like to know the answer to these.

    Thanking you in advance,

    Nischal Venugopal

  • nischal venugopal said:
    HOW DO I SHORTEN IT??

    No idea. The code you posted doesn’t show all the initialization. Also, I don’t know what the HAL functions are doing.

    But I noticed some things in your state machine.

    Some states simply switch from one state to the next. The two states could as well be joined, since after leaving the switch, you immediately loop back into it. Separate states that are simply sequentially executed make no sense (you could assign a separate state to each single instruction as well then).

    Also, some of you states have while loops. That’s also nothing that should be done in a state machine. If you cannot proceed, exit the state and later return to it for another try. You either change the state or you keep the same state, but you don’t loop inside the state ..

    Maybe some of your code inside the states introduces a delay. You cannot start a send process if the state machine isn’t at the proper state, no matter when the trigger comes.

    Take a look at the state diagrams in the users guide for inspiration. Each bubble is a state, and each arrow leaves the code block of this state (and therefore the switch case) even if it returns back to the same bubble on next loop.
    And if you need to wait for a trigger and nothing else can be done in the meantime, enter LPM0 and let an ISR wake you when the trigger comes.

  • hello Jens,

    thank you for the reply and i am sorry about not giving the whole code. here is the complete code.

    7103.IAR.zip

    I am using the code from the work space named simple applications. would be really cool if you could take a look at them and help me out. looking forward for your reply.

    Thanking you in advance,

    Nischal

  • The zip file contains lots of workspace and project files. And also object files, but no source code.

    Well, to give any in-depth advice, I would have to do an in-depth analysis of the project, including the used libraries. And I fear I don’t have the time for doing this.
    The more modular a project is, the more time it takes to figure out how things work together. And there’s a limit for the time I can invest into the forum or a single problem. Especially if it covers an area I didn’t work with before and won’t work with in my job in the foreseeable future. Sorry.

    In my last post, I gave you some guidance regarding your state machine. You should be able to work with it.
    Sometimes, it is better to do things from scratch on your own, using the existing code as guide, rather than trying to directly alter the existing code.

  • Hi jens,

    Thank you for your help on this, I really got a very good perspective of my project. I completely understand that you don't have the time to look into all the requests that come pouring down on you. I will take your suggestion and take a look into the state machine and figure something out.

    thanks,

    Nischal

  • I try to look into every issue where I might have something to contribute (some topics are off my experience, like CC2530), but like pictures from a Mandelbrot set, there’s a depth limit or the invested time goes towards eternity. I sometimes go deeper if I’m personally interested in the result, but not too often (especially since my time has got more limited lately).

    Good luck. And if you have a detail question, feel free to ask.

**Attention** This is a public forum